我有以下XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type='text/xsl' href='parser.xsl'?>
<NVS>
<A>
<F>007</F>
</A>
<A>-002</A>
<B>--003</B>
<C>
<D>------005</D>
</C>
<E>-006</E>
</NVS>
我想为每个节点打印一个树,例如:
/NVS/A/
/NVS/A/F/
/NVS/A/
/NVS/B/
/NVS/C/
/NVS/C/D
/NVS/E/
我尝试了一些XSL,但我买不起正确的结果。 最好的XSL是:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="ISO-8859-1" doctype-public="-//W3C//DTD XHTML//EN" doctype-system="http://www.w3.org/TR/2001/REC-xhtml11-20010531" indent="yes"/>
<xsl:template match="/*">
<html>
<body>
<xsl:for-each select=".">/<xsl:value-of select="."/>
<br/>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
我也试过“for-each”,例如:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="ISO-8859-1" doctype-public="-//W3C//DTD XHTML//EN" doctype-system="http://www.w3.org/TR/2001/REC-xhtml11-20010531" indent="yes"/>
<xsl:template match="/*/*">
<xsl:for-each select=".">/<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
但不是更好。而且我只是打算这个值,而我只想要节点的名称。
有什么想法吗?
答案 0 :(得分:2)
一种可能的解决方案是遍历树并随时跟踪适当的输出。例如,当这个XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<xsl:apply-templates mode="children">
<xsl:with-param name="pName" select="name()"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*[*]" mode="children">
<xsl:param name="pName"/>
<xsl:variable name="vNewName" select="concat($pName, '/', name())"/>
<xsl:value-of select="concat('/', $vNewName, '/ ')"/>
<xsl:apply-templates mode="children">
<xsl:with-param name="pName" select="$vNewName"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*[not(*)]" mode="children">
<xsl:param name="pName"/>
<xsl:value-of select="concat('/', $pName, '/', name(), '/ ')"/>
</xsl:template>
</xsl:stylesheet>
...适用于提供的XML:
<NVS>
<A>
<F>007</F>
</A>
<A>-002</A>
<B>--003</B>
<C>
<D>------005</D>
</C>
<E>-006</E>
</NVS>
...产生了想要的结果:
/NVS/A/
/NVS/A/F/
/NVS/A/
/NVS/B/
/NVS/C/
/NVS/C/D/
/NVS/E/
<强>解释强>
$pName
参数,此参数目前包含根节点的名称。注意使用mode="children"
;我使用它,因此具有更通用匹配的未来模板不包括此根节点。mode="children"
)。在找到这样的节点后,处理器输出一行文本,该文本组合携带的$pName
参数,正斜杠和当前元素的名称。最后,模板通过将模板应用于所有子节点并传递参数来模拟模板#1 - 但是,这次参数包含创建的连接文本,包括此节点。mode="children"
)。在找到这样的节点后,处理器输出一行文本,其行为与模板#2非常相似。答案 1 :(得分:1)
另一个选择是使用ancestor-or-self
轴返回树。
XML输入
<NVS>
<A>
<F>007</F>
</A>
<A>-002</A>
<B>--003</B>
<C>
<D>------005</D>
</C>
<E>-006</E>
</NVS>
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="text()"/>
<xsl:template match="*">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="concat('/',local-name())"/>
</xsl:for-each>
<xsl:text>
</xsl:text>
<xsl:apply-templates select="node()"/>
</xsl:template>
</xsl:stylesheet>
<强>输出强>
/NVS
/NVS/A
/NVS/A/F
/NVS/A
/NVS/B
/NVS/C
/NVS/C/D
/NVS/E
当元素在给定级别存在多次时,您还可以通过在谓词中添加位置来轻松修改它以提供精确路径。例如,有两个A
元素是/NVS
的子元素。
XSLT 1.0
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="text()"/>
<xsl:template match="*">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="concat('/',local-name())"/>
<xsl:if test="(preceding-sibling::*|following-sibling::*)[local-name()=local-name(current())]">
<xsl:value-of select="concat('[',count(preceding-sibling::*[local-name()=local-name(current())])+1,']')"/>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
<xsl:apply-templates select="node()"/>
</xsl:template>
</xsl:stylesheet>
输出(使用与上面相同的输入)
/NVS
/NVS/A[1]
/NVS/A[1]/F
/NVS/A[2]
/NVS/B
/NVS/C
/NVS/C/D
/NVS/E
此外,如果您不想要根元素输出的路径,只需添加此模板:
<xsl:template match="/*">
<xsl:apply-templates/>
</xsl:template>