Java+XSL合并XML文件

使用Java解析XML文件有许多成熟的工具,如dom4j等等。但在一些场景中,我们可能使用Ant、Maven等打包工具对多个XML文件进行合并,我们希望可以直接通过脚本文件,或者简单的程序就能完成这样的功能,那么使用XSL是一个非常不错的选择。本文将介绍通过简单的Java程序加上XSL文件来完成多个XML文件的合并操作。

 

背景

  1. Config.xml文件的结构与FinalConfig.xml文件相似;
  2. 需要将Config.xml文件的内容合并到FinalConfig.xml文件;
  3. 若FinalConfig.xml文件中已存在Config.xml的内容,则覆盖。

需求

程序执行完成生成一个唯一的XML文件FinalConfig.xml;

 

FinalConfig.xml文件结构:

<gameconfig>
    <games>
        <game>
            <gameid>100</gameid>
            <gamename>Fly to the Moon</gamename>
            <gamedesc>This is Fly to the Moon</gamedesc>
        </game>
        <game>
            <gameid>101</gameid>
            <gamename>10 Miles</gamename>
            <gamedesc>This is 10 Miles</gamedesc>
        </game>
    </games>
</gameconfig>

 Config.xml文件结构:

<gameconfig>
    <games>
        <game>
            <gameid>100</gameid>
            <gamename>Fly to the Sun</gamename>
            <gamedesc>This is Fly to the Sun</gamedesc>
        </game>
    </games>
</gameconfig>

 

我们假定gameid是固定值,不会变。在合并完成后,<gameid>为100的node被更新。希望得到新的FinalConfig.xml文件如下:

<gameconfig>
    <games>
        <game>
            <gameid>100</gameid>
            <gamename>Fly to the Sun</gamename>
            <gamedesc>This is Fly to the Sun</gamedesc>
        </game>
        <game>
            <gameid>101</gameid>
            <gamename>10 Miles</gamename>
            <gamedesc>This is 10 Miles</gamedesc>
        </game>
    </games>
</gameconfig>

  

一、Java调用程序

 

private void mergeXml(File xslFile, File configXml, File finalConfigXml){
    DocumentBuilderFactory dbFac = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder;
    Document destDoc = null;
    FileInputStream input;
    try{
        builder = dbFac.newDocumentBuilder();
        destDoc =  builder.parse(finalConfigXml);
        if(!finalConfigXml.exists()) 
        {
            finalConfigXml.createNewFile();
        }
	input = new FileInputStream(xslFile);
	StreamSource source = new StreamSource(input);
	Transformer  transformer = TransformerFactory.newInstance().newTransformer(source);
	//为xsl文件设置变量"configXmlPath",将configXml文件的路径传递给xsl
	transformer.setParameter("configXmlPath", configXml.getPath());
	transformer.transform(new DOMSource(destDoc), new StreamResult(finalConfigXml));
	}catch(Exception e) {
	    e.printStackTrace();
	}
}

 

二、xsl文件

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	
  <xsl:output method="xml" indent="yes"/>
  
  <!-- pass the Config.xml file's path from Java code -->
  <xsl:param name="configXmlPath"/>
  <xsl:variable name="configXml" select="document($configXmlPath)"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="/gamedata">
		<xsl:copy>
		  <xsl:apply-templates select="games" mode="updateGames"/>
		</xsl:copy>
  </xsl:template>
  
  <xsl:template match ="games" mode="updateGames">
    <xsl:variable  name="gamesStr">
        <xsl:for-each select="$configXml/gamedata/games/game">
	    <xsl:choose>
	        <xsl:when test="gameid">
		    <xsl:value-of select="concat('-',current()/gameid)"/>
	        </xsl:when>
	    </xsl:choose>
        </xsl:for-each>
    </xsl:variable>
    <games>
	<xsl:for-each select="game">
	  <xsl:if test="not(contains($gamesStr,gameid))">
              <xsl:copy-of select="current()"/>
	  </xsl:if>
	</xsl:for-each>
	<xsl:apply-templates select="$configXml/gamedata/games/game" />
    </games>
  </xsl:template>
</xsl:stylesheet>

 

xsl文件分析:

1.Java传入参数“configXmlPath”为Config.xml文件的路径

<xsl:param name="configXmlPath"/>

2.取出Config.xml文件中所有的gameid,此处为增强处理,即Config.xml文件中可以存在多个<game>节点

<xsl:variable  name="gamesStr">
    <xsl:for-each select="$configXml/gamedata/games/game">
        <xsl:choose>
            <xsl:when test="gameid">
	        <xsl:value-of select="concat('-',current()/gameid)"/>
            </xsl:when>
        </xsl:choose>
    </xsl:for-each>
</xsl:variable>

3.判断FinalConfig.xml的<games>子节点中是否存在当前的gameid,若不存在则复制

<xsl:for-each select="game">
  <xsl:if test="not(contains($gamesStr,gameid))">
     <xsl:copy-of select="current()"/>
  </xsl:if>
</xsl:for-each>

4.复制Config.xml文件中的所有<game>节点

<xsl:apply-templates select="$configXml/gamedata/games/game" />

 

 

 

 

 

 

你可能感兴趣的:(java,xml,XSL)