Выражение XPath с условием для нескольких предков - PullRequest
3 голосов
/ 13 февраля 2011

Разрабатываемое мной приложение получает структуру 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>

Мне нужно получить список дочерних элементов при следующих условиях:

  1. Child является n потомком поколения Действительный предок.
  2. Child может быть m потомком поколения Контейнер предок, который является o потомком поколения Действительный предок.
  3. Допустимые предки для Дочерний элемент являются Контейнер элементов в качестве m предков поколения и Действительный элемент в качестве предка первого поколения.

где m, n, o - натуральные числа.

Мне нужно записать следующие выражения XPath

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

как одиночное выражение XPath.

Для предоставленного примера выражение XPath вернет только Child элементы, имеющие name атрибут, равный Child1 , Child2 , Child3 и Child4 .

Самое близкое решение, которое я нашел, - следующее выражение.

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

Однако этовыбрал бы Child элемент с атрибутом name , равным Child19 и Child20 .

Поддерживает ли синтаксис XPath любое дополнительное вхождениеэлемента или установочного условия, аналогичного self в предыдущем примере для всех предков между Child и Valid elements?

Ответы [ 2 ]

4 голосов
/ 13 февраля 2011

Используйте

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

Когда это выражение 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 name="Child1"/>
<Child name="Child2"/>
<Child name="Child3"/>
<Child name="Child4"/>

Объяснение

Выражение:

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

означает :

Из всех Child элементов в документе выберите только те, для которых первый предок, который не является Container, равен Valid.

3 голосов
/ 13 февраля 2011
//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

Поэтому два значения равны, только если все теги между Valid и Child называются Container.

Однако в этом выражении предполагается, что вложенных тегов Valid не будет, т. Е. /Valid/Valid/Child не будет им приниматься.

Обновление: Еще раз посмотрев на ваш xml, не будет ли это проще?

//Valid//Child[not(ancestor::Wrapper)]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...