对于此类问题,您通常从构建 XSLT 标识模板开始
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
就其本身而言,它会按原样复制所有节点,这意味着您只需为要转换的节点编写匹配的模板。
首先,您希望将num属性添加到product,因此有一个模板匹配product,您只需将其与属性一起输出并继续处理其子项。
<xsl:template match="product">
<product num="{position()}">
<xsl:apply-templates select="@*|node()"/>
</product>
</xsl:template>
请注意此处在创建num属性时使用属性值模板。花括号表示要计算的表达式,而不是字面输出。
然后,您需要一个模板来匹配产品元素的子元素,并将它们转换为属性节点。这是通过匹配任何这样的孩子的模式完成的,就像这样
<xsl:template match="product/*">
<attribute name="{local-name()}">
<xsl:apply-templates />
</attribute>
</xsl:template>
请注意,如果您只想在子元素中包含文本节点,则<xsl:apply-templates />
可以将其替换为此处。<xsl:value-of select="." />
试试这个 XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="product">
<product num="{position()}">
<xsl:apply-templates select="@*|node()"/>
</product>
</xsl:template>
<xsl:template match="product/*">
<attribute name="{local-name()}">
<xsl:apply-templates />
</attribute>
</xsl:template>
</xsl:stylesheet>
当应用于您的 XML 时,将输出以下内容
<products>
<product num="1">
<attribute name="type">Monitor</attribute>
<attribute name="size">22</attribute>
<attribute name="brand">EIZO</attribute>
</product>
<product num="2">
......
</product>
</products>
当然,如果确实想将子元素转换为适当的属性,而不是命名为“attribute”的元素,则可以使用xsl:attribute命令。用这个替换最后一个模板
<xsl:template match="product/*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
改为使用此模板时,将输出以下内容(好吧,如果您的样本有子元素,它将包括产品 2!)
<products>
<product num="1" type="Monitor" size="22" brand="EIZO"></product>
<product num="2">
......
</product>
</products>