带有多个祖先的条件的XPath表达式

时间:2011-02-12 22:07:03

标签: c# xml xpath

我正在开发的应用程序接收类似于以下的XML结构:

<Root>
    <Valid>
        <Child name="Child1" />
        <Container>
            <Child name="Child2" />
        </Container>
        <Container>
            <Container>
                <Child name="Child3"/>
                <Child name="Child4"/>
            </Container>
        </Container>
        <Wrapper>
            <Child name="Child5" />
        </Wrapper>
        <Wrapper>
            <Container>
                <Child name="Child19" />
            </Container>
        </Wrapper>
        <Container>
            <Wrapper>
                <Child name="Child6" />
            </Wrapper>
        </Container>
        <Container>
            <Wrapper>
                <Container>
                    <Child name="Child20" />
                </Container>
            </Wrapper>
        </Container>
    </Valid>
    <Invalid>
        <Child name="Child7" />
        <Container>
            <Child name="Child8" />
        </Container>
        <Container>
            <Container>
                <Child name="Child9"/>
                <Child name="Child10"/>
            </Container>
        </Container>
        <Wrapper>
            <Child name="Child11" />
        </Wrapper>
        <Container>
            <Wrapper>
                <Child name="Child12" />
            </Wrapper>
        </Container>
    </Invalid>
</Root>

我需要在以下条件下获取Child元素列表:

  1. 儿童有效祖先的 n 代后代。
  2. 孩子可能 m 容器祖先的后代 o 的后代有效祖先。
  3. Child 元素的有效祖先是 m 元素 m 生成祖先,有效元素作为第一代祖先
  4. 其中m,n,o是自然数。

    我需要编写以下XPath表达式

    Valid/Child
    Valid/Container/Child
    Valid/Container/Container/Child
    Valid/Container/Container/Container/Child
    ...
    

    作为单个 XPath表达式。

    对于提供的示例,XPath表达式仅返回名称元素,其名称属性等于 Child1 Child2 Child3 Child4

    我最接近解决方案的是表达式。

    Valid/Child | Valid//*[self::Container]/Child
    

    但是,这会选择儿童元素,名称属性等于 Child19 Child20

    XPath语法是否支持可选的元素出现或者在前面的示例中为self Child Valid 元素之间的所有祖先设置类似于self的条件?

2 个答案:

答案 0 :(得分:4)

使用

//Child[ancestor::*
          [not(self::Container)][1]
                            [self::Valid]
       ]

在提供的XML文档上评估此XPath表达式时:

<Root>
    <Valid>
        <Child name="Child1" />
        <Container>
            <Child name="Child2" />
        </Container>
        <Container>
            <Container>
                <Child name="Child3"/>
                <Child name="Child4"/>
            </Container>
        </Container>
        <Wrapper>
            <Child name="Child5" />
        </Wrapper>
        <Wrapper>
            <Container>
                <Child name="Child19" />
            </Container>
        </Wrapper>
        <Container>
            <Wrapper>
                <Child name="Child6" />
            </Wrapper>
        </Container>
        <Container>
            <Wrapper>
                <Container>
                    <Child name="Child20" />
                </Container>
            </Wrapper>
        </Container>
    </Valid>
    <Invalid>
        <Child name="Child7" />
        <Container>
            <Child name="Child8" />
        </Container>
        <Container>
            <Container>
                <Child name="Child9"/>
                <Child name="Child10"/>
            </Container>
        </Container>
        <Wrapper>
            <Child name="Child11" />
        </Wrapper>
        <Container>
            <Wrapper>
                <Child name="Child12" />
            </Wrapper>
        </Container>
    </Invalid>
</Root>

确切地选择了所需节点:

<Child name="Child1"/>
<Child name="Child2"/>
<Child name="Child3"/>
<Child name="Child4"/>

<强>解释

表达式:

//Child[ancestor::*
          [not(self::Container)][1]
                            [self::Valid]
       ]

表示

从文档中的所有Child元素中,仅选择那些非Container的第一个祖先为Valid的元素。

答案 1 :(得分:3)

//Valid
 //Child[count(ancestor::Container[ancestor::Valid])
          = count(ancestor::*[ancestor::Valid])]

说明:

//Valid//Child

返回作为Child个节点后代的所有Valid个节点。

count(ancestor::Container[ancestor::Valid]])

返回当前节点(Container)的祖先Child标记的数量,并且它们自己有一个名为Valid的祖先

count(ancestor::*[ancestor::Valid])

返回当前节点(Child)祖先的所有标记的数量,并且它们自己有一个名为Valid的祖先

因此,如果ValidChild之间的所有代码都被称为Container,则两个值相等。

但是,此表达式假定不会有任何嵌套的Valid标记,即{}不会接受/Valid/Valid/Child

更新:再次查看您的xml,这会不会更容易?

//Valid//Child[not(ancestor::Wrapper)]