【发布时间】:2017-01-02 10:40:31
【问题描述】:
我正在尝试在 xslt 中做一些棘手的事情 我有一个平面 xml,其中包含大量兄弟姐妹,并且根据我想将它们转换为孩子的名称 我的转换的一般规则是:
- 如果标签/名称是“BLOCK”,则打开一个带有标签/值作为属性的“BLOCK”元素
- 如果标记/名称是“BLOCK_END”,则关闭“BLOCK”元素(
- 在所有其他情况下,创建元素标签/名称,放置标签/值并立即关闭它
所以对于下面的 xml:
<message>
<tag>
<name>BLOCK</name>
<value>first</value>
</tag>
<tag>
<name>FOO</name>
<value>BAR</value>
</tag>
<tag>
<name>BLOCK</name>
<value>second</value>
</tag>
<tag>
<name>FOO2</name>
<value>BAR2</value>
</tag>
<tag>
<name>BLOCK_END</name>
</tag>
<tag>
<name>BLOCK_END</name>
</tag>
<tag>
<name>BLOCK</name>
<value>third</value>
</tag>
<tag>
<name>FOO3</name>
<value>BAR3</value>
</tag>
<tag>
<name>BLOCK_END</name>
</tag>
</message>
这是我希望的结果:
<message>
<BLOCK id="first">
<FOO>BAR</FOO>
<BLOCK id="second">
<FOO2>BAR2</FOO2>
</BLOCK>
</BLOCK>
<BLOCK id="third">
<FOO3>BAR3</FOO3>
</BLOCK">
</message>
我使用了以下 xslt。这工作正常,但遗憾的是它在遇到第一个 BLOCK_END 标记后完成了执行
<xsl:template match="/">
<message>
<xsl:apply-templates select="message/tag[1]" />
</message>
</xsl:template>
<xsl:template match="tag">
<xsl:variable name="tagName" select="name"/>
<xsl:variable name="tagValue" select="value"/>
<xsl:choose>
<xsl:when test="$tagName = 'BLOCK'">
<xsl:element name="{$tagName}">
<xsl:attribute name="id">
<xsl:value-of select="$tagValue"/>
</xsl:attribute>
<xsl:apply-templates select="./following-sibling::*[1]" />
</xsl:element>
</xsl:when>
<xsl:when test="$tagName = 'BLOCK_END'">
<!-- DO NOTHING-->
</xsl:when>
<xsl:otherwise>
<xsl:element name="{$tagName}">
<xsl:value-of select="$tagValue"/>
</xsl:element>
<xsl:apply-templates select="./following-sibling::*[1]" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
更新:感谢BitTickler,我离我越来越近了,但还不是很远。
【问题讨论】:
-
你能使用像 Saxon 9、Altova、XmlPrime 这样的 XSLT 2.0 处理器吗?
-
@MartinHonnen 遗憾的是,我坚持使用核心 XSLT 1.0
-
-
另外,我对最初的
<xsl:for-each ...>声明表示怀疑,因为这是非常必要的,并且已经暗示这种方法会引起麻烦。相反,您应该为第一个标签元素应用模板,然后让递归调用发挥它们的作用。