Нужен xpath, который находит все элементы определенного типа до первого появления определенного элемента - PullRequest
2 голосов
/ 27 июня 2019

Мне нужен xpath, который выбирает все элементы определенного типа элемента, скажем, input, который происходит до первого появления другого элемента.проблема в том, что нет правильной иерархии между целевыми элементами и «другим элементом».и в html может быть любое количество «другого элемента».

Я пытался использовать оси 'following', и это работает, если есть только один «другой элемент».но если их много, он не работает

<a>
    <b>
        <input>zyx</input>
        <div>abc</div>
        <span>def</span>
        <input>ghi</input>
    </b>
    <c>
        <div class="SameAttribute">Test</div>
        <input>jkl</input>
        <div>mno</div>
    </c>
    <d>
        <div class="SameAttribute">Test</div>
        <input>pqr</input>
        <div>stu</div>
    </d>
</a>

, как указано выше в структуре html, я хочу только элементы input, которые находятся внутри тега <b>.xpath должен игнорировать элементы input, находящиеся в тегах <c> и <d>. Попробовал это

.//*[self::input][following::div[@class = 'SameAttribute']]

, но он выбирает элементы из тегов <b> и <c>.

Когда я пытаюсь это сделать, ничего не выбирается

.//*[self::input][following::(div[@class = 'SameAttribute'])[1]]

Я не могу написать xpaths, содержащие любой из тегов <b>, <c>, <d> из-за других ограничений

Ответы [ 5 ]

0 голосов
/ 28 июня 2019

Мне нужны только те элементы ввода, которые находятся внутри тега <b>.xpath должен игнорировать входные элементы, которые находятся внутри тегов <c> и <d>

Использовать :

//b//input

Мне нужноxpath, который выбирает все элементы определенного типа элемента, скажем, input, который происходит до первого появления другого элемента.проблема в том, что нет правильной иерархии между целевыми элементами и «другим элементом».и в html может быть любое количество «другого элемента».

Это не эквивалентно первому требованию, указанному выше.

Вы не указываете, что означаетНе используя «другой элемент», но комбинируя два указанных требования и предоставленный исходный XML-документ, можно логически заключить, что «другой элемент» здесь означает любой следующий элемент одного элемента /a/b[1]

Это будетвыбирается:

(//b)[1]//input

или для предоставленного XML-документа просто:

/a/b[1]//input

Если документ содержит более одного /a/b элементов и вы хотите получить потомков inputтолько из этих /a/b/ элементов, которые предшествуют любым /a/{X} элементам, где {X} - это имя, отличное от b, используйте:

/a/b[not(preceding-sibling::*[not(self::b)])]//input

Наконец, в самом общем случае, если вы хотитевыбрать input потомков только таких b элементов, которые идут ** перед * любым * (non-b) элементом (исключая верхний элемент - если верхний элемент является b, то любой input потомоктЭлемент op удовлетворяет требованию, вот одно выражение XPath, которое выбирает их:

/*//b[not(ancestor::*[not(self::b) and parent::*]) 
    and not(preceding::*[not(self::b)])]
      //input

Здесь мы используем тот факт, что если элемент x находится раньше (в порядке документа), то элемент y, тогдаx является либо предком y (принадлежит его оси ancestor::*), либо предшествующим элементом (принадлежит его оси preceding::*)

верификация на основе XSLT :

Это преобразование оценивает все 5 выражений XPath и выводит выбранные узлы:

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

  <xsl:template match="/">
    <xsl:copy-of select="//b//input"/>
    ==================================
    <xsl:copy-of select="(//b)[1]//input"/>
    ==================================
    <xsl:copy-of select="/a/b[1]//input"/>
    ==================================
    <xsl:copy-of select="/a/b[not(preceding-sibling::*[not(self::b)])]//input"/>
    ==================================
    <xsl:copy-of select=
    "/*//b[not(ancestor::*[not(self::b) and parent::*])
        and not(preceding::*[not(self::b)])]
          //input"/>
  </xsl:template>
</xsl:stylesheet>

При применении к первоначально предоставленному документу XML :

<a>
    <b>
        <input>zyx</input>
        <div>abc</div>
        <span>def</span>
        <input>ghi</input>
    </b>
    <c>
        <div class="SameAttribute">Test</div>
        <input>jkl</input>
        <div>mno</div>
    </c>
    <d>
        <div class="SameAttribute">Test</div>
        <input>pqr</input>
        <div>stu</div>
    </d>
</a>

желаемый, правильный результат выбирается при оценке каждого выражения :

<input>zyx</input>
<input>ghi</input>
    ==================================
    <input>zyx</input>
<input>ghi</input>
    ==================================
    <input>zyx</input>
<input>ghi</input>
    ==================================
    <input>zyx</input>
<input>ghi</input>
    ==================================
    <input>zyx</input>
<input>ghi</input>
0 голосов
/ 27 июня 2019

Я попытался использовать комбинацию осей preceding и ancestor, чтобы прийти к решению. Ниже приведен XPath, который работал для меня
(.//div[@class='SameAttribute'])[1]/preceding::*[self::input][ancestor::a]

0 голосов
/ 27 июня 2019

Один Xpath, который, по-видимому, удовлетворяет вашим критериям:

//input[not(preceding-sibling::*[contains(@class,'SameAttribute')])]

При этом будут найдены все входные элементы, у которых нет предшествующего родного брата, который имеет атрибут класса, который содержит класс SameAttribute.

0 голосов
/ 27 июня 2019

Как вы описали проблему, самое простое решение - //b/*. В качестве альтернативы, если вы хотите, чтобы у всех элементов был тот же родительский элемент, что и у первого элемента input, вам может потребоваться (//input)[1]/following-sibling::*.

Вы, конечно, не хотите, чтобы здесь была ось following: прочтите разницу между following и following-sibling.

Ваше выражение //*[self::input] - очень запутанный способ сказать //input.

0 голосов
/ 27 июня 2019

Вы можете попробовать этот xpath

Это для индексации всех входных данных (пожалуйста, измените номер счета на другие):

(.//*[self::input][following::div[@class = 'SameAttribute']])[1]

Это простой способ, input между тегами <b>:

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