C# 具有多个祖先条件的XPath表达式

C# 具有多个祖先条件的XPath表达式,c#,xml,xpath,C#,Xml,Xpath,我正在开发的应用程序接收类似于以下内容的XML结构: <Root> <Valid> <Child name="Child1" /> <Container> <Child name="Child2" /> </Container> <Container> <Container>

我正在开发的应用程序接收类似于以下内容的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>
作为单个XPath表达式

Valid/Child | Valid//*[self::Container]/Child
例如,XPath表达式将只返回Child元素,这些元素的name属性等于Child1Child2Child3Child4

我得到的最接近的解决方案是下面的表达式

Valid/Child | Valid//*[self::Container]/Child
但是,这将选择属性为Child19Child20Child元素

XPath语法是否支持对子元素有效元素之间的所有祖先可选地出现元素或设置类似于上例中self的条件

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

//Valid//Child
返回所有
子节点
节点,这些节点是
有效
节点的后代

count(ancestor::Container[ancestor::Valid]])
返回当前节点(
Child
)的祖先的
Container
标记的数量,这些标记本身有一个名为
Valid

count(ancestor::*[ancestor::Valid])
返回当前节点(
Child
)的所有祖先标记的数量,这些标记本身具有名为
Valid

count(ancestor::*[ancestor::Valid])
因此,只有当
Valid
Child
之间的所有标记都被称为
Container
时,这两个值才相等

但是,此表达式假定不存在任何嵌套的
有效的
标记,即它不接受
/Valid/Valid/Child

更新:再次查看xml,这不是更容易吗

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

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

从文档中的所有
子元素
中,仅选择那些非
容器
的第一个祖先有效的元素+1.我只能回忆起一个简单的组合,如
Valid/Child | Valid/Container/Child | Valid/Container/Container/Child
。可能是@Alejandro或@Dimite将提供一种只跳过
容器
步骤的简单方法。@Flack+1。这实际上涵盖了所提供的示例。但是,有效元素和子元素之间的容器元素的数量是任意的(0,1,2,3,…),我希望@Dimitre有解决方案。@Rest Wing,这也足以满足您的示例:
Valid//Child[not(祖先::包装器)]
@Flack:+1。是的,这个例子就足够了。然而,可能存在任意数量的此类“无效”祖先。因此,我需要一个更通用的表达式,类似于
Valid//Child[Valid::Container之后的每个祖先]
+1。壮观的更新中的表达式可能会更简单。然而,它没有第一个严格。请参阅关于Flack提出的答案的问题评论。我可以假设没有有效的元素嵌套:)虽然您的解决方案有效,但我已将@Dimitre给出的解决方案标记为最终答案。然而,我并没有脱下你的条纹,这是你应得的:)@Dimitre:+1。华丽,简洁。太糟糕了,我只能投一张赞成票:)使用这个答案,我能够通过
-使用
count(祖先::有效)=1
@RestWing轻松地处理嵌套的
有效的
元素:是的,XPath是一种了不起的语言。更不用说XPath2.0和XPath3.0了。最近,我完全在XPath 3.0中实现了二叉搜索树数据结构——请在我的博客中看一下。@Dimitre:可以。我想.NET framework只支持XPath 1.0,对吗?@RestWing:correct。但是,至少有两个.NETXSLT2.0处理器:Saxon和XQSharp,当然,这两个处理器都支持XPath2.0。Saxon EE9.3.04(付费版)早期实现了XPath 3.0和XSLT 3.0。