使用xslt为Umbraco创建菜单
我已经使用XSLT在umbraco中创建了一个菜单。菜单使用常用的ul和li元素,我只显示菜单的第一级。其目的是创建一个菜单,当我单击父节点(在顶层)时,该菜单将展开以显示子菜单 我正在寻找xslt,单击时需要公开子菜单 我想我需要使用祖先或self来检测当前菜单和父菜单,并显示它们以及$currentPage变量 我有以下xslt:使用xslt为Umbraco创建菜单,xslt,umbraco,Xslt,Umbraco,我已经使用XSLT在umbraco中创建了一个菜单。菜单使用常用的ul和li元素,我只显示菜单的第一级。其目的是创建一个菜单,当我单击父节点(在顶层)时,该菜单将展开以显示子菜单 我正在寻找xslt,单击时需要公开子菜单 我想我需要使用祖先或self来检测当前菜单和父菜单,并显示它们以及$currentPage变量 我有以下xslt: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xsl:stylesheet [ <!E
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
<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']) > 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 > 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']) > 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模板可以改进这一点,但我还没有达到这个速度(这只是我学习xslt的第二天)
我的菜单:
- 菜单项1
- 菜单项2
- 菜单项3
- 菜单项4
- 菜单项1
- 菜单项2
--菜单项2.1
--菜单项2.2 - 菜单项3
- 菜单项4
<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>
欢迎光临]>
这是一些文字]>
1.
菜单项1
这是一些文字]>
1.
菜单项2
一些文字]>
1.
菜单项2.1
一些文字]>
1.
菜单项2.2
一些文字]>
0
这是一些文字]>
1.
菜单项3
这是一些文字]>
1.
菜单项4
这是一些文字]>
编辑:以下内容几乎满足了我的需要:
<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(.)])]" />
我只需要包含当前页面中的直接子项。我尝试(以我对Umbraco非常有限的知识)稍微清理一下您的代码并删除冗余。它看起来似乎可以与您提供的XML示例一起使用,但我无法真正针对Umbraco进行测试
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
<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>
这对你有帮助吗 我知道我需要做我想做的事。关键是:
<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 " "> ]>
<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>
类别
或者您可以解决XSLT中的大量黑客问题,并使用我们的.umbraco.org中的以下导航包
我认为这可以满足您的所有需要,并且不需要在XSLT的黑暗世界中弄脏您的双手
@rob\u g:在我们实现节点可见性之前,请确认我的代码到目前为止是否生成了正确的HTML输出。Tomalak,我已经添加了xml。除非单击菜单项,否则菜单应仅显示级别2节点。假设单击了菜单项2,则菜单项2下的所有级别2节点和所有级别3节点都应可见。单击菜单项2将打开其页面(由生成的元素决定。打开此页面后,$currentPage将引用它。我希望当前页面足以满足我的需要:显示$currentPage的所有直接子项以及级别2之前的所有祖先。谢谢。@rob_g:现在我有了您的XML…请回答三个问题:1)
实际上不是菜单的一部分?它做什么?2)如何从XML中判断单击了哪个节点?3) $currentPage
到底包含什么?对不起,我不知道。@Tomalak 1)umbraco页面由节点表示。主页具有由kbHomepage标识的特定布局。我不想显示主页,但它是开始子树的好地方。从技术上讲,可能有其他页面与kbHomepage处于同一级别,但我配置CMS的方式阻止了这一点。2) $currentPage将为您提供当前页面(即已单击的节点)。见#3。3) $currentPage是一个Umbraco对象,它存储表示正在查看的当前页面的节点。不确定magic umbraco如何填充该值。@rob_g:好的,我开始了,现在看清楚了,谢谢。因此,当我在浏览器中单击菜单项2
时,页面将重新加载,$currentPage
将正好是这个节点:
?谢谢Tim,但在你发布此评论之前,我已经把它全部工作好了。否则我会用它的!
<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(.)])]" />
<!DOCTYPE xsl:stylesheet [ <!ENTITY nbsp " "> ]>
<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>