4

我正在尝试为我在 umbraco 内容管理系统上做的网站构建一个多级下拉 CSS 菜单。

我需要构建它以具有以下结构:

<ul id="nav">
  <li><a href="..">Page #1</a></li>
  <li>
    <a href="..">Page #2</a>
    <ul>
      <li><a href="..">Subpage #1</a></li>
      <li><a href="..">Subpage #2</a></li>        
    </ul>
  </li>
</ul>

所以现在我试图弄清楚如何使用 XSLT 进行嵌套。这是我到目前为止所拥有的:

<xsl:output method="xml" omit-xml-declaration="yes"/>

<xsl:param name="currentPage"/>

<!-- update this variable on how deep your menu should be -->
<xsl:variable name="maxLevelForMenu" select="4"/>

<xsl:template match="/">
  <ul id="nav">
    <xsl:call-template name="drawNodes">  
      <xsl:with-param 
       name="parent" 
       select="$currentPage/ancestor-or-self::node [@level=1]"
      />  
    </xsl:call-template>
  </ul>
</xsl:template>

<xsl:template name="drawNodes">
  <xsl:param name="parent"/> 
  <xsl:if test="umbraco.library:IsProtected($parent/@id, $parent/@path) = 0 or (umbraco.library:IsProtected($parent/@id, $parent/@path) = 1 and umbraco.library:IsLoggedOn() = 1)">
    <xsl:for-each select="$parent/node [string(./data [@alias='umbracoNaviHide']) != '1' and @level &lt;= $maxLevelForMenu]"> 
      <li>
        <a href="{umbraco.library:NiceUrl(@id)}">
          <xsl:value-of select="@nodeName"/>
        </a>  
        <xsl:if test="count(./node [string(./data [@alias='umbracoNaviHide']) != '1' and @level &lt;= $maxLevelForMenu]) &gt; 0">   
          <xsl:call-template name="drawNodes">    
            <xsl:with-param name="parent" select="."/>    
          </xsl:call-template>  
        </xsl:if> 
      </li>
    </xsl:for-each>
  </xsl:if>
</xsl:template>

我似乎无法弄清楚如何检查第一级(此处为第 1 页和第 2 页)是否有任何子级,以及是否添加了额外的<ul>以包含<li>子级。

有人在那里指出我正确的方向吗?

4

2 回答 2

5

首先,不需要传递 aparent参数。上下文将传输此信息。

这是应该解决您的问题的 XSL 样式表:

<!-- update this variable on how deep your menu should be -->
<xsl:variable name="maxLevelForMenu" select="4"/>

<!--- match the document root --->
<xsl:template match="/root">
  <div id="nav">
    <xsl:call-template name="SubTree" />
  </div>
</xsl:template>

<!-- this will be called by xsl:apply-templates -->
<xsl:template match="node">
  <!-- the node is either protected, or the user is logged on (no need to check for IsProtected twice) -->
  <xsl:if test="umbraco.library:IsProtected($parent/@id, $parent/@path) = 0 or umbraco.library:IsLoggedOn() = 1">
    <li>
      <a href="{umbraco.library:NiceUrl(@id)}"><xsl:value-of select="@nodeName"/></a>
      <xsl:call-template name="SubTree" />
    </li>
  </xsl:if>
</xsl:template>

<xsl:template name="SubTree">
  <!-- render sub-tree only if there are any child nodes --->
  <xsl:if test="node">
    <ul>
      <xsl:apply-templates select="node[data[@alias='umbracoNaviHide'] != '1'][@level &lt;= $maxLevelForMenu]">
        <!-- ensure sorted output of the child nodes --->
        <xsl:sort select="@sortOrder" data-type="number" />
      </xsl:apply-templates>
    </ul>
  </xsl:if>
</xsl:template>

这是我对其进行测试的 XML(我对 Umbraco 了解不多,但在查看了一些示例后,我希望我能接近 Umbraco 文档):

<root id="-1">
  <node id="1" level="1" sortOrder="1" nodeName="Page #1">
    <data alias="umbracoNaviHide">0</data>
  </node>
  <node id="2" level="1" sortOrder="2" nodeName="Page #2">
    <data alias="umbracoNaviHide">0</data>
    <node id="3" level="2" sortOrder="2" nodeName="Subpage #2.2">
      <data alias="umbracoNaviHide">0</data>
    </node>
    <node id="4" level="2" sortOrder="1" nodeName="Subpage #2.1">
      <data alias="umbracoNaviHide">0</data>
      <node id="5" level="3" sortOrder="3" nodeName="Subpage #2.1.1">
        <data alias="umbracoNaviHide">0</data>
      </node>
    </node>
    <node id="6" level="2" sortOrder="3" nodeName="Subpage #2.3">
      <data alias="umbracoNaviHide">1</data>
    </node>
  </node>
  <node id="7" level="1" sortOrder="3" nodeName="Page #3">
    <data alias="umbracoNaviHide">1</data>
  </node>
</root>

这是输出:

<div id="nav">
  <ul>
    <li><a href="http://foo/">Page #1</a></li>
    <li><a href="http://foo/">Page #2</a>
      <ul>
        <li><a href="http://foo/">Subpage #2.1</a>
          <ul>
            <li><a href="http://foo/">Subpage #2.1.1</a></li>
          </ul>
        </li>
        <li><a href="http://foo/">Subpage #2.2</a></li>
      </ul>
    </li>
  </ul>
</div>
于 2008-11-21T12:50:17.410 回答
0

这个问题没有什么特别之处。以下解决方案测试节点列表

<xsl:apply-templates/>

不为空,在应用模板之前:

<xsl:stylesheet 版本="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:输出省略-xml-declaration="yes"/>
  <xsl:variable name="vLevel" select="0"/>

    <xsl:template match="root">
      <xsl:变量名="vnextLevelNodes"
           select="节点[@level = $vLevel+1]"/>
      <xsl:if test="$vnextLevelNodes">
       <ul>
         <xsl:apply-templates select="$vnextLevelNodes"/>
       </ul>
      </xsl:if>
    </xsl:模板>

    <xsl:template match="节点">
  <!-- 节点要么受保护,要么用户已登录(无需检查 IsProtected 两次)-->
    <!-- <xsl:if 测试=
      “umbraco.library:IsProtected($parent/@id, $parent/@path) = 0
      或者
       umbraco.library:IsLoggedOn() = 1"> -->
    <xsl:if test="1">
        <li>
          <!-- <a href="{umbraco.library:NiceUrl(@id)}"> -->
          <a href="'umbraco.library:NiceUrl(@id)'">
            <xsl:value-of select="@nodeName"/>
          </a>

                  <xsl:变量名="vnextLevelNodes"
                       select="节点[@level = current()/@level+1]"/>
                  <xsl:if test="$vnextLevelNodes">
                   <ul>
                     <xsl:apply-templates select="$vnextLevelNodes"/>
                   </ul>
                  </xsl:if>
        </li>
    </xsl:if>
    </xsl:模板>
</xsl:样式表>

我使用了以下 XML 源文档:

<root id="-1">
    <node id="1" level="1" sortOrder="1" nodeName="Page #1">
        <data alias="umbracoNaviHide">0</data>
    </节点>
    <node id="2" level="1" sortOrder="2" nodeName="Page #2">
        <data alias="umbracoNaviHide">0</data>
        <node id="3" level="2" sortOrder="2" nodeName="Subpage #2.2">
            <data alias="umbracoNaviHide">0</data>
        </节点>
        <node id="4" level="2" sortOrder="1" nodeName="Subpage #2.1">
            <data alias="umbracoNaviHide">0</data>
            <node id="5" level="3" sortOrder="3" nodeName="子页面#2.1.1">
                <data alias="umbracoNaviHide">0</data>
            </节点>
        </节点>
        <node id="6" level="2" sortOrder="3" nodeName="Subpage #2.3">
            <data alias="umbracoNaviHide">1</data>
        </节点>
    </节点>
    <node id="7" level="1" sortOrder="3" nodeName="Page #3">
        <data alias="umbracoNaviHide">1</data>
    </节点>
</root>

此外,我已经注释掉了任何引用 Umbraco 扩展函数的代码,因为我无权访问它们。

当对这个源 XML 文档应用上述转换时,会产生正确的、想要的结果:

<ul>
    <li>
        <a href="'umbraco.library:NiceUrl(@id)'">第 1 页</a>
    </li>
    <li>
        <a href="'umbraco.library:NiceUrl(@id)'">第 2 页</a>
        <ul>
            <li>
                <a href="'umbraco.library:NiceUrl(@id)'">子页面 #2.2</a>
            </li>
            <li>
                <a href="'umbraco.library:NiceUrl(@id)'">子页面 #2.1</a>
                <ul>
                    <li>
                        <a href="'umbraco.library:NiceUrl(@id)'">子页面 #2.1.1</a>
                    </li>
                </ul>
            </li>
            <li>
                <a href="'umbraco.library:NiceUrl(@id)'">子页面 #2.3</a>
            </li>
        </ul>
    </li>
    <li>
        <a href="'umbraco.library:NiceUrl(@id)'">第 3 页</a>
    </li>
</ul>

希望这有帮助。

干杯,

迪米特·诺瓦切夫

于 2008-11-21T15:07:20.067 回答