Kan*_*kan 2 xml xslt xpath xslt-2.0
我试图使用XSLT从大型XML渲染一些数据.XML数据实际上是一种图形数据而不是分层数据.和元素彼此相关,因此最终可能会有一个循环引用(但关系类型却不同).
我试图遍历一个元素的关系并访问每个相关元素,依此类推.通过这种方式,有时我会达到一个我已经遍历过的元素.在这种情况下,我应该停止进一步遍历,否则我将在一个循环中运行.
我的问题是我无法存储已经遍历的元素列表,并且每次开始遍历元素时都会查找,这样如果元素在查找中,我就可以停止遍历.
简单地说,我想将元素保存在查找表中,并在遍历时将每个元素添加到它中.
这有什么解决方案吗?
递归模板可以传递自身参数,该参数包含"先前"处理的节点的节点集和要处理的节点的队列.这是一个与修改状态变量等效的函数式编程.
样本输入:
<graph startNode="a">
<graphNode id="a">
<edge target="b" />
<edge target="c" />
</graphNode>
<graphNode id="b">
<edge target="c" />
</graphNode>
<graphNode id="c">
<edge target="d" />
</graphNode>
<graphNode id="d">
<edge target="a" />
<edge target="b" />
</graphNode>
</graph>
Run Code Online (Sandbox Code Playgroud)
XSL 2.0样式表:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="graphNodeByID" match="graphNode" use="@id" />
<xsl:template match="/graph">
<results>
<xsl:apply-templates select="key('graphNodeByID', @startNode)"
mode="process"/>
</results>
</xsl:template>
<xsl:template match="graphNode" mode="process">
<xsl:param name="already-processed" select="/.." />
<xsl:param name="queue" select="/.." />
<!-- do stuff with context node ... -->
<processing node="{@id}" />
<!-- Add connected nodes to queue, excluding those already processed. -->
<xsl:variable name="new-queue"
select="($queue | key('graphNodeByID', edge/@target))
except ($already-processed | .)" />
<!-- recur on next node in queue. -->
<xsl:apply-templates select="$new-queue[1]" mode="process">
<xsl:with-param name="already-processed"
select="$already-processed | ." />
<xsl:with-param name="queue" select="$new-queue" />
</xsl:apply-templates>
</xsl:template>
</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)
输出(测试):
<results>
<processing node="a"/>
<processing node="b"/>
<processing node="c"/>
<processing node="d"/>
</results>
Run Code Online (Sandbox Code Playgroud)
如指定的那样,即使图形包含循环,也不会处理两次节点.