XPath для поиска узлов с текстом + всех их потомков и братьев и сестер, которые соответствуют определенным критериям - PullRequest
2 голосов
/ 23 сентября 2011

Справочная информация:
Я пытаюсь улучшить скрипт Greasemonkey Я нашел.
Скрипт помечает цены в иностранных валютах и ​​может перевести их в валютуна ваш выбор.

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

<b><i>9.</i></b><sup>95</sup>EUR

(Newegg.com, например, делает это - они пишут свои цены следующим образом: $ 174 .99 ).

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

document.evaluate("//text()", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null)

Поскольку сценарий должен быть быстрым, я стараюсь избегать слишком частого прохождения DOM ...
Есть ли какие-нибудь гуру XPath, которые могли бы помочь с некоторыми умными решениями для этой цели?
Более подробное описание проблемы:
Код, который у меня теперь есть для поиска текстовых узлов:

var re_skip = /^(SCRIPT|IFRAME|TEXTAREA|STYLE|OPTION|TITLE|HEAD|NOSCRIPT)$/;  // List of elements whose text node-children can be skipped
text = document.evaluate("//text()", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
var i = text.snapshotLength;
while (i--) {
    el = text.snapshotItem(i);
    if (!el.parentNode || re_skip.test(el.parentNode.nodeName.toUpperCase()) || el.parentNode.className == 'autocurrency') {
        continue;
    }
//  ...
//  (RegEx logic to check if prices can be found in the text)
}

  • Проверка на удаление текстовых узлов, родительские элементы которых перечислены в "re_skip", также может быть выполнена в выражении XPath ( с использованием нотации "not" ), право?И это даст увеличение скорости?

  • Если вместо этого используется упорядоченный тип XPath, я думаю, мне больше не придется включать проверку, чтобы увидеть, является ли родительский элемент анализируемого текстового узла (то есть , что скрипт добавляет к согласованным ценам).

  • Если я все правильно понял, то normalize-space () (как предложено здесь ) не может бытьиспользуется в этом случае, так как сценарий добавляет около соответствующей суммы, и нам нужно сохранить правильный индекс для того, где это должно быть введено.

  • Есть ли способ дляXPath разрешить использование только определенных (встроенных) элементов между значениями валюты?Или, возможно, он мог бы сделать это: "когда найден узел, содержащий текст, также включить все его дочерние элементы (и их дочерние элементы и т. Д.) В совпадение - , если дочерний узел не является блокомТип элемента. "(или, возможно, он должен читать: «... если дочерний узел не является DIV, P, TABLE или любым из элементов в re_skip»)

Я могу повторно-пишите регулярное выражение для обработки текста, такого как " $ 174 .99 ", пока я нахожу эти текстовые строки - желательно с использованием XPath, как я понялэто намного быстрее, чем проходить через DOM.

Большое спасибо заранее за любую помощь, которую вы можете мне оказать с этим!
--------------------------------------------------------------
РЕДАКТИРОВАТЬ:
ОК, теперь я понимаю, что вопрос может быть с некоторыми пояснениями и некоторыми примерами, поэтомувот они идут.Веб-страница может выглядеть примерно так:

<body>
  <div>
    <span>9.95 <span>EUR</span></span><br />
    <span>8.<sup>95</sup></span>AU$<br />
    <table>
      <thead>
        <tr>
          <th>Bla</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td><b>7</b>.95kr</td>
        </tr>
      </tbody>
    </table>
    <div>Bla bla</div>
    6.95 <span>GBP</span>
  </div>
  <div><img src="" /><img src=""><span>Bla bla bla</span></div>
</body>

Теперь в этом примере издержки не так велики - я мог бы просто передать весь исходный код в виде строки непосредственно в регулярное выражение, котороенаходит цены.Но обычно на страницах будет много нетекстовых элементов, которые сделают скрипт очень медленным, если я не использую быстрый XPath для разбора текстов.Итак, я ищу выражение XPath, которое нашло бы различные тексты в приведенном выше примере, , но не , просто текстовое содержимое - поскольку нам также нужны теги, которые могут окружать частицена (новая будет позже создана вокруг согласованной цены, включая любые встроенные элементы, которые могут окружать части цены).

Я не знаю точно, какой XPath можно сделать, чтобы вернуть, но как-то Мне нужно взять следующие строки на странице примера выше:

"9.95 <span>EUR</span>"       (or possibly: "<span>9.95 <span>EUR</span></span>")
"<span>8.<sup>95</sup></span>AU$"
"Bla"                         (or possibly: "<th>Bla</th>")
"<b>7</b>.95kr"               (or possibly: "<td><b>7</b>.95kr</td>")
"Bla bla"                     (or possibly: "<div>Bla bla</div>")
"6.95 <span>GBP</span>"
"Bla bla bla"                 (or possibly: "<span>Bla bla bla</span>")

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

1 Ответ

1 голос
/ 23 сентября 2011

Что ж, вы, конечно, можете использовать путь, подобный //*[not(self::script | self::textarea | self::style)]//text(), чтобы найти только тех потомков текстовых узлов, которые не являются элементами "script", "textarea", "style".Таким образом, у вас нет необходимости проверять регулярное выражение, вы можете выразить это требование с помощью XPath.Работает ли это лучше, я не могу сказать, вам придется проверить с реализациями XPath браузеров, с которыми вы хотите использовать скрипт Greasemonkey.

...