XPath 2.0 - 选择2个元素之间的所有节点

时间:2012-10-29 09:37:01

标签: xml xslt xpath xslt-2.0 xpath-2.0

我有以下XML文件:

<document>
  <article>
    <head>headline 1</head>
    <text>
      <paragraph>foo</paragraph>
      <paragraph>bar</paragraph>
    </text>
    <date>
      <day>10</day>
      <month>05</month>
      <year>2002</year>
    </date>
    <source>some text</source>
    <portal>ABC</portal>
    <ID number="1"/>
  </article>
  <article>
    <head>headline 2</head>
    <text>
      <paragraph>lorem ipsum</paragraph>
    </text>
    <date>
      <day>10</day>
      <month>05</month>
      <year>2002</year>
    </date>
    <source>another source</source>
    <portal>DEF</portal>
    <ID number="2"/>
  </article>
</document>

现在我想返回头节点之后出现的每篇文章的所有节点 在门户节点之前。因此,我正在研究XPath 2节点比较(&lt;&lt;&gt;&gt;运算符)。

到目前为止我所拥有的是以下内容,它返回空:

<xsl:template match="/">
  <xsl:copy-of select="/document/article/head/following-sibling::*[. << ./article/portal]"/>
</xsl:template>

如何修复xpath查询?

4 个答案:

答案 0 :(得分:2)

一个简单的XPath 1.0表达式适用于这种情况:

/document/article/head/following-sibling::*[following-sibling::portal]

答案 1 :(得分:2)

使用

/*/*/node()[. >> ../head and ../portal >> .]

这是一个完整的转型

<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="/">
     <xsl:sequence select="/*/*/node()[. >> ../head and ../portal >> .]"/>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<document>
    <article>
        <head>headline 1</head>
        <text>
            <paragraph>foo</paragraph>
            <paragraph>bar</paragraph>
        </text>
        <date>
            <day>10</day>
            <month>05</month>
            <year>2002</year>
        </date>
        <source>some text</source>
        <portal>ABC</portal>
        <ID number="1"/>
    </article>
    <article>
        <head>headline 2</head>
        <text>
            <paragraph>lorem ipsum</paragraph>
        </text>
        <date>
            <day>10</day>
            <month>05</month>
            <year>2002</year>
        </date>
        <source>another source</source>
        <portal>DEF</portal>
        <ID number="2"/>
    </article>
</document>

产生了想要的正确结果

    <text>
        <paragraph>foo</paragraph>
        <paragraph>bar</paragraph>
    </text>
    <date>
        <day>10</day>
        <month>05</month>
        <year>2002</year>
    </date>
    <source>some text</source>

    <text>
        <paragraph>lorem ipsum</paragraph>
    </text>
    <date>
        <day>10</day>
        <month>05</month>
        <year>2002</year>
    </date>
    <source>another source</source>

<强>更新

在评论中,Roman Pekar指定了一项新要求:他希望获得每篇文章的第一个 headportal之间的所有此类节点。

当然,这很简单 - 只需将上述表达更改为:

/*/*/node()[. >> ../head[1] and ../portal[1] >> .]

答案 2 :(得分:2)

我经常在SQL Server中使用xml,所以当我看到Dimitre Novatchev回答时,我已经在SSMS中尝试过了。它没有用,因为SQL服务器中的XQuery实现是a statically typed language and does static type checking,所以我试图找到这个表达式的SQL Server形式。这是:

/document/article/*[. >> ../head[1] and . << ../portal[1]]

完整查询将是

declare @Data xml

select @Data = '
<document>
  <article>
    <head>headline 1</head>
    <text>
      <paragraph>foo</paragraph>
      <paragraph>bar</paragraph>
    </text>
    <date>
      <day>10</day>
      <month>05</month>
      <year>2002</year>
    </date>
    <source>some text</source>
    <portal>ABC</portal>
    <ID number="1"/>
  </article>
  <article>
    <head>headline 2</head>
    <text>
      <paragraph>lorem ipsum</paragraph>
    </text>
    <date>
      <day>10</day>
      <month>05</month>
      <year>2002</year>
    </date>
    <source>another source</source>
    <portal>DEF</portal>
    <ID number="2"/>
  </article>
</document>
'

select @Data.query('/document/article/*[. >> ../head[1] and . << ../portal[1]]')

答案 3 :(得分:1)

我认为您有一个很好的建议,根本不使用<<,但如果您想使用它,我认为<xsl:copy-of select="/document/article/head/following-sibling::*[. << parent::article/portal]"/>会修复您的尝试。