2014-01-31 3 views
0

Я понимаю, что использование <xsl:template /> и <xsl:for-each> почти служат той же цели и <xsl:for-each > является своего рода «анонимного шаблона инлайн».XSLT 1.0 Использование позиции() в <XSL: для-каждого> и <XSL: шаблон>

Вопрос: Однако, учитывая приведенный ниже сценарий, я думаю, что использование <xsl:for-each> является более уместным. Пожалуйста, подтвердите мое понимание, или есть способ, которым выход может быть достигнут через <xsl:template>?

Входной XML:

<?xml version="1.0" encoding="UTF-8"?> 
<books> 
    <book.child.1> 
     <title>charithram</title> 
     <author>sarika</author> 
    </book.child.1> 
    <book.child.2> 
     <title>doublebell</title> 
     <author>psudarsanan</author> 
    </book.child.2> 
</books> 

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

<?xml version="1.0" encoding="UTF-8"?> 
<books> 
    <book id="book1"> 
     <title>charithram</title> 
     <author>sarika</author> 
    </book> 
    <book id="book2"> 
     <title>doublebell</title> 
     <author>psudarsanan</author> 
    </book> 
</books> 

XSLT1 [используя <xsl:for-each >] - Это дает ожидаемый результат

<?xml version="1.0" encoding="ISO-8859-1"?> 
<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:template match="/"> 
     <newbooks> 
      <xsl:for-each select="books/*"> 
      <newbook id="book{position()}"> 
       <title><xsl:value-of select="title" /></title> 
       <author> <xsl:value-of select="author" /></author> 
      </newbook> 
      </xsl:for-each> 
      </newbooks> 
</xsl:template> 
</xsl:stylesheet> 

XSLT2 [используя <xsl:template >]

<?xml version="1.0" encoding="ISO-8859-1"?> 
<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:template match="/"> 
    <newbooks> 
       <xsl:apply-templates/>  
    </newbooks> 
</xsl:template> 
<xsl:template match="books/*" > 
    <newbook id="book{position()}"> 
     <title><xsl:value-of select="title" /></title> 
     <author> <xsl:value-of select="author" /></author> 
    </newbook> 
</xsl:template> 
</xsl:stylesheet> 

Это не дает ожидаемого результата, Вместо этого, выход полученный,

<?xml version="1.0" encoding="UTF-8"?> 
    <newbooks> 
     <newbook id="book2"> 
      <title>charithram</title> 
      <author>sarika</author> 
     </newbook> 
     <newbook id="book4"> 
      <title>doublebell</title> 
      <author>psudarsanan</author> 
     </newbook> 
    </newbooks> 

Единственная причина, я могу думать о получении 2 и 4, может быть позицией узла id внутри контекста.
«Функция position() возвращает позицию контекстного узла в выбранном наборе узлов». В соответствии с этим определением он работает в случае for-each, так как контекст представляет собой элемент <book>. Но почему это не применимо в случае шаблона?

Я также попытался с <xsl:number>, но не может сделать это, чтобы работать, как ожидалось

<xsl:template match="/"> 
     <newbooks> 
        <xsl:apply-templates/>  
     </newbooks> 
    </xsl:template> 
    <xsl:template match="books/*" > 
     <newbook > 
      <xsl:attribute name="id"> 
       <xsl:text>book</xsl:text><xsl:number/> 
      </xsl:attribute> 
      <title><xsl:value-of select="title" /></title> 
      <author> <xsl:value-of select="author" /></author> 
     </newbook> 
    </xsl:template> 

Я получаю выход book1, Книга1 [не увеличивающиеся]

Пожалуйста, помогите.

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

ответ

1

Я думаю, что ваше понимание различий немного ошибочно, но это не проблема здесь, так как ваш <xsl:apply-templates /> по существу делает то же самое, что и <xsl:for-each>.

Но: Вы имеете большое различие в селекторах, которые вы используете в двух фрагментах кода. В вашем первом примере используется <xsl:for-each select="books/*">, который создает набор узлов с мощностью 2, пронумерованный, неудивительно, 1 и 2. В вашем втором фрагменте кода используется <xsl:apply-templates />, что является сокращением для <xsl:apply-templates select="node()"> и создает узел с множеством мощностей пять (!), с узлами 1, 3 и 5 являются текстовыми узлами (которые содержат только пробелы), а узлы 2 и 4 - те, которые вы на самом деле хотите настроить.

Решение? Добавьте свой селектор в элемент apply-templates, как в <xsl:apply-templates select="books/*" />.

EDIT Итак, почему узел, указанный во втором случае, большой? Поскольку он собирает все дочерние узлы books, а способ работы XML состоит в том, что он включает не только элементы - он также включает в себя текстовые узлы (вы хотите, чтобы ваши <title> и <author> имели дочерний элемент текстового узла) - , включая текстовые узлы, которые из-за вашего отступа,, который содержит только такие элементы, как конец строки и пробелы и/или вкладки, все вместе называемые пробелами. Попробуйте исходный второй код для этих входных вариантов:

<?xml version="1.0" encoding="UTF-8"?> 
<books> 
    <book.child.1> 
     <title>charithram</title> 
     <author>sarika</author> 
    </book.child.1> 
    <book.child.2> 
     <title>doublebell</title> 
     <author>psudarsanan</author> 
    </book.child.2> 
</books> 

.

<?xml version="1.0" encoding="UTF-8"?> 
<books><book.child.1> 
     <title>charithram</title> 
     <author>sarika</author> 
    </book.child.1> 
    <book.child.2> 
     <title>doublebell</title> 
     <author>psudarsanan</author> 
    </book.child.2> 
</books> 

.

<?xml version="1.0" encoding="UTF-8"?> 
<books><book.child.1> 
     <title>charithram</title> 
     <author>sarika</author> 
    </book.child.1><book.child.2> 
     <title>doublebell</title> 
     <author>psudarsanan</author> 
    </book.child.2> 
</books> 

Также обратите внимание, что элементы и текст не являются единственными типами узлов:

<?xml version="1.0" encoding="UTF-8"?> 
<books> 
    <!-- first book --> 
    <book.child.1> 
     <title>charithram</title> 
     <author>sarika</author> 
    </book.child.1> 
    <!-- second book --> 
    <book.child.2> 
     <title>doublebell</title> 
     <author>psudarsanan</author> 
    </book.child.2> 
</books> 

Если у вас шаблоны, соответствующие их использования (например, <xsl:template match='text()'> или может быть что-то более конкретно), вы найдете соответствующий выход там. XSLT просто по умолчанию игнорирует непревзойденные узлы в шаблонах применений.

+0

Спасибо, Кристофер, я понимаю проблему и попробовал добавить селектор для применения шаблонов, получив ожидаемый результат. Однако, что касается мощности, for-each создает узел с множеством мощности два. Но я не понимаю, как создает набор узлов с мощностью пять, а узлы 2 и 4 - те, которые я нацеливаю. Не могли бы вы объяснить, что – spiderman

+0

Ницца, я понимаю, как мы получили мощность в пять [может быть любое число, основанное на изменении ввода), и i попытался использовать различные варианты ввода, чтобы увидеть разные позиции. Спасибо за объяснение «как это работает», а не простой ответ на OP. Оценил. – spiderman

Смежные вопросы