在XPath中,如何在锚元素之前和之后选择以下兄弟节点组?

时间:2015-09-23 05:55:55

标签: xml xpath xpath-2.0

我有一个xml文档,如下,

<sec>
    <p type="Running">aa</p>
    <p type="heading 1">bb</p>
    <p type="body">cc</p>
    <p type="body">dd</p>
    <p type="Running">ee</p>
    <p type="Body">ff</p>
    <p type="heading">gg</p>
    <p type="body">hh</p>
    <p type="body">ii</p>
    <p type="Running">jj</p>
    <p type="list">kk</p>
    <p type="list">ll</p>
    <p type="list">mm</p>
    <p type="list">nn</p>
</sec>

使用xpath我需要选择来自<p> <p>节点的连续跟随兄弟,其节点值为Running

在上面的例子中

    <p type="heading 1">bb</p>
    <p type="body">cc</p>
    <p type="body">dd</p>

    <p type="Body">ff</p>
    <p type="heading">gg</p>
    <p type="body">hh</p>
    <p type="body">ii</p>

    <p type="list">kk</p>
    <p type="list">ll</p>
    <p type="list">mm</p>
    <p type="list">nn</p>
应该选择

节点组。

如何编写XPath查询来选择这些节点?

XPath version - 2.0

4 个答案:

答案 0 :(得分:2)

这个问题目前有三个答案,但我认为他们中的任何一个都没有回答这个问题。

在XPath 2.0中,一切都是序列。如果选择一组节点,则在XPath 1.0中调用了一个&#34;节点集&#34;,在XPath 2.0中它是一个&#34;节点序列&#34;。序列的一个属性是它们不能嵌套:(1, (2, 3), 4)(1, 2, 3, 4)相同。

您需要一个选择语句集的select语句,这意味着您希望对每个集合执行某些操作。合乎逻辑的做法如下:

for $r in sec/p[@type = 'Running']
return $r
    /following-sibling::p
    [not(@type = 'Running')]
    [. << following-sibling::p[@type = 'Running'][1]]

这是一个相当复杂的表达方式。虽然它会在内部选择您所追踪的子集,但由于序列规范化,净效应是一个选择等于sec/p[not(@type = 'Running')]的单个序列。

在XPath 2.0中,不可能以不同的方式执行此操作,因此自然要做的就是使用主机语言(如XSLT或XQuery)来选择@type = 'Running'节点,并在每次点击时选择(并做一些事情)以下兄弟姐妹将到下一个@type = 'Running'

<xsl:template match="sec">
    <xsl:apply-templates select="p[@type = 'Running']" />
</xsl:template>

<xsl:template match="p">
    <!-- do something before the group -->
    <xsl:apply-templates select="following-sibling::p[following-sibling::p[@type = 'Running'] >> .]" mode="group"/>
    <!-- do something after the group -->
</xsl:template>

<xsl:template match="p" mode="group">
   <!-- do something with items in the group -->
</xsl:template>

在这里使用xsl:for-each-group可能更容易,这是为了这种事情。

答案 1 :(得分:1)

我不知道XPath 2,但是使用XPath 1和一些高级编程,你可以使用这种XPath表达式,计算类型=“Running”之前的兄弟姐妹:

//p[not(@type="Running")
    and count(preceding-sibling::p[@type="Running"])=1]
                                                     ^
                                                     |
                                                1 then 2 then 3

答案 2 :(得分:0)

在Xpath下面选择除type ='Running'

之外的所有内容
/sec/p[not(@type='Running')]

答案 3 :(得分:-2)

这应该对你有帮助 -

var j = new List<string>();
var t = new XmlDocument();
t.Load(new StreamReader("xmlPath"));
var type = t.GetElementsByTagName("p");

for (var i = 0; i < type.Count; i++)
{
    if (((XmlNode)type[i]).Attributes[0].Value != "Running")
    {
       j.Add(((XmlNode)type[i]).OuterXml);
    }
}