使用 XSLT 的列表虚拟嵌套

virtual nesting of list using XSLT

我需要按以下方式嵌套列表,我必须创建 n-1 个列表包装器,其中 n 是 @virtual-nesting 的值: XML 文档:

<l virtual-nesting="3">
    <li>
        <lilabel/>
        <p>
            <text>Data used:</text>
        </p>
    </li>
</l>

需要输出:

<list>
    <listitem>
        <bodytext>
            <list>
                <listitem>
                    <label/>
                    <bodytext>
                        <p>
                            <text>Data used:</text>
                        </p>
                    </bodytext>
                </listitem>
            </list>
        </bodytext>
    </listitem>
</list>

XSLT 我试过了。因为我是新手:

<xsl:template match="l">

    <xsl:choose>            
        <xsl:when test="@virtual-nesting">   
            <xsl:variable name="virtual"><xsl:value-of select="@virtual-nesting"/></xsl:variable>
            <xsl:if test="$virtual>0">                
                <xsl:apply-templates select="generate-id(following-sibling::node()),@virtual-nesting-1"/>                
            </xsl:if>            
            <xsl:apply-templates select="li"/>            
        </xsl:when>

        <xsl:otherwise>
            <xsl:element name="list">
                <xsl:apply-templates select="li"/> <!-- Template for list and lilabel is already created -->
            </xsl:element>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

请指导我完成此操作。

递归是在 XSLT 中创建嵌套结构的关键。

以下使用递归 <xsl:template match="l">$level 参数。此参数默认为 @virtual-nesting - 1,之后随着每个递归步骤递减。

模板根据其值采用两种不同的路径。

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

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="l">
    <xsl:param name="level" select="@virtual-nesting - 1" />
    <list>
      <listitem>
        <xsl:if test="$level &lt;= 1">
          <xsl:apply-templates />
        </xsl:if>
        <xsl:if test="$level &gt; 1">
          <bodytext>
            <xsl:apply-templates select=".">
              <xsl:with-param name="level" select="$level - 1" />
            </xsl:apply-templates>
          </bodytext>
        </xsl:if>
      </listitem>
    </list>
  </xsl:template>

  <xsl:template match="li">
    <label>
      <xsl:apply-templates select="lilabel/node()" />
    </label>
    <bodytext>
      <xsl:apply-templates select="node()[not(self::lilabel)]" />
    </bodytext>
  </xsl:template>
</xsl:transform>

结果:

<list>
   <listitem>
      <bodytext>
         <list>
            <listitem>
               <label/>
               <bodytext>
                  <p>
                     <text>Data used:</text>
                  </p>
               </bodytext>
            </listitem>
         </list>
      </bodytext>
   </listitem>
</list>