我的输入xml是
<?xml version="1.0" encoding="UTF-8"?>
<foobar>
<foo>
<a>
<a>
<a>atr1</a>
<v>NO</v>
</a>
<a>
<a>more</a>
<v>more</v>
</a>
</a>
<v>ONE</v>
</foo>
<bar>
<baz>
<a>
<a>
<a>attr</a>
<v>123</v>
</a>
<a>
<a>attr222</a>
<v>22</v>
</a>
</a>
<v>TWO</v>
</baz>
<a>
<a>
<a>atr6</a>
<v>ATR</v>
</a>
</a>
</bar>
<a>
<a>
<a>atr0</a>
<v>NO</v>
</a>
<a>
<a>atr2</a>
<v>NO</v>
</a>
</a>
</foobar>
我想要的输出是
<?xml version="1.0" encoding="UTF-8"?>
<foobar atr0="NO" atr2="NO">
<foo atr1="NO" more="more">ONE</foo>
<bar atr6="ATR">
<baz attr="123" attr222="22">TWO</baz>
</bar>
</foobar>
我正在尝试将所有嵌套元素转换为属性。 我的xslt脚本是 -
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- Matches all of nodes -->
<xsl:template match = "node()">
<xsl:copy>
<xsl:for-each select= "*">
<xsl:attribute name="{//a[text()]}">
<xsl:value-of select="//v[text()]"/>
</xsl:attribute>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
脚本正在将第一个foobar元素转换为仅属性。我做错了什么?
答案 0 :(得分:1)
你没有xsl:apply-templates
所以你永远不会超过第一个根元素。此外,node()
包含文本,注释和处理说明,如果您匹配其中一个属性,则不希望尝试创建属性。
尝试这样的事情......
XSLT 1.0
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[a]">
<xsl:copy>
<xsl:apply-templates select="@*|a/a"/>
<xsl:apply-templates select="node()[not(self::a)]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="a/a" priority="1">
<xsl:attribute name="{a}">
<xsl:value-of select="v"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="v">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
<强>输出强>
<foobar atr0="NO" atr2="NO">
<foo atr1="NO" more="more">ONE</foo>
<bar atr6="ATR">
<baz attr="123" attr222="22">TWO</baz>
</bar>
</foobar>
答案 1 :(得分:0)
这是您的代码正在做的事情:
您正在选择一个 node()
:foobar
,当您在其中时,您有一个for-each
并在那里选择任何当前上下文中的节点:*
,因此您匹配foo
,然后从那里获得包含文本的所有//a
(唯一的一个:atr1
)和所有//v
包含文字NO
。由于您从不调用<xsl:apply-templates>
或使用某个表达式来处理树中的节点,因此不会调用其他模板。
您需要递归处理其他节点。此外,您不能只使用//a
,因为在某些节点中有多个a
,您最终会将所有节点连接起来。
一种方法是使用多个递归模板。这是一个可能的解决方案:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="*[not(self::a)][not(self::v)]">
<xsl:copy>
<xsl:if test="a">
<xsl:apply-templates select="a" />
</xsl:if>
<xsl:apply-templates select="*[not(self::a)]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="a[following-sibling::v][text()]">
<xsl:attribute name="{normalize-space(.)}">
<xsl:value-of select="following-sibling::v" />
</xsl:attribute>
</xsl:template>
<xsl:template match="a">
<xsl:apply-templates select="a" />
</xsl:template>
</xsl:stylesheet>