Дайте родительским элементам класс, когда дети активны с XSLT - PullRequest
1 голос
/ 21 января 2010

До недавнего времени XSLT был для меня совершенно новым, и я некоторое время работал над меню / подменю в XSLT с датской CMS Dynamicweb.

Я не знаю, является ли это вопросом, специфичным для 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>

Вы можете видеть, как я добавляю классы на основе тегов Dynamicweb для active и inpath. Дело в том, что ниже в документе (здесь не вставлено) - это код для печати подменю (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 &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>

Ответы [ 2 ]

5 голосов
/ 21 января 2010

Ну и пара наблюдений:

  1. Вам не нужны начальные косые черты в match='//Page'. XPath в атрибуте match используется для выбора шаблона, а не перехода к узлу.

  2. Вам не нужен параметр depth; так как глубина Page - это число Page предков, которое у него есть, вы можете просто использовать count(ancestor::Page) для вычисления глубины.

  3. Если вы хотите получить атрибут Active, пройдя вверх по дереву Page элементов, используйте ancestor-or-self::Page[last()]/@Active. Ось ancestor-or-self - это список узлов, который начинается с узла контекста и включает его родителя, родителя его родителя и т. Д. До достижения 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' делает то же самое; он оценивается как true, если есть какой-либо дочерний элемент Page. Он более читабелен и, скорее всего, быстрее.

Редактировать

Включено наблюдение Томалака (см. Комментарии).

Редактировать

Знаете, я должен прочитать эти вопросы. В вашем контексте, чтобы дать родительскому элементу класс, когда он или один из его children активен, в противоположность тому, что я сделал, вы должны сделать:

<xsl:if test="@Active='True' or Page[@Active = 'True']">
    <xsl:text> active</xsl:text>
</xsl:if>

Но пример Томалака, который использует ось descendant-or-self, является более вероятным, чем вы хотите использовать, если идея состоит в том, чтобы активировать меню, если что-нибудь внутри него активно. Вы также можете сделать это:

<xsl:if test="@Active='True' or .//Page[@Active = 'True']">
    <xsl:text> active</xsl:text>
</xsl:if>

как ".//" - это просто сокращение для descendant::.

1 голос
/ 22 января 2010

Я создал решение вашей проблемы (и я сильно изменил ваш подход в процессе):

<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() &gt; 1 and position() &lt; 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 &amp; 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...