Динамическое группирование узлов XSLT посредством трансформации

Я пытаюсь создать подобную страницу с помощью XSLT-преобразования.

Страницы

  • Страница 1
  • страница 2

Ссылки

  • ссылка1
  • ссылка2

Вот xml

<siteMenu>
  <Pages>
    <title>page1</title>
  </Pages>
  <Pages>
    <title>page2</title>
  </Pages>
  <Links>
    <title>link1</title>
  </Links>
  <Links>
    <title>link2</title>
  </Links>
</siteMenu>

я пытался использовать

<xsl:for-each select="*"> and <xsl:for-each-group select="*" group-by="@v">

но это дает мне каждый элемент, но как я могу разделить их на основе родительского узла?

Я также хочу сделать его динамическим, чтобы, если я добавлю еще один элемент в siteMenu, он соответствующим образом обновил xslt.


person scott    schedule 21.04.2010    source источник


Ответы (3)


Итак, вы хотите сгруппировать по имени узла. Не лучшая идея хранить в узлах XML больше, чем фактическую информацию о структуре, но вот так:

<siteMenu>
  <Pages>
    <title>page1</title>
  </Pages>
  <Pages>
    <title>page2</title>
  </Pages>
  <Links>
    <title>link1</title>
  </Links>
  <Links>
    <title>link2</title>
  </Links>
  <Sites>
    <title>site1</title>
  </Sites>
  <Sites>
    <title>site2</title>
  </Sites>
</siteMenu>

и это преобразование XSLT 2.0 (только соответствующий фрагмент):

<xsl:template match="siteMenu">
  <xsl:for-each-group select="*" group-by="name()">
    <xsl:sort select="name()" />
    <div>
      <h1><xsl:value-of-select="current-grouping-key()" /></h1>
      <ul>
        <xsl:for-each select="current-group()">
          <li><xsl:value-of select="title" /></li>
        </xsl:for-each>
      </ul>
    </div>
  </xsl:for-each-group>
</xsl:template>

или это преобразование XSLT 1.0 (только соответствующий фрагмент):

<xsl:key name="kMenu" match="siteMenu/*" use="name()" />

<xsl:template match="siteMenu">
  <xsl:for-each select="*[
    generate-id() = generate-id(key('kMenu', name())[1])
  ]">
    <xsl:sort select="name()" />
    <div>
      <h1><xsl:value-of-select="name()" /></h1>
      <ul>
        <xsl:for-each select="key('kMenu', name())">
          <li><xsl:value-of select="title" /></li>
        </xsl:for-each>
      </ul>
    </div>
  </xsl:for-each-group>
</xsl:template>

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

<siteMenu>
  <section name="Pages">
    <title>page1</title>
    <title>page2</title>
  </section>
  <section name="Links">
    <title>link1</title>
    <title>link2</title>
  </section>
  <section name="Sites">
    <title>site1</title>
    <title>site2</title>
  </section>
</siteMenu>
person Tomalak    schedule 21.04.2010
comment
Это будет работать для XSLT 2.0, но не для 1.0. Тогда мне придется найти другой маршрут. - person scott; 21.04.2010
comment
@scott: Но вы сами использовали for-each-group в своем вопросе и не оставили никаких указаний на то, что вы используете XSLT 1.0. Я просто должен был предположить, что вы используете версию 2.0… Будет добавлено решение XSLT 1.0. - person Tomalak; 21.04.2010
comment
Я нашел идеальное решение, jenitennison.com/xslt/grouping/muenchian.html . Прекрасно работает. - person scott; 22.04.2010
comment
@scott: Этот ответ является мюнхской группировкой. - person Tomalak; 22.04.2010

Вы selecting все (*).

Используйте select="Pages" для выбора страниц и select="Links" для ссылок.

Узнайте о выражениях XPath здесь.

person Oded    schedule 21.04.2010
comment
Проблема в том, что я хочу сделать его динамичным. Так что я могу добавить еще один узел под названием «Сайты», и он добавит его в меню. - person scott; 21.04.2010

я бы начал с

<ul>
  <xsl:for-each select="//Pages">
    <li><xsl:value-of select="./title"/></li>
  </xsl:for-each>
</ul>

и продолжить оттуда.

person ndim    schedule 21.04.2010
comment
см. мой ответ Одеду о том, чтобы сделать его динамичным. - person scott; 21.04.2010