Возможно ли лучшее управление for-each в xsl / xpath? - PullRequest
1 голос
/ 25 июня 2010

Привет, друзья! У меня есть еще одна проблема xsl / xpath.Конечно, проблема для начинающих, но я думаю, что все еще слишком "настоятельно".

<!-- XML -->
<Module>
    <WideTeaserElement>
      <Headline>Bla bla 1</Headline>
    </WideTeaserElement>
    <WideTeaserElement>
      <Headline>Bla bla 2</Headline>
    </WideTeaserElement>
</Module>

<!-- XSL -->
<!-- You are already in the Node Module -->
<xsl:template match="WideTeaserElement">
    <ul class="TabbedPanelsTabGroup">
        <xsl:for-each select=".">
            <li class="TabbedPanelsTab"><a href="#"><xsl:value-of select="pub:Headline"/></a></li>
         </xsl:for-each>
    </ul>
</xsl>

И что я хочу получить в качестве результата:

<ul class="TabbedPanelsTabGroup">
     <li class="TabbedPanelsTab"><a href="#">Bla bla 1</a></li>
     <li class="TabbedPanelsTab"><a href="#">Bla bla 2</a></li>
</ul>

С моим XSL я получаю вывод с двумя <ul> Элементами.Итак, мой вопрос включает в себя две вещи: 1) Как должно быть преобразование для моей проблемы выше?2) Как вы можете обрабатывать циклы наподобие for-each в XSL, чтобы он был более «под контролем»?

Ответы [ 3 ]

2 голосов
/ 25 июня 2010

Это преобразование (полностью в духе XSLT):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="Module">
   <ul>
     <xsl:apply-templates/>
   </ul>
 </xsl:template>

 <xsl:template match="Headline">
   <li class="TabbedPanelsTab"><a href="#"><xsl:value-of select="."/></a></li>
 </xsl:template>
</xsl:stylesheet>

при применении к предоставленному документу XML :

<Module>
    <WideTeaserElement>
      <Headline>Bla bla 1</Headline>
    </WideTeaserElement>
    <WideTeaserElement>
      <Headline>Bla bla 2</Headline>
    </WideTeaserElement>
</Module>

дает желаемый результат :

<ul>
    <li class="TabbedPanelsTab">
        <a href="#">Bla bla 1</a>
    </li>
    <li class="TabbedPanelsTab">
        <a href="#">Bla bla 2</a>
    </li>
</ul>
2 голосов
/ 25 июня 2010

Вы почти никогда не должны использовать for-each в XSL, и если вы обнаружите, что используете его, вы, вероятно, упускаете важный бит силы XSL.

Ваш случай можетбыть гораздо более идиоматически выраженным путем предоставления шаблона для элемента HeadLine (содержащего ваш элемент <li>...</li>), а затем с помощью <xsl:apply-templates/> в элементе <ul> в шаблоне WideTeaserElement.

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match='Module'>
    <ul class='TabbedPanelsTabGroup'>
      <xsl:apply-templates/>
    </ul>
  </xsl:template>
  <xsl:template match='Headline'>
    <li class='TabbedPanelsTab'><a href='#'><xsl:apply-templates/></a></li>
  </xsl:template>
</xsl:stylesheet>
1 голос
/ 26 июня 2010

Причина, по которой вы получаете два элемента ul, заключается в том, что ваш шаблон, генерирующий элемент ul, соответствует элементам с именем WideTeaserElement, из которых у вас есть два.

Я думаю, что я могу видеть, гдемы думали об этом - предполагали ли вы, что этот шаблон будет обрабатывать все WideTeaserElement с за одну операцию, которую затем вы можете повторить с помощью «для каждого из них»?Вместо этого шаблон вызывается отдельно для каждого вхождения узла WideTeaserElement, а затем «перебирает» его единственное вхождение.

Я согласен с Норманом в том, что for-each редко является лучшим вариантом, ноЯ могу подумать о двух причинах, по которым вы могли бы его использовать.

  • Удобочитаемость;если объем обработки для каждой итерации относительно мал, это может облегчить чтение вашей таблицы стилей, если код, обрабатывающий ее, находится в родительском шаблоне.

Для (очень упрощенного) примера япредпочел бы

 <xsl:template match="mylist">
   <xsl:element name="ul">
     <xsl:for-each select="listitem">
       <xsl:element name="li">
         <xsl:value-of select="." />
       </xsl:element>
     </xsl:for-each>
   </xsl:element>
 </xsl:template>

вместо

<xsl:template match="mylist">
  <xsl:element name="ul">
    <xsl:apply-templates select="listitem" />
  </xsl:element>
</xsl:template>

<xsl:template match="listitem">
  <xsl:element name="li">
    <xsl:value-of select="." />
  </xsl:element>
</xsl:template>

, если бы шаблон mylist на самом деле содержал намного больше кода, и последнее решение означало бы необходимость прокручивать мой код вниз, чтобы увидетькак обрабатывается listitemЭто субъективно, хотя, некоторые могут предпочесть последнее решение всегда.Лично я обычно нахожу, что большинство шаблонов достаточно велики, чтобы разбивать их лучше для удобства чтения, но в меньших это не всегда так.

  • Там, где вы не хотите, чтобы узлы повторялисьбудет рассматриваться как шаблон.В приведенном выше примере последнее решение будет преобразовывать ВСЕ listitem теги, а не только те, которые находятся внутри тега «mylist».Конечно, его можно ограничить, изменив совпадение на listitem[parent::mylist], но часто for-each просто точнее, чем создание нескольких шаблонов для одного и того же имени элемента на основе родословной.

Вообще говоря, хотяобычно вы можете заменить

<xsl:template match="foo">
  <xsl:for-each select="bar">
    ..
  </xsl:for-each>
</xsl:template>

на

<xsl:template match="foo">
  <xsl:apply-templates select="bar" />
</xsl:template>

<xsl:template match="bar">
  ..
</xsl:template>

в любом документе, где элемент bar всегда имеет элемент foo в качестве родительского.

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