как вернуть строку или сопоставить пустое, если узел / тег не найден в xpath (lxml) - PullRequest
2 голосов
/ 27 февраля 2012

У меня есть следующий XPath для соответствия имени автора на странице Amazon:

// div [@ class = 'pTitle'] / span [@ class = 'small itemByline'] | // DIV [@ класс = 'pTitle'] / SPAN [нет (текст ())]

Первая часть этого XPath соответствует ему просто отлично, однако некоторые элементы на странице не имеют промежутка после такого div с классом pTitle, так что совпадать не с чем, но я бы хотел получить '' или что-то еще , чтобы узнать, что автор не был найден на самом деле вместо того, чтобы просто пропустить его. Я полагаю, что второй XPath является недействительным, поскольку он не работает ...

Например, 3 заголовка, начинающиеся с 'A Ditadura', должны возвращаться '' для записи автора с использованием XPath, который я создаю. Они не все же. Таким образом, XPath возвращает 179 предметов вместо 209.

Цель - http://www.amazon.com/wishlist/3MCYFXCFDH4FA/ref=cm_wl_act_print_o?_encoding=UTF8&layout=standard-print&disableNav=1&visitor-view=1&items-per-page=1000

Это часть кода моего модуля Python https://github.com/caio1982/Amazon-Wishlist (спасибо, кстати, за все хорошие ответы в SO, я выучил XPath, спасибо вам, ребята).

Ради информации, я пытаюсь сделать это с помощью расширения Firefox XPath Checker, реализуя его с помощью Python (lxml).

Звучит похоже на Как мне вернуть '' для текста пустого узла () в XPath? , но я не уверен, хотя.

Я подозреваю, что ответом может быть что-то вокруг осей XPath и какое-то [notcontains] ограничение?

EDIT1: перефразируя его немного после предложения Димитра ... можно ли использовать - и если да, то есть ли у вас рабочий пример - метода Беккера XPath с использованием lxml?

EDIT2: образец дерева и ожидаемые результаты:

    <html>
        <body>
            <h1>Title</h1>
            <p>First Paragraph</p>
            <p>Second paragraph: <span>value</span></p>
            <p>Third paragraph: <span>value</span></p>
            <p>Forth paragraph:</p>
        </body>
    </html>

XPath // p / span возвращает строки 'value' второго и третьего абзаца соответственно. Это нормально, но я ищу 4 результата вместо 2, например:

    None
    value
    value
    None

Я знаю, что // p / span не работает для этого, поэтому я ищу некоторую магию строк, сравнение узлов или условия и т. Д.

1 Ответ

1 голос
/ 27 февраля 2012

Вы можете использовать выражение XPath, подобное этому :

concat(
//div[@class='pTitle']/span[@class='small itemByline'],
substring('UNKNOWN', 
          1 + 7*(boolean(//div[@class='pTitle']/span[@class='small itemByline'])
          )
       )

Когда вычисляется это выражение XPath и если существует //div[@class='pTitle']/span[@class='small itemByline'], то его строковое значение (объединяется спустая строка).

Если //div[@class='pTitle']/span[@class='small itemByline'] не существует, то результатом является строка 'UNKNOWN' - пустая строка объединяется с substring('UNKNOWN', 1+0).

Здесьмы используем тот факт, что в XPath 1.0 всякий раз, когда логическое значение является аргументом арифметического оператора, оно сначала преобразуется в число, используя правило:

   number(true()) = 1

и

   number(false()) = 0

Обновление : Здесь приведена проверка на основе XSLT с использованием OP документа XML из EDIT 2 и получение в точности нужного результата (вычисляется то же выражение XPath (обновляется только индекс) 4время и все полученные значения выводятся - каждое в отдельной строке):

<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:for-each select="(//node())[not(position() > count(//p))]">
   <xsl:variable name="vPos" select="position()"/>
   <xsl:value-of select=
     "concat((//p)[position() = $vPos]/span,
             substring('UNKNOWN',
                       1 +7*boolean((//p)[position() = $vPos]/span)
                       )
             )
     "/>

     <xsl:text>&#xA;</xsl:text>
  </xsl:for-each>
 </xsl:template>
</xsl:stylesheet>

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

<html>
    <body>
        <h1>Title</h1>
        <p>First Paragraph</p>
        <p>Second paragraph: 
            <span>value</span>
        </p>
        <p>Third paragraph: 
            <span>value</span>
        </p>
        <p>Forth paragraph:</p>
    </body>
</html>

выражение XPathоценивается N (4) раза, и результаты этой оценки получаются - как мы видим, это именно те результаты, которые мы хотели получить :

UNKNOWN
value
value
UNKNOWN
...