将XML邻接列表模型规范化为HTML树列表

时间:2011-06-21 15:09:14

标签: xslt

我已经看到了转换“邻接模型”XML的例子,但没有一个能够完全适合ul / li子弹列表。有人能给我一个暗示吗?如果解决方案可以支持典型的邻接模型需求并处理多级嵌套/递归,那将是很好的。

如果XML是:

<?xml version="1.0" encoding="ISO-8859-1"?>
<root>
  <row Id="2" Name="data" />
  <row Id="3" Name="people" />
  <row Id="4" Name="person" ParentId="3" />
  <row Id="6" Name="folder" ParentId="2" />
  <row Id="7" Name="thing" ParentId="3" />
  <row Id="8" Name="web" />
  <row Id="9" Name="link" ParentId="8" />
</root>

我用的是:

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="/">
<ul id="someid" class="menu">
  <xsl:apply-templates select="root/row[not(@ParentId)]"/>
</ul>
</xsl:template>

<xsl:template match="row">
<ul>
    <li>
    <xsl:variable name="ID" select="@Id"/>
      <xsl:attribute name="rel">
      <xsl:value-of select="@Id"/>
      </xsl:attribute>
      <xsl:value-of select="@Name"/>
      <xsl:apply-templates select="//row[@ParentId=$ID]"/>
   </li>
</ul>
</xsl:template>

</xsl:stylesheet>   

然后我得到:

<ul id="someid" class="menu">
  <ul>
    <li rel="2">
      data<ul>
        <li rel="6">folder</li>
      </ul>
    </li>
  </ul>
  <ul>
    <li rel="3">
      people
      <ul>
        <li rel="4">person</li>
      </ul><ul>
        <li rel="7">thing</li>
      </ul>
    </li>
  </ul>
  <ul>
    <li rel="8">
      web<ul>
        <li rel="9">link</li>
      </ul>
    </li>
  </ul>
</ul>

请注意,“人”和“事物”之间的额外关闭/打开ul标签不应该存在。我可以看到它为什么会发生但只是不确定如何更改代码来修复它。

感谢。

2 个答案:

答案 0 :(得分:3)

已更新以反映OP新请求

这是一个递归模板,可以在W3C规范中对符合HTML的嵌套列表进行详细说明。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:output indent="yes"/>

    <xsl:template match="/root">
        <ul id="someid" class="menu">
            <xsl:apply-templates select="row[not(@ParentId)]"/>
        </ul>
    </xsl:template>

    <xsl:template match="row">
        <li rel="{@Id}">
            <xsl:value-of select="@Name"/>
            <xsl:if test="count(../row[@ParentId=current()/@Id])>0">
                <ul>
                    <xsl:apply-templates select="../row[@ParentId=current()/@Id]"/>
                </ul>
            </xsl:if>
        </li>
    </xsl:template>

</xsl:stylesheet>

应用于此输入:

<root>
  <row Id="1" Name="data" />
  <row Id="2" Name="data" />
  <row Id="3" Name="people" />
  <row Id="4" Name="person" ParentId="3" />
  <row Id="6" Name="folder" ParentId="2" />
  <row Id="7" Name="thing" ParentId="3" />
  <row Id="8" Name="web" />
  <row Id="9" Name="link" ParentId="8" />
    <row Id="10" Name="anotherone" ParentId="9" />
    <row Id="11" Name="anotherone" ParentId="9" />
    <row Id="12" Name="anotherone" ParentId="9" />
    <row Id="13" Name="anotherone" ParentId="3" />
</root>

产地:

<ul id="someid" class="menu">
   <li rel="1">data</li>
   <li rel="2">data<ul>
         <li rel="6">folder</li>
      </ul>
   </li>
   <li rel="3">people<ul>
         <li rel="4">person</li>
         <li rel="7">thing</li>
         <li rel="13">anotherone</li>
      </ul>
   </li>
   <li rel="8">web<ul>
         <li rel="9">link<ul>
               <li rel="10">anotherone</li>
               <li rel="11">anotherone</li>
               <li rel="12">anotherone</li>
            </ul>
         </li>
      </ul>
   </li>
</ul>

如果您对如何创建列表感到困扰,请在W3School处尝试。

答案 1 :(得分:2)

您非常接近,只需将<xsl:variable name="ID" select="@Id"/><xsl:apply-templates select="//row[@ParentId=$ID]"/>移到<ul>...</ul>声明之外。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

  <xsl:template match="/">
    <ul id="someid" class="menu">
      <xsl:apply-templates select="root/row[not(@ParentId)]"/>
    </ul>
  </xsl:template>

  <xsl:template match="row">
    <xsl:variable name="ID" select="@Id"/>
      <li>
        <xsl:attribute name="rel">
          <xsl:value-of select="@Id"/>
        </xsl:attribute>
        <xsl:value-of select="@Name"/>
      </li>
    <xsl:if test="//row[@ParentId=$ID]">
      <ul>
        <xsl:apply-templates select="//row[@ParentId=$ID]"/>
      </ul>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>

这会产生我认为你正在寻找的结果

<ul id="someid" class="menu">
  <li rel="2">data</li>
  <ul>
    <li rel="6">folder</li>
  </ul>
  <li rel="3">people</li>
  <ul>
    <li rel="4">person</li>
    <li rel="7">thing</li>
  </ul>
  <li rel="8">web</li>
  <ul>
    <li rel="9">link</li>
  </ul>
</ul>

这也会删除顶级<ul>

之前的额外<li rel="2">