如何合并(覆盖)两个xml文档?

时间:2014-06-06 14:28:14

标签: xml xslt xslt-2.0 saxon

假设我有一个像这样的 A 文档:

<document>
    <element>
        <value>1</value>
        <wom>bat</wom>
    </element>
    <bar>
        <baz />
        <baz />
        <baz />
    </bar>
</document>

以及 B 这样的文档:

<document>
    <element>
        <value>2</value>
    </element>
    <bar>

    </bar>
</document>

结果如下:

<document>
    <element>
        <value>2</value>
        <wom>bat</wom>
    </element>
    <bar>

    </bar>
</document>

所以我想要实现的是使用文档 B 中提供的值覆盖文档 A 中的标记(例如element)中的值但保持兄弟姐妹的价值不受影响。如果 B 中的标记为空(叶子),我希望其中 A 中的对应项也被清空。我已经检查了this问题,但它正在合并而不是覆盖。我该如何解决这个问题?

澄清: B 文档具有相同的结构,但 B 的元素较少。我必须清空 A 中的每个元素,这些元素在 B 中为空,如果元素不为空,我必须覆盖元素中的每个内部元素(参见我的示例)。 / p>

1 个答案:

答案 0 :(得分:4)

一种方法可能是在DocumentA上导航,但将参数集传递给文档B中的等效节点。

首先,匹配A的文档节点,然后从B

开始匹配文档节点
   <xsl:template match="/">
      <xsl:apply-templates>
         <xsl:with-param name="parentB" select="document('DocB.xml')"/>
      </xsl:apply-templates>
   </xsl:template>

然后,你将有一个模板匹配任何元素(在A中)与B中的当前(父)节点作为参数

   <xsl:template match="*">
      <xsl:param name="parentB"/>

找到等效的孩子&#39;在B中的节点,你首先会找到A节点的当前位置(如果有多个同名的子节点),然后检查父B节点下是否存在这样的子节点

<xsl:variable name="posA">
   <xsl:number  />
</xsl:variable>
<xsl:variable name="nodeB" select="$parentB/*[local-name() = local-name(current())][number($posA)]"/>

然后,只是确定是否复制A或B节点的情况。要复制B节点,B节点必须存在,并且没有任何子元素(它可能有子文本节点,但可以复制

<xsl:when test="$nodeB and not($nodeB/*)">
   <xsl:copy-of select="$nodeB/node()"/>
</xsl:when>

否则,继续处理A节点(将当前B节点作为参数传入)。

试试这个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:apply-templates>
         <xsl:with-param name="parentB" select="document('DocB.xml')"/>
      </xsl:apply-templates>
   </xsl:template>

   <xsl:template match="*">
      <xsl:param name="parentB"/>
      <xsl:variable name="posA">
          <xsl:number  />
       </xsl:variable>
      <xsl:variable name="nodeB" select="$parentB/*[local-name() = local-name(current())][number($posA)]"/>
      <xsl:copy>
         <xsl:choose>
            <xsl:when test="$nodeB and not($nodeB/*)">
               <xsl:copy-of select="$nodeB/node()"/>
            </xsl:when>
            <xsl:otherwise>
               <xsl:apply-templates select="@*|node()">
                  <xsl:with-param name="parentB" select="$nodeB"/>
               </xsl:apply-templates>
            </xsl:otherwise>
         </xsl:choose>
      </xsl:copy>
   </xsl:template>

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