如何使用xslt 2.0进行此特定查询?

时间:2011-09-07 07:15:01

标签: xml xpath xslt xpath-2.0

下面提到的内容是我的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'进行比较。

逻辑2: 如果它小于之前的值,则只选择当前的<w:p>,否则,不要做任何事情。

为所有<w:p>节点应用上述 逻辑1和逻辑2

所以,就我而言,我只想选择以下<w:p>个节点。

  

必需的选择是:

Para1
Para5
Para8
Para10

希望你明白我的问题......

我为这种情况做了什么?...

请指导我摆脱这个问题...

谢谢&amp;问候, P.SARAVANAN

2 个答案:

答案 0 :(得分:3)

我认为这可以通过对身份转换的简单补充在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>

答案 1 :(得分:2)

只需使用此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,则可以按以下方式覆盖identity rule/template

<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>

由于XPath 1.0缺少强类型,相应的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: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转换都会产生想要的正确结果