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

Ada*_*old 3 xml xslt saxon xslt-2.0

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

<document>
    <element>
        <value>1</value>
        <wom>bat</wom>
    </element>
    <bar>
        <baz />
        <baz />
        <baz />
    </bar>
</document>
Run Code Online (Sandbox Code Playgroud)

和这样的B文档:

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

    </bar>
</document>
Run Code Online (Sandbox Code Playgroud)

结果如下所示:

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

    </bar>
</document>
Run Code Online (Sandbox Code Playgroud)

因此,我想要实现的目标是用文档Belement提供的值覆盖文档A中标记(如 )中的值,但保持同级值不变。然而,如果B中的标签为空(叶),我希望A中的对应标签也被清空。我已经检查过这个问题,但它是合并而不是覆盖。我怎么解决这个问题?

澄清: AB文档具有相同的结构,但B 的元素较少。我必须清空A中B中为空的每个元素,并且如果元素不为空,我必须覆盖该元素中的每个内部元素(请参阅我的示例)。

Tim*_*m C 5

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

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

   <xsl:template match="/">
      <xsl:apply-templates>
         <xsl:with-param name="parentB" select="document('DocB.xml')"/>
      </xsl:apply-templates>
   </xsl:template>
Run Code Online (Sandbox Code Playgroud)

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

   <xsl:template match="*">
      <xsl:param name="parentB"/>
Run Code Online (Sandbox Code Playgroud)

要在 B 中找到等效的“子”节点,首先要找到 A 节点的当前位置(如果有多个同名子节点),然后检查父 B 节点下是否存在这样的子节点

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

那么,就只是判断是复制A节点还是B节点的情况了。要复制 B 节点,B 节点必须存在,并且没有任何子元素(但它可能有子文本节点,它将被复制

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

否则,继续处理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>
Run Code Online (Sandbox Code Playgroud)