使用xslt为Umbraco创建菜单

时间:2010-04-20 06:19:08

标签: xslt umbraco

我使用XSLT在umbraco中创建了一个菜单。菜单使用通常的ul和li元素,我只显示菜单的第一级。目的是创建一个菜单,当我单击父节点(在顶层)时,该菜单会展开以显示子菜单。

我在xslt之后我需要在点击时公开子菜单。

我想我需要使用祖先或自我来检测当前菜单和父菜单并显示它们以及$ currentPage变量。

我有以下xslt:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
<xsl:stylesheet 
  version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxml="urn:schemas-microsoft-com:xslt" 
    xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:tagsLib="urn:tagsLib" xmlns:urlLib="urn:urlLib" 
    exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib urlLib ">

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

<xsl:param name="currentPage"/>

<xsl:template match="/">
    <div id="kb-categories"> 
        <h3>Categories</h3>
        <xsl:call-template name="drawNodes">  
            <xsl:with-param name="parent" select="$currentPage/ancestor-or-self::node [@level=1]"/>  
        </xsl:call-template>
    </div>
</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 $parent/@level = 1">           
        <ul class="kb-menuLevel1" >     
        <xsl:for-each select="$parent/node [string(./data [@alias='showInMenu']) = 1]"> 
            <li>  
                <a href="/kb{umbraco.library:NiceUrl(@id)}">
                    <xsl:value-of select="@nodeName"/>
                </a>                
                <xsl:variable name="level" select="@level" />
                <xsl:if test="(count(./node [string(./data [@alias='showInMenu']) = '1']) &gt; 0)">   
                    <xsl:call-template name="drawNodes">    
                        <xsl:with-param name="parent" select="."/>    
                    </xsl:call-template>  
                </xsl:if> 
            </li> 
        </xsl:for-each>
        </ul>
    </xsl:if>
    <xsl:if test="(umbraco.library:IsProtected($parent/@id, $parent/@path) = 0 or (umbraco.library:IsProtected($parent/@id, $parent/@path) = 1)) and $parent/@level &gt; 1">    
        <ul class="kb-menuLevel{@level}" style="display: none;">            
        <xsl:for-each select="$parent/node [string(./data [@alias='showInMenu']) = 1]"> 
            <li>  
                <a href="/kb{umbraco.library:NiceUrl(@id)}">
                    <xsl:value-of select="@nodeName"/>
                </a>                
                <xsl:variable name="level" select="@level" />
                <xsl:if test="(count(./node [string(./data [@alias='showInMenu']) = '1']) &gt; 0)">   
                    <xsl:call-template name="drawNodes">    
                        <xsl:with-param name="parent" select="."/>    
                    </xsl:call-template>  
                </xsl:if> 
            </li>
        </xsl:for-each>
        </ul>
    </xsl:if>

</xsl:template>

</xsl:stylesheet>

我怀疑使用apply-templates可以改善这一点,但我还没有达到速度(这只是我学习xslt的第二天)。

我的菜单:

  • 菜单项1
  • 菜单项2
  • 菜单项3
  • 菜单项4

当我点击菜单项2时,我将进入菜单项2的页面,子菜单也将显示:

  • 菜单项1
  • 菜单项2
    - 菜单项2.1
    - 菜单项2.2
  • 菜单项3
  • 菜单项4

依旧嵌套菜单。

以上是上面的一些示例xml。

<root>  
    <node id="1" nodeTypeAlias="kbHomepage" nodeName="Home" level="1">
        <data alias="introduction">
            <![CDATA[<p>Welcome</p>]]>
        </data>
        <node id="2" nodeTypeAlias="guide" nodeName="Menu Item 1" level="2">
            <data alias="bodyText">
                <![CDATA[<p>This is some text</p>]]>
            </data>
            <data alias="showInMenu">1</data>
            <data alias="menuName">Menu Item 1</data>
        </node>     
        <node id="3" nodeTypeAlias="guide" nodeName="Menu Item 2" level="2">
            <data alias="bodyText">
                <![CDATA[<p>This is some text</p>]]>
            </data>
            <data alias="showInMenu">1</data>
            <data alias="menuName">Menu Item 2</data>
            <node id="4" nodeTypeAlias="guide" nodeName="Menu Item 2.1" level="3">
                <data alias="bodyText">
                    <![CDATA[<p>Some Text</p>]]>
                </data>
                <data alias="showInMenu">1</data>
                <data alias="menuName">Menu Item 2.1</data>
            </node>
            <node id="5" nodeTypeAlias="guide" nodeName="Menu Item 2.2" level="3">
                <data alias="bodyText">
                    <![CDATA[<p>Some Text</p>]]>
                </data>
                <data alias="showInMenu">1</data>
                <data alias="menuName">Menu Item 2.2</data>
                <node id="6" nodeTypeAlias="guide" nodeName="Item 2.2.1 Guide" level="4">
                    <data alias="bodyText">
                        <![CDATA[<p>Some Text</p>]]>
                    </data>
                    <data alias="showInMenu">0</data>
                    <data alias="menuName"></data>
                </node>
            </node>
        </node>     
        <node id="8" nodeTypeAlias="guide" nodeName="Menu Item 3" level="2">
            <data alias="bodyText">
                <![CDATA[<p>This is some text</p>]]>
            </data>
            <data alias="showInMenu">1</data>
            <data alias="menuName">Menu Item 3</data>
        </node>     
        <node id="9" nodeTypeAlias="guide" nodeName="Menu Item 4" level="2">
            <data alias="bodyText">
                <![CDATA[<p>This is some text</p>]]>
            </data>
            <data alias="showInMenu">1</data>
            <data alias="menuName">Menu Item 4</data>
        </node>     
    </node>
    <node id="7" nodeTypeAlias="someAlias" nodeName="Some Other Page" level="1">
        <data alias="bodyText">
            <![CDATA[<p>This is some text</p>]]>
        </data>         
    </node>     
</root>

编辑:以下几乎可以满足我的需求:

<xsl:variable name="visibleChidren" select="node[data[@alias='showInMenu'] = 1 and (@level = 2 or descendant-or-self::*[generate-id($currentPage) = generate-id(.)] or preceding-sibling::*[generate-id($currentPage) = generate-id(.)] or following-sibling::*[generate-id($currentPage) = generate-id(.)])]" />

我只需要包含当前页面中的直接孩子。

3 个答案:

答案 0 :(得分:2)

我尝试(使用我对Umbraco的非常有限的知识)来清理你的代码并删除冗余。它看起来好像适用于您提供的XML示例,但我无法对Umbraco进行真正的测试。

<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxml="urn:schemas-microsoft-com:xslt"
  xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:tagsLib="urn:tagsLib" xmlns:urlLib="urn:urlLib"
  exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib urlLib ">

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

  <xsl:param name="currentPage" />

  <xsl:template match="/">
    <div id="kb-categories">
      <h3>Categories</h3>
      <xsl:apply-templates mode="list" select="/root/node[@nodeTypeAlias='kbHomepage']" />
    </div>
  </xsl:template>

  <!-- matches anything with <node> children and creates an <ul> -->
  <xsl:template match="*[node]" mode="list">
    <!-- prepare a list of all visible children -->
    <xsl:variable name="visibleChidren" select="node[
      data[@alias='showInMenu'] = 1
      and (
        not(umbraco.library:IsProtected(@id, @path)) 
        or umbraco.library:IsLoggedOn() 
      )
    ]" />
    <!-- prepare a CSS class for the "selected path" -->
    <xsl:variable name="display">
      <xsl:if test=".//node[generate-id() = generate-id($currentPage)]">
        <xsl:text>visible</xsl:text>
      </xsl:if>
    </xsl:variable>
    <xsl:if test="$visibleChidren">
      <ul class="menu kb-menuLevel{$visibleChidren[1]/@level} {$display}">
        <xsl:apply-templates mode="item" select="$visibleChidren" />
      </ul>
    </xsl:if>
  </xsl:template>

  <!-- matches <node> elements and turns them into list items -->
  <xsl:template match="node" mode="item">
    <li>
      <xsl:if test="generate-id() = generate-id($currentPage)">
        <xsl:attribute name="class">selected</xsl:attribute>
      </xsl:if>
      <a href="/kb{{umbraco.library:NiceUrl(@id)}}">
        <xsl:value-of select="@nodeName" />
      </a>
      <!-- if there are any child nodes, render them -->
      <xsl:if test="node">
        <xsl:apply-templates mode="list" select="." />
      </xsl:if>
    </li>
  </xsl:template>

</xsl:stylesheet>

给您以下内容。请注意,我已在<a href...中转义了属性值模板 - 删除上面的双重卷曲以再次启用它们:

<div id="kb-categories">
  <h3>Categories</h3>
  <ul class="menu kb-menuLevel2 visible">
    <li>
      <a href="/kb{umbraco.library:NiceUrl(@id)}">Menu Item 1</a>
    </li>
    <li>
      <a href="/kb{umbraco.library:NiceUrl(@id)}">Menu Item 2</a>
      <ul class="menu kb-menuLevel3 visible">
        <li class="selected">
          <a href="/kb{umbraco.library:NiceUrl(@id)}">Menu Item 2.1</a>
        </li>
        <li>
          <a href="/kb{umbraco.library:NiceUrl(@id)}">Menu Item 2.2</a>
        </li>
      </ul>
    </li>
    <li>
      <a href="/kb{umbraco.library:NiceUrl(@id)}">Menu Item 3</a>
    </li>
    <li>
      <a href="/kb{umbraco.library:NiceUrl(@id)}">Menu Item 4</a>
    </li>
  </ul>
</div>

现在你可以用CSS做了:

ul.menu {
  display: hidden;
}
ul.menu.visible {
  display: block;
}
ul.menu li.selected {
  font-weight: bold;
}

这对你有帮助吗?

答案 1 :(得分:0)

我想出了我需要做的事情。关键是:

<xsl:variable name="visibleChidren" select="node[data[@alias='showInMenu'] = 1 and (@level = 2 or descendant-or-self::*[generate-id($currentPage) = generate-id(.)] or preceding-sibling::*[generate-id($currentPage) = generate-id(.)] or following-sibling::*[generate-id($currentPage) = generate-id(.)] or parent::*[generate-id($currentPage) = generate-id(.)])]" />

来自整个xslt:

<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp "&#x00A0;"> ]>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:msxml="urn:schemas-microsoft-com:xslt"
  xmlns:umbraco.library="urn:umbraco.library" xmlns:Exslt.ExsltCommon="urn:Exslt.ExsltCommon" xmlns:Exslt.ExsltDatesAndTimes="urn:Exslt.ExsltDatesAndTimes" xmlns:Exslt.ExsltMath="urn:Exslt.ExsltMath" xmlns:Exslt.ExsltRegularExpressions="urn:Exslt.ExsltRegularExpressions" xmlns:Exslt.ExsltStrings="urn:Exslt.ExsltStrings" xmlns:Exslt.ExsltSets="urn:Exslt.ExsltSets" xmlns:tagsLib="urn:tagsLib" xmlns:urlLib="urn:urlLib"
  exclude-result-prefixes="msxml umbraco.library Exslt.ExsltCommon Exslt.ExsltDatesAndTimes Exslt.ExsltMath Exslt.ExsltRegularExpressions Exslt.ExsltStrings Exslt.ExsltSets tagsLib urlLib ">

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

  <xsl:param name="currentPage"/>
  <xsl:variable name="currentLevel" select="$currentPage/@level" />

  <xsl:template match="/">
    <div id="kb-categories">
      <h3>Categories</h3>
      <xsl:apply-templates mode="list" select="$currentPage/ancestor-or-self::node [@nodeTypeAlias = 'kbHomepage']" />
    </div>
  </xsl:template>

  <!-- matches anything with <node> children and makes a list out of them -->
  <xsl:template match="node" mode="list">
    <!-- select only sub-nodes that have 'showInMenu' = 1 -->
    <xsl:variable name="visibleChidren" select="node[data[@alias='showInMenu'] = 1 and (@level = 2 or descendant-or-self::*[generate-id($currentPage) = generate-id(.)] or preceding-sibling::*[generate-id($currentPage) = generate-id(.)] or following-sibling::*[generate-id($currentPage) = generate-id(.)] or parent::*[generate-id($currentPage) = generate-id(.)])]" />
    <xsl:if test="$visibleChidren">
      <ul>
        <xsl:apply-templates mode="item" select="$visibleChidren" />
      </ul>
    </xsl:if>
  </xsl:template>

  <xsl:template match="node" mode="item">
      <li>
        <a href="/kb{umbraco.library:NiceUrl(@id)}">
          <xsl:value-of select="@nodeName"/>
        </a>
        <xsl:apply-templates mode="list" select="." />
      </li>
  </xsl:template>

</xsl:stylesheet>

答案 2 :(得分:0)

或者你可以在XSLT中解决很多黑客攻击并使用my.umbraco.org中的以下导航包

我认为这就是你所需要的一切,而且不需要在XSLT的阴暗世界中弄脏你。

http://our.umbraco.org/projects/cogworks---flexible-navigation