如何复制属性?

How to copy attributes?

输入xml文件:

<root>
    <x1 attr11="sd5">
        <x2 attr12="sd6" attr15="sd7">
            <a />
            <b>
                <x3 attr18="sd8">
                    <c>
                        <x4 attr19="sd9"/>
                        <d />
                        <e />
                    </c>
                </x3>
            </b>
        </x2>
    </x1>
</root>

从中获取更新的“updates.xml”文件 - 标记属性:

<updates>
    <a attr1="adf" attr2="67" />
    <b attr3="g6h"/>    
    <c attr4="7jj" />   
    <d attr5="88" attr6="mn4" />    
    <e />
</updates>

如果输入文件包含“updates.xml”文件中的标签(无属性),则“updates.xml”文件中的属性会被复制到其中。 XSLT1.0 转换后的文件应该是这样的:

<root>
    <x1 attr11="sd5">
        <x2 attr12="sd6" attr15="sd7">
            <a attr1="adf" attr2="67" />
            <b attr3="g6h">
                <x3 attr18="sd8">
                    <c attr4="7jj">
                        <x4 attr19="sd9"/>
                        <d attr5="88" attr6="mn4" />
                        <e />
                    </c>
                </x3>
            </b>
        </x2>
    </x1>
</root>

现在这是 XSLT1.0 转换文件:

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exslt="http://exslt.org/common"
  exclude-result-prefixes="exslt"
  version="1.0">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

  <xsl:param name="updates" select="document('updates.xml')"/>
  <xsl:key name="replacement" match="//*" use="local-name()"/>

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

  <xsl:template match="*[not(node())]">
    <xsl:variable name="element" select="(.)"/>
    <xsl:variable name="replacement">
      <xsl:for-each select="$updates">
        <xsl:copy-of select="key('replacement', local-name($element))"/>
      </xsl:for-each>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="exslt:node-set($replacement)/*">
        <xsl:copy-of select="$replacement"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:copy-of select="(.)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

XML 转换后的文件:

<root>
    <x1 attr11="sd5">
        <x2 attr12="sd6" attr15="sd7">
            <a attr1="adf" attr2="67" />
            <b>
                <x3 attr18="sd8">
                    <c>
                        <x4 attr19="sd9" />
                        <d attr5="88" attr6="mn4" />
                        <e />
                    </c>
                </x3>
            </b>
        </x2>
    </x1>
</root>

为什么不将属性复制到 'b' 和 'c' 标签?

使用 apply-templates 处理原始属性以及来自其他文档的属性(即身份转换)并保持递归处理:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exslt="http://exslt.org/common"
  exclude-result-prefixes="exslt"
  version="1.0">
  <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

  <xsl:param name="updates" select="document('updates.xml')"/>
  <xsl:key name="replacement" match="*" use="local-name()"/>

  <!--Identity template-->
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="*">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:variable name="this" select="."/>
      <xsl:for-each select="$updates">
        <xsl:apply-templates select="key('replacement', local-name($this))/@*"/>
      </xsl:for-each>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
 

</xsl:stylesheet>