这是一个 XSLT 1.0 解决方案——我们只假设两个文档没有混合内容元素(没有元素同时具有元素和非空白文本节点子节点):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<my:patternDoc>
<root>
<a>abc</a>
<b>def</b>
</root>
</my:patternDoc>
<xsl:variable name="vinitTarget" select="/"/>
<xsl:variable name="vinitPattern" select="document('')/*/my:patternDoc"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:call-template name="clone"/>
</xsl:copy>
</xsl:template>
<xsl:template name="clone">
<xsl:param name="pTargetNode" select="/*/*[1]"/>
<xsl:param name="pPatterntNode" select="$vinitPattern/*/*[1]"/>
<xsl:if test="$pTargetNode">
<xsl:choose>
<xsl:when test="not(name($pTargetNode) = name($pPatterntNode))">
<xsl:copy-of select="$pTargetNode"/>
<xsl:call-template name="clone">
<xsl:with-param name="pTargetNode"
select="$pTargetNode/following-sibling::*[1]"/>
<xsl:with-param name="pPatterntNode"
select="$pPatterntNode/following-sibling::*[1]"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="$pTargetNode[not(*)] and $pPatterntNode[not(*)]">
<xsl:copy-of select="$pPatterntNode"/>
<xsl:call-template name="clone">
<xsl:with-param name="pTargetNode"
select="$pTargetNode/following-sibling::*[1]"/>
<xsl:with-param name="pPatterntNode"
select="$pPatterntNode/following-sibling::*[1]"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$pTargetNode/*">
<xsl:element name="{name($pTargetNode)}"
namespace="{namespace-uri($pTargetNode)}">
<xsl:call-template name="clone">
<xsl:with-param name="pTargetNode"
select="$pTargetNode/*[1]"/>
<xsl:with-param name="pPatterntNode"
select="$pPatterntNode/*[1]"/>
</xsl:call-template>
</xsl:element>
<xsl:call-template name="clone">
<xsl:with-param name="pTargetNode"
select="$pTargetNode/following-sibling::*[1]"/>
<xsl:with-param name="pPatterntNode"
select="$pPatterntNode/following-sibling::*[1]"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
当此转换应用于提供的“目标”XML 文档时:
<root>
<a>xyz</a>
<c>ghi</c>
</root>
产生了想要的正确结果:
<root>
<a xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my">abc</a>
<c>ghi</c>
</root>
注意:
复制的额外名称空间只是因为模式文档当前嵌入到 XSLT 样式表中。这只是为了方便。在实际情况下,模式文档将与 XSLT 样式表分开,并且不会复制额外的名称空间节点。
让我们验证提供的转换是否可以在更复杂的 XML 文档上正常工作:
<root>
<a>
<b>
<c>xyz</c>
<f/>
<g>tuv</g>
</b>
</a>
<d>
<e>ghi</e>
</d>
</root>
如果同一转换(上图)中的嵌入模式文档现在是:
<my:patternDoc>
<root>
<a>
<b>
<c>abc</c>
<f/>
<g>mnk</g>
</b>
</a>
<d>
<e>pqr</e>
</d>
</root>
</my:patternDoc>
再次产生所需的正确结果:
<root>
<a>
<b>
<c xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my">abc</c>
<f xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my"/>
<g xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my">mnk</g>
</b>
</a>
<d>
<e xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my">pqr</e>
</d>
</root>