如何用XSLT为深度优先遍历的XML树元素生成prev属性?
实现XSLT生成prev链接的解决方案
问题背景
现有嵌套结构的XML页面数据,已完成next链接的生成,需要补充实现prev链接,使输出的每个page节点包含正确的前序和后序页面ID。
原始XML结构
<pages> <page id="1"> <page id="1A" /> <page id="1B" /> </page> <page id="2" /> <page id="3"> <page id="3A" /> <page id="3B" /> <page id="3C" /> </page> </pages>
现有XSLT代码(已实现next链接)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/pages"> <pages> <xsl:for-each select=".//page"> <page id="{@id}" prev="???" next="{(child::page|following::page)/@id}" /> </xsl:for-each> </pages> </xsl:template> </xsl:stylesheet>
期望输出
<?xml version="1.0"?> <pages> <page id="1" prev="" next="1A"/> <page id="1A" prev="1" next="1B"/> <page id="1B" prev="1A" next="2"/> <page id="2" prev="1B" next="3"/> <page id="3" prev="2" next="3A"/> <page id="3A" prev="3" next="3B"/> <page id="3B" prev="3A" next="3C"/> <page id="3C" prev="3B" next=""/> </pages>
解决方案
直接使用preceding::page无法精准获取序列中的前一个节点,需先将所有page节点按文档顺序收集为可索引的节点集,再通过位置匹配前后节点。修改后的XSLT代码如下:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" indent="yes"/> <!-- 存储所有page节点的文档序列 --> <xsl:variable name="all-pages" select=".//page"/> <xsl:template match="/pages"> <pages> <xsl:for-each select="$all-pages"> <xsl:variable name="current-pos" select="position()"/> <page id="{@id}" prev="{if ($current-pos > 1) then $all-pages[$current-pos - 1]/@id else ''}" next="{if ($current-pos < count($all-pages)) then $all-pages[$current-pos + 1]/@id else ''}" /> </xsl:for-each> </pages> </xsl:template> </xsl:stylesheet>
代码说明
$all-pages变量按文档顺序收集所有page节点,保证遍历顺序与期望输出一致- 通过
position()获取当前节点在序列中的位置索引 prev属性:若当前节点不是第一个,则取序列中前一位的节点ID,否则为空next属性:若当前节点不是最后一个,则取序列中后一位的节点ID,否则为空
该方案同时修正了原next表达式可能返回多个ID的问题,确保输出完全符合预期。
内容的提问来源于stack exchange,提问作者0xF
相关产品推荐
相关产品推荐

