2016-03-11 1 views
1

Я пытаюсь добавить элементы с запятой и пробелом в <album>, если это не последний <album> внутри родителя <recording>.Добавление пунктуации во вложенные шаблоны

У меня есть аналогичный шаблон для <recording> s, который работает должным образом. Тем не менее, я не могу заставить второй шаблон для пунктуации <album> работать правильно.

Я считаю, что есть что-то сделать, чтобы с первого шаблона существующего ...

Входной XML

<sample> 
<collection> 
    <recording> 
     <artist>Radiohead</artist> 
     <album>OK Computer</album> 
    </recording> 
    <recording> 
     <artist>Tori Amos</artist> 
     <album>Boys For Pele</album> 
     <album>To Venus And Back</album> 
    </recording> 
</collection> 

Пример XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
exclude-result-prefixes="xs" 
version="2.0"> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="collection"> 
    <xsl:copy> 
     <xsl:for-each select="recording"> 
      <xsl:copy> 
       <xsl:apply-templates select="node() | @*"/> 
      </xsl:copy> 
      <xsl:if test="position()!=last()"> 
       <xsl:element name="x">, </xsl:element> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="recording"> 
    <xsl:copy> 
     <xsl:for-each select="album"> 
      <xsl:copy> 
       <xsl:apply-templates select="node() | @*"/> 
      </xsl:copy> 
      <xsl:if test="position()!=last()"> 
       <comma>, </comma> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 

Но мой выход

<sample> 
<collection> 
    <recording> 
     <artist>Radiohead</artist> 
     <album>OK Computer</album> 
    </recording><x>, </x> 
    <recording> 
     <artist>Tori Amos</artist> 
     <album>Boys For Pele</album> 
     <album>To Venus And Back</album> 
    </recording> 
</collection> 

Вместо того, что я хочу (обратите внимание на <x> после первого <album> во втором <recording>)

<sample> 
    <collection> 
     <recording> 
      <artist>Radiohead</artist> 
      <album>OK Computer</album> 
     </recording><x>, </x> 
     <recording> 
      <artist>Tori Amos</artist> 
      <album>Boys For Pele</album><x>, </x> 
      <album>To Venus And Back</album> 
     </recording> 
    </collection> 
</sample> 

ответ

1

Измените свой второй (соответствует коллекция) шаблон

<xsl:template match="collection"> 
    <xsl:copy> 
     <xsl:for-each select="recording"> 
      <xsl:apply-templates select="."/> 
      <xsl:if test="position()!=last()"> 
       <xsl:element name="x">, </xsl:element> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 

и изменить ваши записи шаблон

<xsl:template match="recording"> 
    <xsl:copy> 
     <xsl:apply-templates select="(node() | @*) except album"/> 
     <xsl:for-each select="album"> 
      <xsl:copy> 
       <xsl:apply-templates select="node() | @*"/> 
      </xsl:copy> 
      <xsl:if test="position()!=last()"> 
       <x>, </x> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 

удаления xsl:copy элемент и заменить его с xsl:apply-templates элементом и перемещение вызова на другой записи детей в запись шаблон.

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

Кроме того, в шаблоне записи, вы добавляете запятой элемент вместо х элемента. Я изменил их на x элементов выше, так как это то, что вы, кажется, хотели.


Кроме того, ваш первый xsl:for-each не нужен.Если мы перемещаем тест положение из коллекции шаблона в записи шаблона мы можем упростить Collection шаблон, чтобы избежать xsl:for-each:

<xsl:template match="collection"> 
    <xsl:copy> 
     <xsl:apply-templates select="recording"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="recording"> 
    <xsl:copy> 
     <xsl:apply-templates select="(node() | @*) except album"/> 
     <xsl:for-each select="album"> 
      <xsl:copy> 
       <xsl:apply-templates select="node() | @*"/> 
      </xsl:copy> 
      <xsl:if test="position()!=last()"> 
       <x>, </x> 
      </xsl:if> 
     </xsl:for-each> 
    </xsl:copy> 
    <xsl:if test="position()!=last()"> 
     <xsl:element name="x">, </xsl:element> 
    </xsl:if>  
</xsl:template> 

Мы могли бы даже сделать то же самое с альбомы, устраняющие как xsl:for-each элементы

<xsl:template match="collection"> 
    <xsl:copy> 
     <xsl:apply-templates select="recording"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="recording"> 
    <xsl:copy> 
     <xsl:apply-templates select="(node() | @*) except album"/> 
     <xsl:apply-templates select="album"/> 
    </xsl:copy> 
    <xsl:if test="position()!=last()"> 
     <xsl:element name="x">, </xsl:element> 
    </xsl:if>  
</xsl:template> 

<xsl:template match="album"> 
    <xsl:copy> 
     <xsl:apply-templates select="node() | @*"/> 
    </xsl:copy> 
    <xsl:if test="position()!=last()"> 
     <x>, </x> 
    </xsl:if>  
</xsl:template> 

Все вышеперечисленное копирует текстовые узлы между элементами, которые являются полностью пустыми, что может быть нежелательно. Добавление следующих строк в верхней части таблицы стилей предотвратит что:

<xsl:strip-space elements="*"/> 

Все примеры в этом посте были протестированы с использованием оригинального пример ОП с дополнительным элементом и xsl:strip-space<xsl:output method="xml" indent="yes"/> использованием Saxon-ОН 9.7.0.2 J и произвел результаты, эквивалентные желаемому выходу OP до отступов (элементы x произошли на их собственных линиях).

+0

Спасибо большое за кратким объяснением. Это было очень полезно и принесло желаемый результат. Я знал, что есть какой-то цикл, который мне нужно было обойти с этими двумя шаблонами. – user2093335

0

Что бы я хотел сделать, это создать шаблон, который соответствует recording или album, и если это не первый в своем роде, выведите <x>, </x>.

XML Input

<sample> 
    <collection> 
     <recording> 
      <artist>Radiohead</artist> 
      <album>OK Computer</album> 
     </recording> 
     <recording> 
      <artist>Tori Amos</artist> 
      <album>Boys For Pele</album> 
      <album>To Venus And Back</album> 
     </recording> 
    </collection> 
</sample> 

XSLT 2,0

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

    <xsl:template match="@*|node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="recording|album"> 
    <xsl:variable name="count"> 
     <xsl:number/> 
    </xsl:variable> 
    <xsl:if test="$count > 1"><x>, </x></xsl:if> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

XML Output

<sample> 
    <collection> 
     <recording> 
     <artist>Radiohead</artist> 
     <album>OK Computer</album> 
     </recording> 
     <x>, </x> 
     <recording> 
     <artist>Tori Amos</artist> 
     <album>Boys For Pele</album> 
     <x>, </x> 
     <album>To Venus And Back</album> 
     </recording> 
    </collection> 
</sample>