Как сделать этот конкретный запрос, используя xslt 2.0? - PullRequest
2 голосов
/ 07 сентября 2011

Ниже приводится содержимое моего XML-документа.

<w:document>

    <w:body>
             <w:p pStyle="Heading1">Para1</w:p> 
             <w:p pStyle="Heading2">Para2</w:p> 
             <w:p pStyle="Heading3">Para3</w:p> 
             <w:p pStyle="Heading4">Para4</w:p> 

             <w:p pStyle="Heading1">Para5</w:p> 
             <w:p pStyle="Heading3">Para6</w:p> 
             <w:p pStyle="Heading4">Para7</w:p> 

             <w:p pStyle="Heading2">Para8</w:p> 
             <w:p pStyle="Heading3">Para9</w:p> 

             <w:p pStyle="Heading1">Para10</w:p> 


    </w:body>

</w:document>

Итак, читая каждое <w:p>, я хочу проверить значение его атрибута pStyle Value. Например, в приведенном выше файле первый<w:p> содержит значение этого атрибута как "Heading1" .Итак, для первых <w:p> мне все равно и просто возьми. После этого взято <w:p>,

* Логика 1: * я хочу разделитьзначение атрибута Заголовок1 для извлечения строк после Заголовок .Итак, теперь мы получаем '1' .

Впоследствии, читая следующее <w:p>, применяем те же логика 1 для плеваниятекущее значение атрибута. Итак, в этом случае у нас есть '2' .Теперь я хочу сравнить текущее значение '2' с предыдущим значением '1' .

Logic 2: Если оно меньше предыдущего значения, выберите только текущее значение <w:p>, в противном случае ничего не делайте.

Примените выше Logic 1 и Logic 2 для всех <w:p> узлов.

Итак, в моем случае я хочу выбрать только следующие <w:p> узлы.

Обязательный выбор:

Para1
Para5
Para8
Para10

Надеюсь, вы поняли мою проблему ...

Что я делаю в этой ситуации? ...

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

Спасибо и всего наилучшего, P.SARAVANAN

Ответы [ 2 ]

3 голосов
/ 07 сентября 2011

Я думаю, что это можно сделать в XSLT1.0 простым добавлением к преобразованию идентичности. Вам просто нужно игнорировать узлы w: p , где атрибут pStyle больше или равен предыдущему брату, я думаю.

<xsl:template match="w:p[
       number(substring-after(@pStyle, 'Heading')) 
       &gt;= number(substring-after(preceding-sibling::w:p[1]/@pStyle, 'Heading'))
    ]">
   <!-- Ignore the node -->
</xsl:template>

Вот полное преобразование в этом случае (обратите внимание, что вам, возможно, придется изменить пространство имен)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:w="http://stackoverflow.com/users/452680/saravanan">
   <xsl:output method="xml" indent="yes"/>

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

   <xsl:template match="w:p[number(substring-after(@pStyle, 'Heading')) &gt;= number(substring-after(preceding-sibling::w:p[1]/@pStyle, 'Heading'))]">
       <!-- Ignore the node -->
   </xsl:template>

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

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

<w:document xmlns:w="http://stackoverflow.com/users/452680/saravanan">
   <w:body>
      <w:p pStyle="Heading1">Para1</w:p>
      <w:p pStyle="Heading1">Para5</w:p>
      <w:p pStyle="Heading2">Para8</w:p>
      <w:p pStyle="Heading1">Para10</w:p>
   </w:body>
</w:document>
2 голосов
/ 07 сентября 2011

Просто используйте это выражение XPath 1.0 :

/*/*/w:p[not(substring-after(@pStyle,'Heading')
            >= 
             substring-after(preceding-sibling::*[1]/@pStyle,'Heading')
             )
         ]

Соответствующее выражение XPath 2.0, выбирающее тот же набор элементов: :

 /*/*/w:p[1]
|
 /*/*/w:p[position() ge 2]
             [xs:integer(substring-after(@pStyle,'Heading'))
            lt
              xs:integer(substring-after(preceding-sibling::*[1]/@pStyle,'Heading'))
             ]

Если вы используете XSLT 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="Undefined!!!">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

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

 <xsl:template match=
  "w:p[xs:integer(substring-after(@pStyle,'Heading'))
      ge
       xs:integer(substring-after(preceding-sibling::*[1]/@pStyle,'Heading'))
       ]"/>
</xsl:stylesheet>

при применении к предоставленному документу XML (исправлено, чтобы быть правильно сформированным):

<w:document xmlns:w="Undefined!!!">
    <w:body>
        <w:p pStyle="Heading1">Para1</w:p>
        <w:p pStyle="Heading2">Para2</w:p>
        <w:p pStyle="Heading3">Para3</w:p>
        <w:p pStyle="Heading4">Para4</w:p>
        <w:p pStyle="Heading1">Para5</w:p>
        <w:p pStyle="Heading3">Para6</w:p>
        <w:p pStyle="Heading4">Para7</w:p>
        <w:p pStyle="Heading2">Para8</w:p>
        <w:p pStyle="Heading3">Para9</w:p>
        <w:p pStyle="Heading1">Para10</w:p>
    </w:body>
</w:document>

желаемый, правильный результат выдается :

<w:document xmlns:w="Undefined!!!">
   <w:body>
      <w:p pStyle="Heading1">Para1</w:p>
      <w:p pStyle="Heading1">Para5</w:p>
      <w:p pStyle="Heading2">Para8</w:p>
      <w:p pStyle="Heading1">Para10</w:p>
   </w:body>
</w:document>

Соответствующее решение XSLT 1.0 с переопределением правила идентификации немного проще из-за отсутствия строгой типизации в XPath 1.0:

<xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:w="Undefined!!!">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>

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

     <xsl:template match=
      "w:p[substring-after(@pStyle,'Heading')
          >=
          substring-after(preceding-sibling::*[1]/@pStyle,'Heading')
           ]"/>
</xsl:stylesheet>

Или вы можете просто использовать выражения в начале этого решения :

XSLT 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="Undefined!!!" exclude-result-prefixes="xs">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
<w:document xmlns:w="Undefined!!!">
    <w:body>
     <xsl:copy-of select=
    "/*/*/w:p[1]
      |
       /*/*/w:p[position() ge 2]
                 [xs:integer(substring-after(@pStyle,'Heading'))
               lt
                xs:integer(substring-after(preceding-sibling::*[1]/@pStyle,'Heading'))
               ]
      "/>
    </w:body>
 </w:document>
 </xsl:template>
</xsl:stylesheet>

XSLT 1.0:

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

 <xsl:template match="/">
<w:document xmlns:w="Undefined!!!">
    <w:body>
     <xsl:copy-of select=
    "/*/*/w:p
          [not(substring-after(@pStyle,'Heading')
              >=
               substring-after(preceding-sibling::*[1]/@pStyle,'Heading')
               )
          ]
      "/>
    </w:body>
 </w:document>
 </xsl:template>
</xsl:stylesheet>

Все три вышеупомянутых преобразования XSLT дают требуемый, правильный результат .

...