XPath для выбора всего текста в заданном node и текста его chldren

В основном мне нужно очистить текст, содержащий вложенные теги.

Что-то вроде этого:

<div id='theNode'>
This is an <span style="color:red">example</span> <b>bolded</b> text
</div>

И я хочу выражение, которое произведет это:

This is an example bolded text

Я боролся с этим в течение часа или более без результата.

Любая помощь приветствуется

Ответ 1

string-value элемента node является конкатенацией строковых значений всех текстовых node потомков элемента node в порядке документа.

Вы хотите вызвать функцию XPath string() в элементе div.

string(//div[@id='theNode'])

Вы также можете использовать функцию normalize-space, чтобы уменьшить нежелательные пробелы, которые могут появиться из-за новых строк и отступов в исходном документе. Это приведет к удалению начального и конечного пробелов и замену последовательностей пробельных символов одним пробелом. Когда вы передаете набор узлов в normalize-space(), узел node сначала будет преобразован в него строковым значением. Если аргументы не передаются в normalize-space, он будет использовать контекст node.

normalize-space(//div[@id='theNode'])

// if theNode was the context node, you could use this instead
normalize-space()

Возможно, вы захотите использовать более эффективный способ выбора контекста node, чем пример XPath, который я использовал. например, в некоторых браузерах на этой странице может быть запущен следующий пример Javascript.

var el = document.getElementById('question');
var result = document.evaluate('normalize-space()', el, null ).stringValue;

Простым текстовым текстом node между элементами span и b может быть проблема.

Ответ 2

Использование

string(//div[@id='theNode'])

Когда это выражение оценивается, результатом является строковое значение первого (и, надеюсь, только) div элемента в документе.

Поскольку строковое значение элемента определяется в Спецификация XPath как конкатенация в порядке документа всех его текстовых потомков node, это точно искомая строка.

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

Использование

normalize-space(string(//div[@id='theNode']))

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

<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="string(//div[@id='theNode'])"/>"
===========
  "<xsl:copy-of select="normalize-space(string(//div[@id='theNode']))"/>"
 </xsl:template>
</xsl:stylesheet>

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

<div id='theNode'> This is an 
    <span style="color:red">example</span>
    <b>bolded</b> text 
</div>

вычисляются два выражения XPath и результаты этих оценок копируются в выходной файл:

  " This is an 
    example
    bolded text 
"
===========
  "This is an example bolded text"

Ответ 3

Как насчет этого:

/div/text() [1] |/div/span/text() |/div/b/text() |/div/text() [2]

Hmmss Я не уверен в последней части. Возможно, вам придется играть с этим.

Ответ 4

Если вы используете scrapy в python, вы можете использовать descendant-or-self::*/text(). Полный пример:

txt = """<div id='theNode'>
This is an <span style="color:red">example</span> <b>bolded</b> text
</div>"""

selector = scrapy.Selector(text=txt, type="html") # Create HTML doc from HTML text
all_txt = selector.xpath('//div/descendant-or-self::*/text()').getall()
final_txt = ''.join( _ for _ in all_txt).strip()
print(final_txt) # 'This is an example bolded text'