首页 文章

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

提问于
浏览
3

我正在开发的应用程序收到类似于以下的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元素的列表:

  • Childn 的后代 Valid 祖先 .

  • Child 元素的有效祖先是 Container 元素作为 m 生成祖先, Valid 元素作为第一代祖先 .

其中m,n,o是自然数 .

我需要编写以下XPath表达式

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

作为 single XPath表达式 .

对于提供的示例,XPath表达式将仅返回 Child 元素,其 name 属性等于 Child1Child2Child3Child4 .

我最接近解决方案是遵循表达式 .

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

但是,这将选择 Child 元素, name 属性等于 Child19Child20 .

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

2 回答

  • 4

    Use

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

    When this XPath expression is evaluated on the provided XML document:

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

    Exactly the wanted nodes are selected:

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

    Explanation

    表达方式:

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

    means

    从文档中的所有 Child 元素中,仅选择那些不是 Container 的第一个祖先是 Valid 的元素 .

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

    说明:

    //Valid//Child
    

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

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

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

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

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

    因此,如果 ValidChild 之间的所有标记都被称为 Container ,则两个值仅相等 .

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

    Update: 再一次看你的xml,这会不会更容易?

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

相关问题