XPath для возврата конкатенации строк соответствующих значений дочерних узлов

Может ли кто-нибудь предложить формат выражения XPath, который возвращает строковое значение, содержащее конкатенированные значения определенных подходящих дочерних узлов элемента, но игнорируя другие:

<div>
    This text node should be returned.
    <em>And the value of this element.</em>
    And this.
    <p>But this paragraph element should be ignored.</p>
</div>

Возвращаемое значение должно быть одной строкой:

This text node should be returned. And the value of this element. And this.

Возможно ли это в одном выражении XPath?

Спасибо.


person Tim Coulter    schedule 10.09.2009    source источник


Ответы (7)


В XPath 1.0:

Ты можешь использовать

/div//text()[not(parent::p)]

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

person Tomalak    schedule 10.09.2009
comment
Спасибо - вы абсолютно правы. Я только что прочитал справочник по XPath и обнаружил, что все строковые функции неявно работают с первым узлом в наборе узлов, поэтому, следовательно, нет возможности совместить выборку и конкатенацию. - person Tim Coulter; 10.09.2009
comment
Прекрасный и элегантный. Молодец! - person Aaron; 04.02.2012

В XPath 2.0:

string-join(/*/node()[not(self::p)], '')

person Dimitre Novatchev    schedule 10.09.2009
comment
Но вложенная функция не поддерживается в string-join(), например, string-join(normalize-space(//a[@class=title]//text())) - person SIslam; 13.10.2015
comment
@SIslam, это не проблема вложенных функций, а просто то, что normalize-space() принимает один аргумент, а не последовательность. Вместо этого вы можете использовать это выражение: string-join(//a[@class='title']/normalize-space()) . Конечно, вы должны добавить второй аргумент к вызову string-join() - person Dimitre Novatchev; 14.10.2015

/div//text()

двойная косая черта заставляет извлекать текст независимо от промежуточных узлов

person Dewfy    schedule 10.09.2009
comment
Это связано и полезно знать. Спасибо. - person Aaron; 04.02.2012

Этот вид, который работает:

Использование в качестве контекста /div/:

text() | em/text()

Или без использования контекста:

/div/text() | /div/em/text()

Если вы хотите объединить первые две строки, используйте это:

concat(/div/text(), /div/em/text())
person Guillermo    schedule 10.09.2009
comment
Спасибо. Это хороший шаг в правильном направлении. Но я не вижу, как объединить результаты. Когда я заключаю это в вызов функции string(), она возвращает только значение первого выбранного узла. - person Tim Coulter; 10.09.2009
comment
Да, и, как вы могли видеть, мое решение делает то же самое, что и правильное решение. ¬¬ Вы можете объединить (...) узлы, но вы не увидите третий текст. Попробуйте это: concat(/div/text(), /div/em/text()) - person Guillermo; 10.09.2009

Если вам нужны все дети, кроме p, вы можете попробовать следующее...

    string-join(//*[name() != 'p']/text(), "")

который возвращает...

This text node should be returned.
And the value of this element.
And this.
person Rodney P. Barbati    schedule 18.06.2013

Я знаю, что это происходит немного поздно, но я полагаю, что мой ответ все еще может быть актуальным. Недавно я столкнулся с похожей проблемой. И поскольку я использую scrapy в Python 3.6, который не поддерживает xpath 2.0, я не мог использовать функцию string-join, предложенную в нескольких онлайн-ответах.

В итоге я нашел простой обходной путь (как показано ниже), которого я не видел ни в одном из ответов stackoverflow, поэтому я делюсь им.

temp_selector_list = response.xpath('/div')
string_result = [''.join(x.xpath(".//text()").extract()) for x in temp_selector_list]

Надеюсь это поможет!

person Chiraz BenAbdelkader    schedule 31.12.2019

Вы также можете использовать цикл for-each и собирать значения в такой переменной

<xsl:variable name="newstring">
    <xsl:for-each select="/div//text()">
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:variable>
person user2406081    schedule 21.05.2013
comment
Не имеет значения. Постер спросил о XQuery. - person Alberto; 27.07.2016