Java+XSL合并多个XML文件
使用 Java 解析 XML 文件有许多成熟的工具,如 dom4j 等等。但在一些场景中,我们可能使用 Ant、Maven 等构建工具对多个 XML 文件进行合并,我们希望可以直接通过脚本文件,或者简单的程序就能完成这样的功能,那么使用 XSL 是一个非常不错的选择。本文将介绍通过简单的 Java 程序加上 XSL 文件来完成多个 XML 文件的合并操作。(XSL 是一种样式表语言,可用以描述如何显示一个 XML 文件)
背景:
- Config.xml 文件的结构与 FinalConfig.xml 文件相似;
- 需要将 Config.xml 文件的内容合并到 FinalConfig.xml 文件;
- 若 FinalConfig.xml 文件中已存在 Config.xml 的内容,则覆盖。
目标:程序执行完成后,生成一个唯一的 XML 文件 FinalConfig.xml;
FinalConfig.xml 文件结构:
1 <gameconfig> 2 <games> 3 <game> 4 <gameid>100</gameid> 5 <gamename>Fly to the Moon</gamename> 6 <gamedesc>This is Fly to the Moon</gamedesc> 7 </game> 8 <game> 9 <gameid>101</gameid> 10 <gamename>10 Miles</gamename> 11 <gamedesc>This is 10 Miles</gamedesc> 12 </game> 13 </games> 14 </gameconfig>
Config.xml 文件结构:
1 <gameconfig> 2 <games> 3 <game> 4 <gameid>100</gameid> 5 <gamename>Fly to the Sun</gamename> 6 <gamedesc>This is Fly to the Sun</gamedesc> 7 </game> 8 </games> 9 </gameconfig>
我们假定 gameid 是固定值,不会变。在合并完成后,<gameid>为 100 的 node 被更新。希望得到新的 FinalConfig.xml 文件如下:
1 <gameconfig> 2 <games> 3 <game> 4 <gameid>100</gameid> 5 <gamename>Fly to the Sun</gamename> 6 <gamedesc>This is Fly to the Sun</gamedesc> 7 </game> 8 <game> 9 <gameid>101</gameid> 10 <gamename>10 Miles</gamename> 11 <gamedesc>This is 10 Miles</gamedesc> 12 </game> 13 </games> 14 </gameconfig>
一、Java 调用程序
1 private void mergeXml(File xslFile, File configXml, File finalConfigXml){ 2 DocumentBuilderFactory dbFac = DocumentBuilderFactory.newInstance(); 3 DocumentBuilder builder; 4 Document destDoc = null; 5 FileInputStream input; 6 try{ 7 builder = dbFac.newDocumentBuilder(); 8 destDoc = builder.parse(finalConfigXml); 9 if(!finalConfigXml.exists()) 10 { 11 finalConfigXml.createNewFile(); 12 } 13 input = new FileInputStream(xslFile); 14 StreamSource source = new StreamSource(input); 15 Transformer transformer = TransformerFactory.newInstance().newTransformer(source); 16 //为xsl文件设置变量"configXmlPath",将configXml文件的路径传递给xsl 17 transformer.setParameter("configXmlPath", configXml.getPath()); 18 transformer.transform(new DOMSource(destDoc), new StreamResult(finalConfigXml)); 19 }catch(Exception e) { 20 e.printStackTrace(); 21 } 22 }
二、XSL 文件
1 <?xml version="1.0" encoding="UTF-8"?> 2 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 3 4 <xsl:output method="xml" indent="yes"/> 5 6 <!-- pass the Config.xml file's path from Java code --> 7 <xsl:param name="configXmlPath"/> 8 <xsl:variable name="configXml" select="document($configXmlPath)"/> 9 10 <xsl:template match="@* | node()"> 11 <xsl:copy> 12 <xsl:apply-templates select="@* | node()"/> 13 </xsl:copy> 14 </xsl:template> 15 16 <xsl:template match="/gamedata"> 17 <xsl:copy> 18 <xsl:apply-templates select="games" mode="updateGames"/> 19 </xsl:copy> 20 </xsl:template> 21 22 <xsl:template match ="games" mode="updateGames"> 23 <xsl:variable name="gamesStr"> 24 <xsl:for-each select="$configXml/gamedata/games/game"> 25 <xsl:choose> 26 <xsl:when test="gameid"> 27 <xsl:value-of select="concat('-',current()/gameid)"/> 28 </xsl:when> 29 </xsl:choose> 30 </xsl:for-each> 31 </xsl:variable> 32 <games> 33 <xsl:for-each select="game"> 34 <xsl:if test="not(contains($gamesStr,gameid))"> 35 <xsl:copy-of select="current()"/> 36 </xsl:if> 37 </xsl:for-each> 38 <xsl:apply-templates select="$configXml/gamedata/games/game" /> 39 </games> 40 </xsl:template> 41 </xsl:stylesheet>
三、XSL 文件解析
1.Java 传入参数 “configXmlPath” 为 Config.xml 文件的路径
1 <xsl:param name="configXmlPath"/>
2.取出 Config.xml 文件中所有的 gameid,此处为增强处理,即 Config.xml 文件中可以存在多个 <game> 节点
1 <xsl:variable name="gamesStr"> 2 <xsl:for-each select="$configXml/gamedata/games/game"> 3 <xsl:choose> 4 <xsl:when test="gameid"> 5 <xsl:value-of select="concat('-',current()/gameid)"/> 6 </xsl:when> 7 </xsl:choose> 8 </xsl:for-each> 9 </xsl:variable>
3.判断 FinalConfig.xml 的 <games> 子节点中是否存在当前的 gameid ,若不存在则复制
1 <xsl:for-each select="game"> 2 <xsl:if test="not(contains($gamesStr,gameid))"> 3 <xsl:copy-of select="current()"/> 4 </xsl:if> 5 </xsl:for-each>
4.复制 Config.xml 文件中的所有 <game> 节点
<xsl:apply-templates select="$configXml/gamedata/games/game" />
(本文系从原博客迁移至此,并进行部分编辑。原文链接:http://thewaychung.iteye.com/blog/2072740)