2012-06-03 5 views
3

Я искал преобразование узла в зависимости от количества элементов. т. е. 5, затем закройте узел и снова откроем новый. пример нижеИспользование XSLT для преобразования XML на основе количества узлов

<root> 
    <branch> 
    <foo>bar</foo> 
    <foo>bar2</foo> 
    <foo>bar3</foo> 
    <foo>bar4</foo> 
    <foo>bar5</foo> 
    <foo>bar6</foo> 
    <foo>bar7</foo> 
    </branch> 
<root> 

должны стать

<root> 
    <branch> 
    <foo>bar</foo> 
    <foo>bar2</foo> 
    <foo>bar3</foo> 
    <foo>bar4</foo> 
    <foo>bar5</foo> 
    <branch> 
    </branch> 
    <foo>bar6</foo> 
    <foo>bar7</foo> 
    </branch> 
<root> 

Пожалуйста, помогите о том, как это может быть сделано в XSLT.

ответ

4

I. Это XSLT-преобразование 1.0:

<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="/*"> 
    <root> 
    <xsl:apply-templates/> 
    </root> 
</xsl:template> 

<xsl:template match="foo[position() mod 5 = 1]"> 
    <branch> 
    <xsl:copy-of select= 
    ". | following-sibling::*[not(position() > 4)]"/> 
    </branch> 
</xsl:template> 
<xsl:template match="text()"/> 
</xsl:stylesheet> 

при нанесении на прилагаемом документе XML (с поправкой на хорошо сформированные):

<root> 
    <branch> 
     <foo>bar</foo> 
     <foo>bar2</foo> 
     <foo>bar3</foo> 
     <foo>bar4</foo> 
     <foo>bar5</foo> 
     <foo>bar6</foo> 
     <foo>bar7</foo> 
    </branch> 
</root> 

производит нужное, правильное результат:

<root> 
    <branch> 
     <foo>bar</foo> 
     <foo>bar2</foo> 
     <foo>bar3</foo> 
     <foo>bar4</foo> 
     <foo>bar5</foo> 
    </branch> 
    <branch> 
     <foo>bar6</foo> 
     <foo>bar7</foo> 
    </branch> 
</root> 

Объяснение:

Это случай «позиционной группировки», где каждый начальный элемент группы является первым из 5-кортежа (так что его положение удовлетворяет: position() mod 5 = 1.


II. XSLT 2.0 Решение:

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

<xsl:template match="/*"> 
    <root> 
    <xsl:for-each-group select="*/*" 
     group-adjacent="(position() -1) idiv 5"> 
      <branch> 
      <xsl:sequence select="current-group()"/> 
      </branch> 
    </xsl:for-each-group> 
    </root> 
</xsl:template> 
</xsl:stylesheet> 

когда это XSLT-преобразование 2.0 применяется на том же самом документе XML (выше), то же хотел, правильный результат получается.

Объяснение:

Правильное использование <xsl:for-each-group> инструкции XSLT 2.0 с атрибутом group-adjacent и функции current-group().

0

В XSLT такой операции нет как «открытие» или «закрытие» узла. У вас неправильное представление о модели обработки, и пока вы не получите ее прямо в голове, вам будет трудно решить эту проблему. В частности, вы не поняли, что XSLT (концептуально) создает дерево результатов, а не файл, содержащий лексический XML с начальными и конечными тегами. Вам нужно создать один узел в дереве результатов, соответствующий каждой группе из пяти узлов в исходном дереве (или, эквивалентно, создать один узел в результирующем дереве, соответствующем каждому узлу в дереве источников, положение которого является множественным из 5).

Решение Dimitre совершенно правильно, но я лично считаю, что дать вам рабочее решение, не объясняя, где вы ошибетесь в своем мышлении, - это не лучший способ ответить на ваш вопрос.

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