как мне выбрать следующих братьев и сестер моего текущего элемента процесса, пока он не удовлетворит условие для каждого с помощью xslt 2.0?

Это мой XML-документ (небольшой фрагмент).

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">

<w:body>

    <w:p> <!-- Current Node -->
        <w:pPr>
            <w:pStyle w:val="Heading1"/>
        </w:pPr>

        <w:r>
            <w:t>
                 Paragraph1
            </w:t>
        </w:r>
    </w:p>

    <w:tbl>
        <w:t>table info
        </w:t>
    </w:tbl>

    <w:p>
        <w:pPr>
        </w:pPr>
        <w:r>
            <w:t>
                 Paragraph2
            </w:t>
        </w:r>
    </w:p>

    <w:p>
        <w:pPr>
        </w:pPr>
        <w:r>
            <w:t>
                 Paragraph3
            </w:t>
        </w:r>
    </w:p>

    <w:p>
        <w:pPr>
            <w:pStyle w:val="Heading1"/>
        </w:pPr>

        <w:r>
            <w:t>
                 Paragraph4
            </w:t>
        </w:r>
    </w:p>

    <w:p>
        <w:pPr>
        </w:pPr>
        <w:r>
            <w:t>
                 Paragraph5
            </w:t>
        </w:r>
    </w:p>

    <w:p>
        <w:pPr>
            <w:pStyle w:val="Heading1"/>
        </w:pPr>

        <w:r>
            <w:t>
                 Paragraph6
            </w:t>
        </w:r>
    </w:p>

</w:body>
</w:document>

Здесь я хочу выбрать следующего брата первого<w:p>, используя оператор for-each, пока он не встретит следующий<w:p>, имеющий его <w:pPr><w:pStyle w:val="Heading1"/></w:pPr>.

например, для первого<w:p> я хочу выбрать только следующие три следующих брата и сестры (т. е. абзац 2, абзац 3 и включая информацию о таблице).

Тот же случай для 4th<w:p>, если это текущий узел. Затем я хочу выбрать только 5-й <w:p>.

Я не знаю, как указать это условие для каждого. Итак, можете ли вы помочь мне получить это...

Мой требуемый вывод похож на:

<Document>
   <Heading1>
        <paragraph>paragrap1</paragraph>
        <paragraph>table info</paragraph>
        <paragraph>paragrap2</paragraph>
        <paragraph>paragrap3</paragraph>
   </Heading1>
   <Heading1>
        <paragraph>paragrap4</paragraph>
        <paragraph>paragrap5</paragraph>
   </Heading1>
   <Heading1>
        <paragraph>paragrap6</paragraph>
   </Heading1>
</Document>

person Saravanan    schedule 28.12.2011    source источник


Ответы (4)


Здесь я хочу выбрать следующего брата первого <w:p> с помощью оператора for-each, пока он не встретит следующий <w:p>, имеющий свой <w:pPr><w:pStyle w:val="Heading1"/></w:pPr>.

Это преобразование XSLT 2.0 демонстрирует один из способов его выполнения с помощью оператора XPAth 2.0 >>:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
  exclude-result-prefixes="w xs">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="*/w:p[1]">

  <xsl:variable name="vNextWP" select=
  "following-sibling::w:p
    [w:pPr/w:pStyle/@w:val='Heading1']
     [1]
  "/>

  <xsl:copy-of select=
  "following-sibling::w:p[$vNextWP >> .]"/>
 </xsl:template>

 <xsl:template match="text()"/>
</xsl:stylesheet>

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

<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">

    <w:body>

        <w:p> <!-- Current Node -->
            <w:pPr>
                <w:pStyle w:val="Heading1"/>
            </w:pPr>

            <w:r>
                <w:t>
                     Paragraph1
                </w:t>
            </w:r>
        </w:p>

        <w:p>
            <w:pPr>
            </w:pPr>
            <w:r>
                <w:t>
                     Paragraph2
                </w:t>
            </w:r>
        </w:p>

        <w:p>
            <w:pPr>
            </w:pPr>
            <w:r>
                <w:t>
                     Paragraph3
                </w:t>
            </w:r>
        </w:p>

        <w:p>
            <w:pPr>
                <w:pStyle w:val="Heading1"/>
            </w:pPr>

            <w:r>
                <w:t>
                     Paragraph4
                </w:t>
            </w:r>
        </w:p>

        <w:p>
            <w:pPr>
            </w:pPr>
            <w:r>
                <w:t>
                     Paragraph5
                </w:t>
            </w:r>
        </w:p>

        <w:p>
            <w:pPr>
                <w:pStyle w:val="Heading1"/>
            </w:pPr>

            <w:r>
                <w:t>
                     Paragraph6
                </w:t>
            </w:r>
        </w:p>

    </w:body>
</w:document>

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

<w:p xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
            <w:pPr>
            </w:pPr>
            <w:r>
                <w:t>
                     Paragraph2
                </w:t>
            </w:r>
        </w:p>
<w:p xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
            <w:pPr>
            </w:pPr>
            <w:r>
                <w:t>
                     Paragraph3
                </w:t>
            </w:r>
        </w:p>

Обновление: OP разъяснил, какой результат преобразования требуется (группировка), поэтому вот:

И. Решение XSLT 1.0:

 <xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
 exclude-result-prefixes="w">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kFollowing"
  match="w:p[not(w:pPr/w:pStyle/@w:val = 'Heading1')]
        |
         w:tbl"
  use="generate-id(preceding-sibling::w:p
           [w:pPr/w:pStyle/@w:val = 'Heading1'][1])
  "/>

 <xsl:template match="/*">
  <Document>
   <xsl:apply-templates/>
  </Document>
 </xsl:template>

 <xsl:template match=
 "w:p[w:pPr/w:pStyle/@w:val = 'Heading1']">

  <Heading1>
   <xsl:apply-templates mode="inGroup" select=
    ". | key('kFollowing', generate-id())"/>
   </Heading1>
 </xsl:template>

 <xsl:template match="*" mode="inGroup">
  <paragraph>
    <xsl:value-of select="normalize-space(.//w:t)"/>
  </paragraph>
 </xsl:template>

 <xsl:template match="w:body/*" priority="-1"/>
</xsl:stylesheet>

когда это преобразование применяется к вновь предоставленному XML-документу:

<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">

<w:body>

    <w:p> <!-- Current Node -->
        <w:pPr>
            <w:pStyle w:val="Heading1"/>
        </w:pPr>

        <w:r>
            <w:t>
                 Paragraph1
            </w:t>
        </w:r>
    </w:p>

    <w:tbl>
        <w:t>table info
        </w:t>
    </w:tbl>

    <w:p>
        <w:pPr>
        </w:pPr>
        <w:r>
            <w:t>
                 Paragraph2
            </w:t>
        </w:r>
    </w:p>

    <w:p>
        <w:pPr>
        </w:pPr>
        <w:r>
            <w:t>
                 Paragraph3
            </w:t>
        </w:r>
    </w:p>

    <w:p>
        <w:pPr>
            <w:pStyle w:val="Heading1"/>
        </w:pPr>

        <w:r>
            <w:t>
                 Paragraph4
            </w:t>
        </w:r>
    </w:p>

    <w:p>
        <w:pPr>
        </w:pPr>
        <w:r>
            <w:t>
                 Paragraph5
            </w:t>
        </w:r>
    </w:p>

    <w:p>
        <w:pPr>
            <w:pStyle w:val="Heading1"/>
        </w:pPr>

        <w:r>
            <w:t>
                 Paragraph6
            </w:t>
        </w:r>
    </w:p>

</w:body>
</w:document>

получен желаемый правильный результат:

<Document>
   <Heading1>
      <paragraph>Paragraph1</paragraph>
      <paragraph>table info</paragraph>
      <paragraph>Paragraph2</paragraph>
      <paragraph>Paragraph3</paragraph>
   </Heading1>
   <Heading1>
      <paragraph>Paragraph4</paragraph>
      <paragraph>Paragraph5</paragraph>
   </Heading1>
   <Heading1>
      <paragraph>Paragraph6</paragraph>
   </Heading1>
</Document>

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

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
  exclude-result-prefixes="w"   >
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/*">
     <Document>
      <xsl:for-each-group
      select="*/*"
      group-starting-with="w:p[w:pPr/w:pStyle/@w:val = 'Heading1']">
       <Heading1>
         <xsl:for-each select="current-group()//w:t">
           <paragraph>
             <xsl:sequence select="normalize-space(.)"/>
           </paragraph>
         </xsl:for-each>
       </Heading1>
      </xsl:for-each-group>
     </Document>
 </xsl:template>
</xsl:stylesheet>

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

<Document>
   <Heading1>
      <paragraph>Paragraph1</paragraph>
      <paragraph>table info</paragraph>
      <paragraph>Paragraph2</paragraph>
      <paragraph>Paragraph3</paragraph>
   </Heading1>
   <Heading1>
      <paragraph>Paragraph4</paragraph>
      <paragraph>Paragraph5</paragraph>
   </Heading1>
   <Heading1>
      <paragraph>Paragraph6</paragraph>
   </Heading1>
</Document>
person Dimitre Novatchev    schedule 28.12.2011
comment
Спасибо за ваш пост. Предположим, если между пунктом 2 и пунктом 3 есть элемент, то он выбран или нет... Например, ‹w:tbl›‹w:t›table info‹/w:t›‹/w: tbl› добавляется между этими ‹w:p›'s(paragraph2,paragraph3) - person Saravanan; 28.12.2011
comment
: Извините, что упоминаю мой требуемый формат. Пожалуйста, посмотрите мой обновленный требуемый формат. - person Saravanan; 28.12.2011
comment
@Saravanan, примите это во внимание для моего кода выше (тот, что с примером CDATA), если вы хотите взглянуть ... - person First Zero; 28.12.2011
comment
@FirstZero: конечно, я посмотрю - person Saravanan; 29.12.2011
comment
@Saravanan: Хорошо, я обновил свой ответ двумя решениями (XSLT 1.0 и XSLT 2.0) для вашего недавно обновленного вопроса. Развлекайся. - person Dimitre Novatchev; 29.12.2011
comment
@DimitreNovatchev Элегантные решения! :) - person First Zero; 29.12.2011

Этого можно добиться (в XSLT 1.0) с помощью ключа для группировки элементов x:t по первому предыдущему элементу w:pPr/w:pStyle.

<xsl:key 
   name="text" 
   match="w:t" 
   use="generate-id(preceding::w:pPr[w:pStyle][1]/w:pStyle)" />

Затем для любого (или всех) определенного элемента w:pStyle вы можете получить все связанные текстовые элементы, например

<xsl:apply-templates select="key('text', generate-id())" />

Итак, следующий XSLT....

<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" 
  exclude-result-prefixes="w">

   <xsl:output method="xml" indent="yes" />

   <xsl:key 
      name="text" 
      match="w:t" 
      use="generate-id(preceding::w:pPr[w:pStyle][1]/w:pStyle)" />

   <xsl:template match="/">
      <Document>
         <xsl:apply-templates select="//w:pPr/w:pStyle" />
      </Document>
   </xsl:template>

   <xsl:template match="w:pStyle">
      <xsl:element name="{@w:val}">
         <xsl:apply-templates select="key('text', generate-id())" />
      </xsl:element>
   </xsl:template>

   <xsl:template match="w:t">
      <paragraph><xsl:value-of select="normalize-space(.)" /></paragraph>
   </xsl:template>
</xsl:stylesheet>

При применении к вашему образцу входного XML-документа выводится следующее:

<Document>
   <Heading1>
      <paragraph>Paragraph1</paragraph>
      <paragraph>table info</paragraph>
      <paragraph>Paragraph2</paragraph>
      <paragraph>Paragraph3</paragraph>
   </Heading1>
   <Heading1>
      <paragraph>Paragraph4</paragraph>
      <paragraph>Paragraph5</paragraph>
   </Heading1>
   <Heading1>
      <paragraph>Paragraph6</paragraph>
   </Heading1>
</Document>
person Tim C    schedule 28.12.2011

Я подозреваю, что вы хотите выполнить позиционную группировку, группировать братьев и сестер и начинать или заканчивать группу всякий раз, когда выполняется какое-либо условие. Если это описывает проблему, рассмотрите возможность использования xsl:for-each-group с атрибутом group-starting-with или group-ending-with.

person Michael Kay    schedule 28.12.2011

Есть альтернативный способ и немного схитрить с помощью CDATA, вот мой вариант

1/Для первого и последнего элемента position() я использую CDATA для открытия и закрытия тега <Heading1>,

2/Если вы находитесь между первым и последним, а элемент w:p имеет Heading1, я уверен, что один тег Heading1 должен быть закрыт, а другой открыт.

3 / Если ничего не совпадает, вы должны быть абзацем.

  <xsl:for-each select="//w:body/*">
        <xsl:choose>
            <!-- If you are the first one, create the heading element -->
            <xsl:when test="position() = 1">
                <xsl:text disable-output-escaping="yes">
                <![CDATA[
                <Heading1>
                ]]>
                </xsl:text>
                <paragraph>
                    <xsl:value-of select=".//w:t" />
                </paragraph>
            </xsl:when>
            <!-- If you are last close the element -->
            <xsl:when test="position() = last()">
                <paragraph>
                    <xsl:value-of select=".//w:t" />
                </paragraph>
                <xsl:text disable-output-escaping="yes">
                <![CDATA[
                </Heading1>
                ]]>
                </xsl:text>
            </xsl:when>
            <!-- If you are in-between first and last open and close -->
            <xsl:when test="w:pPr/w:pStyle/@w:val = 'Heading1'">
                <xsl:text disable-output-escaping="yes">
                <![CDATA[
                </Heading1><Heading1>
                ]]>
                </xsl:text>
                <!-- Nothing matches that means we need to pick up the paragraph -->
                <paragraph>
                    <xsl:value-of select=".//w:t" />
                </paragraph>
            </xsl:when>
            <xsl:otherwise>
                <!-- Nothing matches that means we need to pick up the paragraph -->
                <paragraph>
                    <xsl:value-of select=".//w:t" />
                </paragraph>
            </xsl:otherwise>
            </xsl:choose>
    </xsl:for-each>

Что дает результат (я создал несколько узлов в XML для тестирования)

<Heading1>
    <paragraph> Paragraph1 </paragraph>
    <paragraph>table info </paragraph>
    <paragraph> Paragraph2 </paragraph>
    <paragraph> Paragraph3 </paragraph>

</Heading1>
<Heading1>
    <paragraph> Paragraph1 </paragraph>
    <paragraph>table info </paragraph>
    <paragraph> Paragraph2 </paragraph>
    <paragraph> Paragraph3 </paragraph>
</Heading1>
person First Zero    schedule 28.12.2011