当子项处于XSLT活动状态时,为父元素提供一个类

reb*_*ion 1 xml xslt

直到最近XSLT对我来说还是全新的,我一直在使用名为Dynamicweb的丹麦CMS在XSLT中使用菜单/子菜单.

我不知道这是一个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() &gt; 1 and position() &lt; 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>
Run Code Online (Sandbox Code Playgroud)

您可以看到我如何基于Dynamicweb标记为active和添加类inpath.问题是文档中的更下方(此处未粘贴)是用于打印子菜单(ulli)的代码.如果我单击一个子菜单项,该项目将获得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 &amp; 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>
Run Code Online (Sandbox Code Playgroud)

Rob*_*ney 5

好吧,有几点意见:

  1. 你不需要使用前导斜杠match='//Page'.match属性中的XPath 用于选择模板,而不是导航到节点.

  2. 你不需要depth参数; 由于a的深度PagePage它的祖先数量,你可以count(ancestor::Page)用来计算深度.

  3. 如果要Active通过向上走Page元素树来获取属性,请使用ancestor-or-self::Page[last()]/@Active.祖先或自身轴是以上下文节点开始并包括其父节点,父节点的父节点等的节点列表,直到达到TLE为止.该Page部件仅查找Page该轴上的元素,并且[last()]谓词查找这些Page元素中的最后一个元素,这些元素始终是最高级别的Page元素.

  4. 我强烈怀疑count(//Page)从长远来看,你的使用并不能很好地为你服务.这会计算Page源树中的每个元素,无论它在何处被发现.这真的是你想要的吗?或者您想知道当前Page元素相对于其兄弟Page元素的位置?如果是这样,你可以这样做position() != 1 and position() != last().这是有效的,因为position()返回上下文节点相对于其表达式上下文的位置.也就是说,在xsl:apply-templates select='*'调用时,它会创建一组元素并为每个元素找到匹配的模板.这就是表达背景; 该列表中的第三个元素将具有position()3个.

  5. 没有必要这样做test='count(Page). test='Page'做同样的事情; 如果有任何子Page元素,则计算结果为true .它更具可读性,而且速度更快.

编辑

纳尔马克的观察结果(见评论).

编辑

你知道,我应该读这些问题.在你的情况下,给予父元素的类时,它或它的一个孩子是活动的,我所做的一切正好相反,你会怎么做:

<xsl:if test="@Active='True' or Page[@Active = 'True']">
    <xsl:text> active</xsl:text>
</xsl:if>
Run Code Online (Sandbox Code Playgroud)

但是Tomalak使用descendant-or-self轴的例子更有可能是你想要使用的,如果想要激活一个菜单,如果它内的任何地方都是活动的.你也可以这样做:

<xsl:if test="@Active='True' or .//Page[@Active = 'True']">
    <xsl:text> active</xsl:text>
</xsl:if>
Run Code Online (Sandbox Code Playgroud)

因为".//"实际上只是一个捷径descendant::.