Запрос Xpath для выбора всех элементов, игнорирующих потомков, на основе критериев - PullRequest
1 голос
/ 25 февраля 2012

Я пытаюсь выбрать все элементы <set>erase</set> таким образом, чтобы, если два или более элемента имели иерархию <set>erase</set> (например, <b> и <d> оба имеют <set>erase</set>), тогда только родительский элемент имя узла должно быть выбрано (например, <b> в этом случае).

Пример XML ниже:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<a>
    <b>
        <set>erase</set>
        <d>
            <set>erase</set>
        </d>
    </b>

    <c>
        <x></x>
    </c>

    <e>
        <y>
            <set>erase</set>
            <q></q>
        </y>
        <z>
            <p>
                <set>erase</set>
            </p>
        </z>
    </e>
</a>

Когда я использую query = //set[contains(.,'erase')], я получаю все <set>erase</set> nodeList b,d,y,p в наборе результатов.

Мне нужна помощь в формировании запроса для выбора <set>erase</set> из b, y и p.

1 Ответ

2 голосов
/ 25 февраля 2012

Вот то же самое решение :

Одно выражение XPath, которое выбирает именно нужные элементы, равно :

          //*[set[. = 'erase' and not(node()[2])]
             and
              not(ancestor::*
                     [set
                        [. = 'erase' and not(node()[2])]
                     ]
                  )
              ]

Проверка на основе XSLT :

<xsl:stylesheet version="1.0"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
         <xsl:output omit-xml-declaration="yes" indent="yes"/>
         <xsl:strip-space elements="*"/>

         <xsl:template match="/">
             <xsl:for-each select=
             "//*[set[. = 'erase' and not(node()[2])]
                 and
                  not(ancestor::*
                         [set
                            [. = 'erase' and not(node()[2])]
                         ]
                      )
                  ]">

              <xsl:value-of select="name()"/>
              <xsl:text>&#xA;</xsl:text>
            </xsl:for-each>
         </xsl:template>
</xsl:stylesheet>

, когда это преобразование применяется к предоставленному документу XML :

<a>
    <b>
        <set>erase</set>
        <d>
            <set>erase</set>
        </d>
    </b>
    <c>
        <x></x>
    </c>
    <e>
        <y>
            <set>erase</set>
            <q></q>
        </y>
        <z>
            <p>
                <set>erase</set>
            </p>
        </z>
    </e>
</a>

Содержимое выражения XPath оценивается, и имена выбранных элементов выводятся - правильно и как ожидалось :

b
y
p

Если вам нужно выбрать set потомков из указанных вышеэлементы, просто добавьте приведенное выше выражение XPath с помощью /set:

          //*[set[. = 'erase' and not(node()[2])]
             and
              not(ancestor::*
                     [set
                        [. = 'erase' and not(node()[2])]
                     ]
                  )
              ]
               /set

Опять же, XSLT-проверка :

<xsl:stylesheet version="1.0"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
         <xsl:output omit-xml-declaration="yes" indent="yes"/>
         <xsl:strip-space elements="*"/>

         <xsl:template match="/">
             <xsl:copy-of select=
             "//*[set[. = 'erase' and not(node()[2])]
                 and
                  not(ancestor::*
                         [set
                            [. = 'erase' and not(node()[2])]
                         ]
                      )
                  ]
                   /set
                  "/>
         </xsl:template>
</xsl:stylesheet>

Это преобразование простооценивает приведенное выше выражение XPath и копирует на выход правильно выбранные три set элемента :

<set>erase</set>
<set>erase</set>
<set>erase</set>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...