直到最近,XSLT对我来说还是全新的,我在XSLT中使用名为Dynamicweb的丹麦CMS进行了一段时间的菜单/子菜单。
我不知道这是一个Dynamicweb特定问题还是与XSLT相关的问题,但无论如何我都会问。
我当前的XSLT文档如下所示:
<xsl:template match="//Page">
<xsl:param name="depth"/>
<li>
<xsl:attribute name="id">
<xsl:value-of select="concat('', translate(translate(@MenuText, translate(@MenuText, $validRange, ''), ''), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))" />
</xsl:attribute>
<a>
<xsl:attribute name="class">
<!-- Add .inpath class -->
<xsl:if test="@InPath='True'">
<xsl:text> inpath</xsl:text>
</xsl:if>
<!-- Add .firstitem class -->
<xsl:if test="position() = 1">
<xsl:text> firstitem</xsl:text>
</xsl:if>
<!-- Add .miditem class -->
<xsl:if test="position() > 1 and position() < count(//Page)">
<xsl:text> miditem</xsl:text>
</xsl:if>
<!-- Add .lastitem class -->
<xsl:if test="position() = count(//Page)">
<xsl:text> lastitem</xsl:text>
</xsl:if>
<!-- Add .active class -->
<xsl:if test="@Active = 'True'">
<xsl:text> active</xsl:text>
</xsl:if>
</xsl:attribute>
<!-- Add link ID (URL friendly menu text) -->
<xsl:attribute name="id">
<xsl:value-of select="concat('anchor-', translate(translate(@MenuText, translate(@MenuText, $validRange, ''), ''), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'))" />
</xsl:attribute>
<!-- Add link URL -->
<xsl:attribute name="href">
<xsl:value-of select="@FriendlyHref" disable-output-escaping="yes" />
</xsl:attribute>
<!-- Add link text -->
<span><xsl:value-of select="@MenuText" disable-output-escaping="yes" /></span>
</a>
<xsl:if test="count(Page) and @MenuText != 'Home'">
<ul class="level{@AbsoluteLevel+1}">
<xsl:apply-templates select="Page">
<xsl:with-param name="depth" select="$depth+1"/>
</xsl:apply-templates>
</ul>
</xsl:if>
</li>
</xsl:template>
您可以看到我如何根据active
和inpath
的Dynamicweb标记添加类。问题是文档(未粘贴在此处)的下方是用于打印子菜单(ul
和li
)的代码。如果我单击一个子菜单项,该项将获得active
类,但是有没有办法给父级active
类?
更新:添加了原始XML(对于凌乱的XML抱歉)。
<?xml version="1.0" encoding="utf-8"?>
<NavigationTree>
<Settings>
<Pageview ID="1" AreaID="1" MenuText="Home" Title="Home" NavigationName="" />
<Setting Level="1">
<NavigationImage Value="" />
<NavigationMouseoverImage Value="" />
<NavigationActiveImage Value="" />
<NavigationImgAfter Value="" />
<NavigationDividerImage Value="" />
<NavigationHideSpacer Value="True" />
<NavigationSpace Value="0" />
</Setting>
<Setting Level="2">
<NavigationImage Value="" />
<NavigationMouseoverImage Value="" />
<NavigationActiveImage Value="" />
<NavigationImgAfter Value="" />
<NavigationDividerImage Value="" />
<NavigationHideSpacer Value="" />
<NavigationSpace Value="0" />
</Setting>
<Setting Level="3">
<NavigationImage Value="" />
<NavigationMouseoverImage Value="" />
<NavigationActiveImage Value="" />
<NavigationImgAfter Value="" />
<NavigationDividerImage Value="" />
<NavigationHideSpacer Value="" />
<NavigationSpace Value="0" />
</Setting>
<Setting Level="4">
<NavigationImage Value="" />
<NavigationMouseoverImage Value="" />
<NavigationActiveImage Value="" />
<NavigationImgAfter Value="" />
<NavigationDividerImage Value="" />
<NavigationHideSpacer Value="" />
<NavigationSpace Value="3" />
</Setting>
<Setting Level="5">
<NavigationImage Value="" />
<NavigationMouseoverImage Value="" />
<NavigationActiveImage Value="" />
<NavigationImgAfter Value="" />
<NavigationDividerImage Value="" />
<NavigationHideSpacer Value="" />
<NavigationSpace Value="3" />
</Setting>
</Settings>
<Page ID="1" AreaID="1" MenuText="Home" MouseOver="" Href="Default.aspx?ID=1" FriendlyHref="/default/home.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="1" RelativeLevel="1" Sort="1" LastInLevel="False" InPath="True" ChildCount="3" class="L1_Active" Active="True" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True">
<Page ID="6" AreaID="1" MenuText="News" MouseOver="" Href="Default.aspx?ID=6" FriendlyHref="/default/home/news.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="2" RelativeLevel="2" Sort="1" LastInLevel="False" InPath="False" ChildCount="0" class="L2" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" />
<Page ID="7" AreaID="1" MenuText="About" MouseOver="" Href="Default.aspx?ID=7" FriendlyHref="/default/home/about.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="2" RelativeLevel="2" Sort="2" LastInLevel="False" InPath="False" ChildCount="0" class="L2" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" />
<Page ID="8" AreaID="1" MenuText="Presence" MouseOver="" Href="Default.aspx?ID=8" FriendlyHref="/default/home/presence.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="2" RelativeLevel="2" Sort="3" LastInLevel="True" InPath="False" ChildCount="0" class="L2" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" />
</Page>
<Page ID="2" AreaID="1" MenuText="Hygiene" MouseOver="" Href="Default.aspx?ID=14" FriendlyHref="/default/hygiene.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="False" ShowInSitemap="True" AbsoluteLevel="1" RelativeLevel="1" Sort="2" LastInLevel="False" InPath="False" ChildCount="2" class="L1" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True">
<Page ID="14" AreaID="1" MenuText="Professional" MouseOver="" Href="Default.aspx?ID=14" FriendlyHref="/default/hygiene/professional.aspx" Image="/Files/Navigation/menu_antibac_01.gif" ImageActive="/Files/Navigation/menu_antibac_02.gif" ImageMouseOver="/Files/Navigation/menu_antibac_02.gif" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="2" RelativeLevel="2" Sort="1" LastInLevel="False" InPath="False" ChildCount="0" class="L2" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" />
<Page ID="15" AreaID="1" MenuText="Private" MouseOver="" Href="Default.aspx?ID=15" FriendlyHref="/default/hygiene/private.aspx" Image="/Files/Navigation/menu_antibac_01.gif" ImageActive="/Files/Navigation/menu_antibac_02.gif" ImageMouseOver="/Files/Navigation/menu_antibac_02.gif" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="2" RelativeLevel="2" Sort="2" LastInLevel="True" InPath="False" ChildCount="0" class="L2" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" />
</Page>
<Page ID="3" AreaID="1" MenuText="Household & Leisure" MouseOver="" Href="Default.aspx?ID=3" FriendlyHref="/default/household---leisure.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="1" RelativeLevel="1" Sort="3" LastInLevel="False" InPath="False" ChildCount="0" class="L1" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" />
<Page ID="4" AreaID="1" MenuText="Car Care" MouseOver="" Href="Default.aspx?ID=4" FriendlyHref="/default/car-care.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="1" RelativeLevel="1" Sort="4" LastInLevel="False" InPath="False" ChildCount="1" class="L1" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True">
<Page ID="20" AreaID="1" MenuText="Carix" MouseOver="" Href="Default.aspx?ID=20" FriendlyHref="/default/car-care/carix.aspx" Image="/Files/Navigation/menu_carix_01.gif" ImageActive="/Files/Navigation/menu_carix_02.gif" ImageMouseOver="/Files/Navigation/menu_carix_02.gif" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="2" RelativeLevel="2" Sort="1" LastInLevel="True" InPath="False" ChildCount="0" class="L2" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" />
</Page>
<Page ID="5" AreaID="1" MenuText="Industrial Chemicals" MouseOver="" Href="Default.aspx?ID=5" FriendlyHref="/default/industrial-chemicals.aspx" Image="" ImageActive="" ImageMouseOver="" Title="" Allowclick="True" ShowInSitemap="True" AbsoluteLevel="1" RelativeLevel="1" Sort="5" LastInLevel="True" InPath="False" ChildCount="0" class="L1" Active="False" IsPagePasswordProtected="False" IsPageUserProtected="False" CanAccessPasswordProtectedPage="False" CanAccessUserProtectedPage="True" />
</NavigationTree>
答案 0 :(得分:5)
嗯,有几点意见:
您不需要match='//Page'
中的前导斜杠。 match
属性中的XPath用于选择模板,而不是导航到节点。
您不需要depth
参数;由于Page
的深度是它所拥有的Page
祖先的数量,因此您只需使用count(ancestor::Page)
来计算深度。
如果您希望通过向上走Active
元素树获取Page
属性,请使用ancestor-or-self::Page[last()]/@Active
。祖先或自身轴是以上下文节点开始并包括其父节点,父节点的父节点等的节点列表,直到达到TLE为止。 Page
部分仅在该轴上找到Page
元素,[last()]
谓词找到最后一个Page
元素,这些元素始终是最高级{{1}元素。
我强烈怀疑你使用Page
从长远来看不会对你有好处。这会计算源树中的每个count(//Page)
元素,而不管它在何处被发现。这真的是你想要的吗?或者您想知道当前Page
元素相对于其兄弟Page
元素的位置?如果是这样,您可以Page
。这是有效的,因为position() != 1 and position() != last()
返回上下文节点相对于其表达式上下文的位置。也就是说,当调用position()
时,它会创建一组元素并为每个元素找到匹配的模板。这就是表达背景;该列表中的第三个元素的xsl:apply-templates select='*'
为3。
没有必要position()
。 test='count(Page)
做同样的事情;如果有任何子test='Page'
元素,则计算结果为true。它更具可读性,而且速度更快。
修改强>
收集Tomalak的观察(见评论)。
修改强>
你知道,我应该读这些问题。在你的上下文中,当一个类或它的一个 children 处于活动状态时,给一个父元素一个类,与我所做的相反,你会这样做:
Page
但Tomalak使用<xsl:if test="@Active='True' or Page[@Active = 'True']">
<xsl:text> active</xsl:text>
</xsl:if>
轴的示例更可能是您想要使用的,如果想要激活菜单,如果其中任何位置处于活动状态。你也可以这样做:
descendant-or-self
as“.//”实际上只是<xsl:if test="@Active='True' or .//Page[@Active = 'True']">
<xsl:text> active</xsl:text>
</xsl:if>
的快捷方式。
答案 1 :(得分:1)
我已经为你的问题创建了一个解决方案(我在这个过程中大量修改了你的方法):
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:variable name="upper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:variable name="lower" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="validRange" select="concat($upper, $lower)" />
<xsl:template match="NavigationTree">
<ul class="level1">
<xsl:apply-templates select="Page">
<xsl:sort select="@Sort" data-type="number" />
</xsl:apply-templates>
</ul>
</xsl:template>
<xsl:template match="Page">
<xsl:variable name="idText" select="
translate(
translate(@MenuText, translate(@MenuText, $validRange, ''), ''), $upper, $lower
)
" />
<li id="{$idText}">
<a href="{@FriendlyHref}" id="anchor-{$idText}">
<xsl:attribute name="class">
<xsl:if test="position() = 1">firstitem </xsl:if>
<xsl:if test="position() > 1 and position() < last()">miditem </xsl:if>
<xsl:if test="position() = last()">lastitem </xsl:if>
<xsl:if test="@InPath='True'">inpath </xsl:if>
<!-- the descendant-or-self XPath axis solves your question! -->
<xsl:if test="descendant-or-self::Page[@Active='True']">active </xsl:if>
</xsl:attribute>
<span>
<xsl:value-of select="@MenuText" />
</span>
</a>
<xsl:if test="Page">
<ul class="level{Page/@AbsoluteLevel}">
<xsl:apply-templates select="Page">
<xsl:sort select="@Sort" data-type="number" />
</xsl:apply-templates>
</ul>
</xsl:if>
</li>
</xsl:template>
</xsl:stylesheet>
导致(当第20页设置为“活动”时):
<ul class="level1">
<li id="home">
<a href="/default/home.aspx" id="anchor-home" class="firstitem inpath">
<span>Home</span>
</a>
<ul class="level2">
<li id="news">
<a href="/default/home/news.aspx" id="anchor-news" class="firstitem">
<span>News</span>
</a>
</li>
<li id="about">
<a href="/default/home/about.aspx" id="anchor-about" class="miditem">
<span>About</span>
</a>
</li>
<li id="presence">
<a href="/default/home/presence.aspx" id="anchor-presence" class="lastitem">
<span>Presence</span>
</a>
</li>
</ul>
</li>
<li id="hygiene">
<a href="/default/hygiene.aspx" id="anchor-hygiene" class="miditem">
<span>Hygiene</span>
</a>
<ul class="level2">
<li id="professional">
<a href="/default/hygiene/professional.aspx" id="anchor-professional" class="firstitem">
<span>Professional</span>
</a>
</li>
<li id="private">
<a href="/default/hygiene/private.aspx" id="anchor-private" class="lastitem">
<span>Private</span>
</a>
</li>
</ul>
</li>
<li id="householdleisure">
<a href="/default/household---leisure.aspx" id="anchor-householdleisure" class="miditem">
<span>Household & Leisure</span>
</a>
</li>
<li id="carcare">
<a href="/default/car-care.aspx" id="anchor-carcare" class="miditem active">
<span>Car Care</span>
</a>
<ul class="level2">
<li id="carix">
<a href="/default/car-care/carix.aspx" id="anchor-carix" class="firstitem lastitem active">
<span>Carix</span>
</a>
</li>
</ul>
</li>
<li id="industrialchemicals">
<a href="/default/industrial-chemicals.aspx" id="anchor-industrialchemicals" class="lastitem">
<span>Industrial Chemicals</span>
</a>
</li>
</ul>
请注意,您不希望disable-output-escaping="yes"
,我已将其删除,因为它会产生格式错误的XML。