Запрос XPath с потомком и потомком текста () предикатов

StackOverflow https://stackoverflow.com/questions/3920957

Вопрос

Я хотел бы построить запрос XPath, который вернет элемент «div» или «таблица», пока у него есть потомк, содержащий текст «ABC». Одно оговорку состоит в том, что не может иметь никаких потомков Div или таблиц.

<div>
  <table>
    <form>
      <div>
        <span>
          <p>abcdefg</p>
        </span>
      </div>
      <table>
        <span>
          <p>123456</p>
        </span>
      </table>
    </form>
  </table>
</div>

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

/div/table/form/div 

Моя лучшая попытка выглядит что-то подобное:

//div[contains(//text(), "abc") and not(descendant::div or descendant::table)] | //table[contains(//text(), "abc") and not(descendant::div or descendant::table)]

Но не возвращает правильный результат.

Спасибо за вашу помощь.

Это было полезно?

Решение

Что-то другое: :)

//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1]

Кажется, намного короче, чем другие решения, не так ли? :)

Перевод на простой английский: Для любого текстового узла в документе, который содержит строку "abc" Выберите свой первый предков, который является либо div или а table.

Это более эффективно, как требуется только одно полное сканирование дерева документа (а не какого-либо другого), а ancestor::* обход очень дешевый по сравнению с descendent:: (дерево) сканирование.

Чтобы убедиться, что это решение «действительно работает»:

<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=
  "//text()[contains(.,'abc')]/ancestor::*[self::div or self::table][1] "/>
 </xsl:template>
</xsl:stylesheet>

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

<div>
  <table>
    <form>
      <div>
        <span>
          <p>abcdefg</p>
        </span>
      </div>
      <table>
        <span>
          <p>123456</p>
        </span>
      </table>
    </form>
  </table>
</div>

Требуется, правильный результат производится:

<div>
   <span>
      <p>abcdefg</p>
   </span>
</div>

Примечание: Не нужно использовать XSLT - любой хост XPath 1.0 - например, DOM, должен получить тот же результат.

Другие советы

//*[self::div|self::table] 
   [descendant::text()[contains(.,"abc")]]  
   [not(descendant::div|descendant::table)]

Проблема с contains(//text(), "abc") Это функции литых узлов наборы принимают первый узел.

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

//div[
  descendant::text()[contains(., "abc")] 
  and not(descendant::div or descendant::table)
] | 
//table[
  descendant::text()[contains(., "abc")] 
  and not(descendant::div or descendant::table)
]

Это помогает?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top