Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > JavaScript: Наши скрипты > jpath - убийца xpath и cssquery |
Автор: cruelangel 28.10.2007, 01:16 | ||
основной недостаток xpath и css selectors заключается в том, что логика их работы основана на продвижении сверху вниз. это удобно, когда мы начинаем путь из корня и ищем узлы-потомки, но совершенно не удобно, если мы ищем соседей или родителей. в jpath все направления движения равноправны - вы просто выбираете ось и двигаетесь по ней как и по любой другой. пара примеров: var cells= jpath( table, '/2tr /td' ); // выбирает все ячейки, находящиеся во второй строке таблицы var table= jpath( cell, '^1table' )[0]; // выбирает самую вложенную таблицу в которой находится ячейка как видно, каждый путь состоит из одного или большего количества операторов, пробельные символы между операторами игнорируются. каждый оператор состоит из: 1. префикс оси. обязательный параметр. определяет в какую сторону будем двигаться. примеры перфиксов: ^ / + - @ 2. индекс. если он не указан, то будут выбраны все узлы находящиеся на этой оси. если оказан, то будет выбран только узел с указанным номером (1 - первый узел). 3. название узла. если он не указан - будут выбираться любые узлы. если указана звёздочка, то любые хтмл-элементы. ну и если указано собственно название, то будут выбираться только соответствующие узлы (регистр не важен). примеры названий: body table #text #comment возвращаемое значение - массив найденых узлов. пока реализовано 6 осей: 1. младшие братья. префикс +. на этой оси располагаются все братья, расположенные ниже текущего элемента. например, если вам нужно перейти к следующему параграфу, просто напишите: var currentParagraf= jpath( currentParagraf, '+1p' )[0]; 2. старшие братья. префикс -. то же самое, но в другую сторону. все предыдущие параграфы можно получить так: var paragrafs= jpath( currentParagraf, '-p' )[0]; 3. предки. префикс ^. на этой оси расположены все предки. непосредственного предка можно получить так: var parentNode= jpath( node, '^1*' )[0]; 4. дети. префикс /. например, следующий код, в отличие от childNodes, вернёт все дочерние html-элементы: var childs= jpath( node, '/*' ); 5. потомки. префикс //. на этой оси располагаются вообще все узлы-потомки. следующий код демонстрирует выборку всех таблиц на странице: var tables= jpath( document, '//table' ); 6. аттрибуты. префикс @. следующий код показывает как найти все ссылки на странице: var links= jpath( document, '//a@href^1' ); в планах: 1. ось элементов расположенных ниже на странице. префикс ++. возвращает всех младших братьев узла и его родителей, а также всех их детей. 2. противоположная ось. префикс --. ну и собственно текущий сырец:
|
Автор: Sardar 28.10.2007, 01:48 |
А как же с осями following-sibling/preceding-sibling и ancestor? Также в XPath можно пользоваться (довольно ограниченным) набором функций в предикатах, например брать только префикс. P.S. код аккуратный, читаю в удовольствие ![]() |
Автор: cruelangel 28.10.2007, 02:09 |
блин, я опять изобрёл велосипед ![]() хотя нет, фильтрацию по свойствам дом-объектов в xpath не засунешь... насчёт функций - думаю не стоит излишне перегружать язык запросов. |
Автор: SelenIT 28.10.2007, 02:14 |
Сорри, а где таковая в jpath? А атрибуты вроде есть и там, и там... |
Автор: cruelangel 28.10.2007, 02:22 |
SelenIT, этого пока нет, как и фильтрации вообще ![]() второй вариант помог бы избежать таких монстров: var height= document && document.documentEleent && document.documentElement.offsetHeight; ![]() |
Автор: SelenIT 28.10.2007, 02:48 |
А обязательно делать фильтрацию по свойствам встроенной в сам язык запросов? Не удобнее ли будет иметь два раздельных инструмента - универсальный XPath (можно даже со стандартным синтаксисом, дабы не множить сущности) и универсальный фильтр по JS-свойствам для коллекций (неважно каким путем полученных)? |
Автор: cruelangel 28.10.2007, 12:09 |
ты предлагаешь что-то вроде этого: jpath( jpath( '//div' ).filter( function( nodes ){ ... } ), '//span' ) вместо этого: jpath( '//div[..]//span' ) ? а стандартный синтаксис слишком громоздкий... |
Автор: cruelangel 28.10.2007, 19:30 |
в общем, от квадратных скобочек я отказался, ибо они сильно усложняют логику, тем не менее можно фильтровать как по аттрибутам так и по свойствам. найти все тэги с классом submit: var submits= jpath( document, '//* @class=!\\bsubmit\\b! ^1' ); или: var submits= jpath( document, '//* .className=!\\bsubmit\\b! ^1' ); первый вариант ищет по аттрибутам, второй - по свойствам. ещё пример - поиск всех элементов с установленным стилем style.display="none": var hiddens= jpath( document, '//* .style .display=!^none$! ^2' ); как видно в этом выражении 4 оператора, что они делают: 1. находит все элементы-потомки 2. находит для них свойства style 3. для всех свойств style находит свойства display значения которых удовлетворяют регулярному выражению обрамлённому восклицательными знаками (вместо них как и в pcre можно использовать любые другие символы, экранированные ограничители внутри регулярки использовать пока нельзя) 4. для всех найденных свойств display находит второго предка, то есть хтмл-элемент к которому он относится. |
Автор: cruelangel 28.10.2007, 20:08 |
var headings= jpath( document, '//* .nodeName=/^H\\d$/ ^1' ); - ищет все заголовочные элементы. обратите внимание, что теперь сопоставление с именем тэга регистрозависимо. это значит, что имена тэгов нужно писать в верхнем регистре, либо использовать модификатор игнорирования регистра: var headings= jpath( document, '//* .nodeName=/^h\\d$/i ^1' ); var all_h1= jpath( document, '//h1=!!i' ); Добавлено @ 20:15 SelenIT, просто если делать квадратные скобки, то для реализации возможности вкладывать их друг в друга придётся мутить полноценный токенайзер, а не как у меня сейчас - одной регуляркой идёт выделение операторов и поточная их обработка. |
Автор: cruelangel 28.10.2007, 22:58 |
позаимствовал из css один селектор: var lefts= jpath( document, '//* @class~="left" ' ); - найдёт все элементы с классом left. всё, что внутри кавычек также является регулярным выражением, но к нему будет автоматически дописано '(?:^|\\s)' вначале и '(?:\\s|$)' в конце |
Автор: cruelangel 31.10.2007, 16:26 |
пофиксил багу с неработающим '//' Добавлено через 6 минут и 49 секунд попытка воспользоваться благами цивилизации - xpath - благополучно провалилась ![]() |
Автор: cruelangel 2.11.2007, 15:44 |
пофиксил багу с неработающей звёздочкой. повысил перфоманс. добавил выходную фильтрацию - теперь выдаются только уникальные узлы, без дубликатов. |