将两个XML文档组合在一起使用类似的模式

时间:2014-07-05 18:10:53

标签: xslt

我有两个需要以特殊方式组合的XML文档。

作为一个简单的例子,我将两个文件放在一起:

<?xml version="1.0" encoding="utf-8" ?>
<data>
    <config1>
        <option1 type="a">A</option1>
        <option2 type="b">B</option2>
        <option3 type="c">C</option3>
    </config1>
    <config2>
        <option2 type="bb">BB</option2>
        <option4>D</option4>
    </config2>
</data>

所以,我需要将 config1 config2 合并到这个结果中:

<?xml version="1.0" encoding="UTF-8"?>
<data>
  <config>
    <option1 type="a">A</option1>
    <option2 type="bb">BB</option2>
    <option3 type="c">C</option3>
    <option4>D</option4>
  </config>
</data>

转换规则是:

  1. 如果 config2
  2. 中没有此选项,请从 config1 获取选项
  3. 否则从 config2
  4. 获取该选项
  5. config1 获取选项 config1
  6. 我是按照XSLT制作的:

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" indent="yes"/>
    
      <xsl:template match="/*">
        <xsl:copy>
          <config>
            <!-- Select options from config 1. -->
            <xsl:for-each select="config1/*">
              <xsl:choose>
                <!-- Leave option as is. -->
                <xsl:when test="not(/data/config2/*[name() = name(current())])">
                  <xsl:copy-of select="."/>
                </xsl:when>
                <!-- Overwrite option. -->
                <xsl:otherwise>
                  <xsl:copy-of select="/data/config2/*[name() = name(current())]"/>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:for-each>
    
            <!-- Select options from config 2. -->
            <xsl:for-each select="config2/*">
              <!-- Append "new" option -->
              <xsl:if test="not(/data/config1/*[name()=name(current())])">
                <xsl:copy-of select="."/>
              </xsl:if>
            </xsl:for-each>
          </config>
        </xsl:copy>
      </xsl:template>
    </xsl:stylesheet>
    

    它有效,但看起来很蹩脚。

    许多XSL专家更喜欢将for-templates替换为for-each。

    是否可以以这种方式重写我的模板?

1 个答案:

答案 0 :(得分:2)

  

作为一个简单的例子,我将两个文件放在一起:

这不是一个好主意,因为处理两个文档与处理同一文档中的两个节点集不同。因此,假设您处理的文档是:

<?xml version="1.0" encoding="utf-8" ?>
<data>
    <config1>
        <option1 type="a">A</option1>
        <option2 type="b">B</option2>
        <option3 type="c">C</option3>
    </config1>
</data>

还有另一份文件:

<强> file2.xml

<?xml version="1.0" encoding="utf-8" ?>
<data>
    <config2>
        <option2 type="bb">BB</option2>
        <option4>D</option4>
    </config2>
</data>

您可以使用以下样式表:

XSLT 1.0

<?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" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:variable name="config2" select="document('file2.xml')/data/config2" />

<xsl:template match="/">
    <data>
        <config>
            <xsl:apply-templates select="data/config1/*[not(name()=name($config2/*))] | $config2/*"/>
        </config>
    </data>
</xsl:template>

<xsl:template match="data/*/*">
    <xsl:copy-of select="."/>
</xsl:template>

</xsl:stylesheet>

获得此结果:

<?xml version="1.0" encoding="UTF-8"?>
<data>
   <config>
      <option1 type="a">A</option1>
      <option3 type="c">C</option3>
      <option2 type="bb">BB</option2>
      <option4>D</option4>
   </config>
</data>