这是使用XSLT列出或计数的某种方式 从当前节点到每个叶节点的路径 基于一些标准。 例如在特定情况下 这里假设当前节点是“t” 和从当前节点到每个叶节点的路径 “trg”属性。 在下面例如
<root>
<t>
<a1>
<b1 trg="rr">
<c1></c1>
</b1>
<b2>
<c2></c2>
</b2>
</a1>
<a2>
<b3>
<c3></c3>
</b3>
</a2>
</t>
</root>
这里只有这个属性的路径 t / a1 / b2 / c2 和 t / a2 / b3 / c3
但不是 t / a1 / b1 / c1
答案 0 :(得分:2)
最简单的方法是:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="text()"/>
<xsl:template match="text()" mode="search"/>
<xsl:template match="t">
<xsl:apply-templates mode="search">
<xsl:with-param name="pPath" select="name()"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*" mode="search">
<xsl:param name="pPath"/>
<xsl:apply-templates mode="search">
<xsl:with-param name="pPath" select="concat($pPath,'/',name())"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*[not(*)]" mode="search">
<xsl:param name="pPath"/>
<xsl:value-of select="concat($pPath,'/',name(),'
')"/>
</xsl:template>
<xsl:template match="*[@trg]" mode="search" priority="1"/>
</xsl:stylesheet>
输出:
t/a1/b2/c2
t/a2/b3/c3
注意:完成拉式。路径搜索开始的规则(t
patttern)。隧道参数(*
模式)的规则。用于输出叶子路径(*[not(*)]
模式)的规则。递归破坏条件的规则(*[@trg]
模式)。
答案 1 :(得分:0)
我可以想办法实现这一点,但它看起来并不好看,所以希望有人会想出更好的方法......
首先,我使用当前节点的级别
定义了一个变量<xsl:variable name="level">
<xsl:value-of select="count(ancestor::*)"/>
</xsl:variable>
接下来,匹配所有后代或恰好是叶节点的当前节点,并且没有任何祖先(包括其自身,但只有当前级别),属性@trg ='rr'为指定。
<xsl:apply-templates select=".//*[not(node())][not(ancestor-or-self::*[count(ancestor::*) > $level][@trg='rr'])]">
<xsl:with-param name="currentLevel" select="$level"/>
</xsl:apply-templates>
匹配叶节点后,您应该能够将父节点的路径备份回当前节点。
这是完整的样式表
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="root/t"/>
</xsl:template>
<xsl:template match="t">
<!-- The level of the current node -->
<xsl:variable name="level">
<xsl:value-of select="count(ancestor::*)"/>
</xsl:variable>
<paths>
<!-- Match all leaf nodes where there is not an ancestor (up to the current node) with the attribute @trg = 'rr' -->
<xsl:apply-templates select=".//*[not(node())][not(ancestor-or-self::*[count(ancestor::*) > $level][@trg='rr'])]">
<xsl:with-param name="currentLevel" select="$level"/>
</xsl:apply-templates>
</paths>
</xsl:template>
<!-- For leaf nodes, write out the ancestor path to a specified level -->
<xsl:template match="*[not(node())]">
<xsl:param name="currentLevel"/>
<path>
<xsl:for-each select="ancestor::*[count(ancestor::*) >= $currentLevel]">
<xsl:value-of select="name()"/>
<xsl:text>/</xsl:text>
</xsl:for-each>
<xsl:value-of select="name()"/>
</path>
</xsl:template>
</xsl:stylesheet>
当应用于给定的XML时,将返回以下结果
<paths>
<path>t/a1/b2/c2</path>
<path>t/a2/b3/c3</path>
</paths>
答案 2 :(得分:0)
使用XSLT 2.0 / XPath 2.0
可以最好地解决此问题非常初始的XSLT 1.0尝试:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="*[not(*)]">
<xsl:call-template name="buildPath">
<xsl:with-param name="pstartNode" select="/*/t"/>
</xsl:call-template>
</xsl:template>
<xsl:template match="text()"/>
<xsl:template name="buildPath">
<xsl:param name="pstartNode" select="."/>
<xsl:param name="pendNode" select="."/>
<xsl:choose>
<xsl:when test=
"not(count($pstartNode | $pendNode/ancestor-or-self::node())
=
count($pendNode/ancestor-or-self::node())
)
">
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vPath" select=
"ancestor::*
[count(.|$pstartNode/descendant-or-self::*)
=
count($pstartNode/descendant-or-self::*)
]
"/>
<xsl:if test="not($vPath[@trg])">
<xsl:for-each select=
"ancestor::*
[count(.|$pstartNode/descendant-or-self::*)
=
count($pstartNode/descendant-or-self::*)
]">
<xsl:value-of select="concat(name(),'/')"/>
</xsl:for-each>
<xsl:value-of select="concat(name(), '
')"/>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<root>
<t>
<a1>
<b1 trg="rr">
<c1></c1>
</b1>
<b2>
<c2></c2>
</b2>
</a1>
<a2>
<b3>
<c3></c3>
</b3>
</a2>
</t>
</root>
生成想要的正确结果:
t/a1/b2/c2
t/a2/b3/c3
答案 3 :(得分:0)
这是样式表:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<paths>
<xsl:apply-templates select="root/t">
<xsl:with-param name="path"/>
</xsl:apply-templates>
</paths>
</xsl:template>
<xsl:template name="path">
<xsl:param name="path"/>
<xsl:choose>
<xsl:when test="string-length($path)">
<xsl:value-of select="$path"/>/<xsl:value-of select="name()"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="name()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="*">
<xsl:param name="path"/>
<xsl:if test="not(@trg)">
<xsl:if test="not(count(*))">
<path>
<xsl:call-template name="path">
<xsl:with-param name="path">
<xsl:value-of select="$path"/>
</xsl:with-param>
</xsl:call-template>
</path>
</xsl:if>
<xsl:apply-templates select="*">
<xsl:with-param name="path">
<xsl:call-template name="path">
<xsl:with-param name="path">
<xsl:value-of select="$path"/>
</xsl:with-param>
</xsl:call-template>
</xsl:with-param>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
这个想法非常简单 - 主要处理模板(math="*"
)是适用于每个节点的递归函数。它有一个参数 - path
,它是从搜索根节点(t
)到此节点的实际路径。一旦节点没有孩子 - 它可以输出。
另一个名为path
的模板是一个简单的辅助函数,可以正确生成路径。如果你可以在你的XSLT处理器中注册一个XPath函数,我宁愿这样做,也不要去掉冗长的call-template
结构。整个call-template ...
调用可以是简单的<xsl:value-of select="myfn:path($path)"/>
,这将大大提高可读性,这对XSLT非常重要;)
无论如何,我觉得我的解释中有太多路径字样了,所以不要犹豫,问一下是不是很清楚。