虽然在这样一个简单的输入 XML 中可能并不完全需要,但通常值得从 XSLT identity transform 开始,它自己复制节点,这意味着您只需要为“异常”编写模板
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
在您的情况下,您可以将问题视为将根的第一个子元素转换为新元素,因此您将有一个模板来匹配第一个元素
<xsl:template match="/*/*[1]">
要创建具有动态名称的新元素,请使用 xsl:element 命令,如下所示
<xsl:element name="{local-name()}And{local-name(following-sibling::*[1])}">
或者为了保持可读性,在表达式中使用变量
<xsl:variable name="second" select="local-name(following-sibling::*[1])" />
<xsl:element name="{local-name()}And{$second}">
注意这里使用了Attribute Value Templates,它表示要计算的表达式,而不是字面输出。因此,在这种情况下,local-name() 被评估以获取元素的名称(不包括命名空间)。
在此您将使用 xsl:apply-templates 复制两个子元素的子元素(这将处理存在要复制的文本以外的节点的情况)
<xsl:apply-templates select="node()" />
<xsl:text> </xsl:text>
<xsl:apply-templates select="following-sibling::*[1]/node()"/>
最后,要停止身份转换复制它,您还需要一个模板来排除 root
的第二个孩子
<xsl:template match="/*/*[position() > 1]" />
试试这个 XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*/*[1]">
<xsl:variable name="second" select="local-name(following-sibling::*[1])" />
<xsl:element name="{local-name()}And{$second}">
<xsl:apply-templates select="node()" />
<xsl:text> </xsl:text>
<xsl:apply-templates select="following-sibling::*[1]/node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="/*/*[position() > 1]" />
</xsl:stylesheet>
注意,这不会将第一个字母大写。为此(在 XSLT 1.0 中),您需要结合使用 substring 提取第一个字母,并使用 translate 将其转换为大写。