使用 xslt 在 xml 中构建子级别列表

construct sub level list in xml by using xslt

使用 xslt 按级别创建 XML 结构。

输入文件:

<list type="bulleted"></list>
<list2 type="bulleted"></list2>
<list3 type="bulleted"></list3>
<list3 type="bulleted"></list3>
<list2 type="bulleted"></list2>
<list3 type="bulleted"></list3>
<list4 type="bulleted"></list4>
<list2 type="bulleted"></list2>

结果会是,

<list type="bulleted"><list2 type="bulleted"><list3 type="bulleted"></list3> <list3 type="bulleted"></list3></list2> <list2 type="bulleted"><list3 type="bulleted"><list4 type="bulleted"></list4></list3></list2><list2 type="bulleted"></list2></list>

为了将示例最小化为这里唯一真正的问题,我已将您的输入修改为:

XML

<root>
    <list1 id="1"></list1>
    <list2 id="2"></list2>
    <list3 id="3"></list3>
    <list3 id="4"></list3>
    <list2 id="5"></list2>
    <list3 id="6"></list3>
    <list4 id="7"></list4>
    <list2 id="8"></list2>
</root>

注意:添加的id个数在转换中没有作用;它们的唯一目的是方便比较输出和输入。

嵌套的规则是每个列表都嵌套在第一个列表编号比它自己的列表编号少 1 的前面的兄弟项下。

假设只有一个top list,名字是list1.

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="list-by-parent" 
         match="*[starts-with(name(), 'list')]" 
         use="generate-id(preceding-sibling::*[name()=concat('list', substring-after(name(current()),'list') - 1)][1])"/>

<xsl:template match="/root">
    <xsl:apply-templates select="list1"/>
</xsl:template>

<xsl:template match="*[starts-with(name(), 'list')]">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="key('list-by-parent', generate-id())"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

结果

<?xml version="1.0" encoding="UTF-8"?>
<list1 id="1">
   <list2 id="2">
      <list3 id="3"/>
      <list3 id="4"/>
   </list2>
   <list2 id="5">
      <list3 id="6">
         <list4 id="7"/>
      </list3>
   </list2>
   <list2 id="8"/>
</list1>