Как применить шаблоны к каждому выбранному узлу в for-each? - PullRequest
7 голосов
/ 25 октября 2009

Я знаю, что я что-то здесь упускаю. В приведенном ниже преобразовании XSLT фактический результат не соответствует желаемому результату.

Внутри for-each я хочу применить шаблон match="track" к каждому выбранному элементу track. Если я правильно понял XSLT, при текущей настройке сопоставляются только дочерние узлы каждого выбранного элемента track с шаблонами, а не сами элементы track.

Как я могу заставить элементы track проходить через шаблон по желанию? Нужно ли переосмыслить весь мой подход?

Примечание. Преобразование выполняется с использованием PHP. Объявления XML для краткости опущены.

XML-документ:

<album>
    <title>Grave Dancers Union</title>
    <track id="shove">Somebody To Shove</track>
    <track id="gold">Black Gold</track>
    <track id="train">Runaway Train</track>
    <producer>Michael Beinhorn</producer>
</album>

Таблица стилей XSL:

<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/album">
        <ol>
            <xsl:for-each select="track">
                <li><xsl:apply-templates/></li>
            </xsl:for-each>
        </ol>
    </xsl:template>

    <xsl:template match="track">
        <a href="{@id}"><xsl:apply-templates/></a>
    </xsl:template>
</xsl:stylesheet>

Результат:

<ol>
    <li>Somebody To Shove</li>
    <li>Black Gold</li>
    <li>Runaway Train</li>
</ol>

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

<ol>
    <li><a href="shove">Somebody To Shove</a></li>
    <li><a href="gold">Black Gold</a></li>
    <li><a href="train">Runaway Train</a></li>
</ol>

Ответы [ 4 ]

13 голосов
/ 25 октября 2009

Я бы согласился с 'ndim', что вам, вероятно, следует реструктурировать свой XSLT, чтобы покончить с циклом xsl: for-each.

В качестве альтернативы, вы можете изменить xsl: apply-templates, чтобы выбрать текущий узел дорожки в xsl: for-each

<xsl:for-each select="track">
   <li>
      <xsl:apply-templates select="." />
   </li>
</xsl:for-each>

Сохранение xsl: for-each позволит, по крайней мере, при желании отсортировать дорожки в другом порядке.

4 голосов
/ 25 октября 2009

Я бы немного его перестроил (если вам не нужна сортировка, возможен подход for-each):

<xsl:template match="/album">
  <ol>
    <xsl:apply-templates select="track"/>
  </ol>
</xsl:template>

<xsl:template match="track">
  <li><a href="{@id}"><xsl:apply-templates/></a></li>
<xsl:template>

Это выглядит короче и ближе к делу, ИМХО.

Я думаю, ваш

    <xsl:for-each select="track">
       <li><xsl:apply-templates/></li>
    </xsl:for-each>

просматривает все элементы дорожки с for-each, а затем применяет правила по умолчанию к его потомкам. Таким образом, содержимое for-each имеет тот же узел контекста, что и шаблон match="track", и, следовательно, шаблон match="track" никогда не совпадает.

Если вы действительно хотите использовать for-each таким образом, вам потребуется изменить одну из следующих двух вещей в вашем подходе:

  1. Добавьте атрибут name="track" в шаблон match="track", а затем используйте <xsl:call-template/> из for-each (моя идея, и хуже, чем Tim C)
  2. Используйте решение Tim C, используя <xsl:apply-templates select="."/>. Преимущество этого состоит в том, что вы избегаете именования и сохраняете возможность сортировки дорожек.
0 голосов
/ 29 октября 2009

Оператор for-each меняет контекстный узел с альбома на дорожку. Вызов apply-templates по умолчанию применяет шаблоны к дочерним узлам контекстного узла, которые в вашем случае являются дочерними узлами элемента track. Следовательно, ваш шаблон, который соответствует 'track', никогда не попадет.

0 голосов
/ 26 октября 2009

Я думаю, что применение apply-templates и Template Mode - более чистое решение:

<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>

  <xsl:template match="/">
    <body>
      <xsl:apply-templates select="album" mode="ol" />
    </body>
  </xsl:template>

  <xsl:template match="album" mode="ol">
    <ol>
      <xsl:apply-templates select="track" mode="li" />
    </ol>
  </xsl:template>

  <xsl:template match="track" mode="li">
    <li>
      <xsl:apply-templates select="." />
    </li>
  </xsl:template>

  <xsl:template match="track">
    <a href="{@id}">
      <xsl:value-of select="." />
    </a>
  </xsl:template>


</xsl:stylesheet>

Результат:

<body>
  <ol>
    <li>
      <a href="shove">Somebody To Shove</a>
    </li>
    <li>
      <a href="gold">Black Gold</a>
    </li>
    <li>
      <a href="train">Runaway Train</a>
    </li>
  </ol>
</body>
...