Получение всех узлов между текущим узлом и другим без current ()? - PullRequest
0 голосов
/ 26 марта 2009

Я работаю над скриптом Greasemonkey, который должен работать на каждом узле между двумя другими. В настоящее время я получаю первый узел, использующий (все более сложное) выражение XPath. У меня есть другое выражение, чтобы получить «между» узлами, но оно содержит начальное выражение дважды и становится довольно длинным. Вот более ранняя версия, которая содержала только два «предложения»:

var xpHeader   = "//h2[a/@name='section-References' or a/@name='References']";
var xpContents = "//h2[a/@name='section-References' or a/@name='References']/following-sibling::*[following-sibling::h2[1] = //h2[a/@name='section-References' or a/@name='References']/following-sibling::h2[1]]"

То, что я ищу, - это способ выбора «содержимого» на основе узла контекста, а не повторное включение исходного выражения несколько раз - это выражение «заголовка» очень быстро станет значительно сложнее. Я знаю, что это можно сделать в XSLT с помощью функции current(), но, конечно, это не доступно в vanilla XPath:

<xsl:template match="//h2[a/@name='section-References' or a/@name='References']">
    <xsl:for-each select="following-sibling::*[following-sibling::h2[1] = current()/following-sibling::h2[1]]">
        <!-- do stuff -->
    </xsl:for-each>
</xsl:template>

Когда я набираю это, мне приходит в голову, что на этом этапе, вероятно, будет проще использовать DOM для сбора содержимого, а не XPath, но мне все еще интересно знать, можно ли это сделать .

Исходная версия скрипта доступна на UserScripts.org .

Ответы [ 3 ]

2 голосов
/ 26 марта 2009

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

var nodes = document.evaluate("//h2[a/@name='section-References' or a/@name='References']/following-sibling::*", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var contents=[];
if (nodes.snapshotLength>0) contents.push(new Array());
var currentGroup=0;
for (var i=0;i<nodes.snapshotLength;i++) {
  if (nodes.shapshotItem(i)==<your favorite way to detect the right flavor of h2 element>) {
    currentGroup++;
    contents.push(new Array());
    continue;
  }
  contents[currentGroup].push(nodes.snapshotItem(i));
}

Это немного многословно, но в итоге вы получите массив массивов элементов между интересными узлами h2.

2 голосов
/ 26 марта 2009

Хотя вы пишете выражения XPath, для Javascript они просто строки. Вы можете объединять строки.

var xpContents = xpHeader + "/following-sibling::*["
  + "following-sibling::h2[1] = " + xpHeader + "/following-sibling::h2[1]"
  + "]";

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

1 голос
/ 26 марта 2009

Вы можете использовать jQuery или другую инфраструктуру JavaScript, чтобы упростить работу с DOM.

Пример:

// ==UserScript==
// @name           MyScript
// @namespace      http://example.com
// @description    Example
// @include        *
//
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js
// ==/UserScript==

$('h2[some crazy attributes...]').each(function() {
  // Do something
});

Обратитесь к справке jQuery для получения дополнительной информации о выборе и обходе элементов DOM через атрибуты XPath.

Селекторы jQuery

jQuery Traversal

jQuery next ()

jQuery nextAll ()

...