我正在尝试为umbraco内容管理系统上的网站构建一个多级dropdrown 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>孩子。

有谁指出我正确的方向?

有帮助吗?

解决方案

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

以下是应解决问题的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>

其他提示

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

<xsl:apply-templates/>

的节点列表 在应用模板之前,

不为空:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes"/>
  <xsl:variable name="vLevel" select="0"/>

    <xsl:template match="root">
      <xsl:variable name="vnextLevelNodes"
           select="node[@level = $vLevel+1]"/>
      <xsl:if test="$vnextLevelNodes">
       <ul>
         <xsl:apply-templates select="$vnextLevelNodes"/>
       </ul>
      </xsl:if>
    </xsl:template>

    <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"> -->
    <xsl:if test="1">
        <li>
          <!-- <a href="{umbraco.library:NiceUrl(@id)}"> -->
          <a href="'umbraco.library:NiceUrl(@id)'">
            <xsl:value-of select="@nodeName"/>
          </a>

                  <xsl:variable name="vnextLevelNodes"
                       select="node[@level = current()/@level+1]"/>
                  <xsl:if test="$vnextLevelNodes">
                   <ul>
                     <xsl:apply-templates select="$vnextLevelNodes"/>
                   </ul>
                  </xsl:if>
        </li>
    </xsl:if>
    </xsl:template>
</xsl:stylesheet>

我使用了以下XML源文档:

<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>

此外,我已注释掉任何引用Umbraco扩展功能的代码,因为我无法访问它们。

当对此源XML文档应用上述转换时,会生成正确的所需结果:

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

希望这会有所帮助。

干杯,

Dimitre Novatchev

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top