Пользовательский селектор jQuery для текстовых узлов

Я хотел бы извлечь текст из элемента DOM с помощью пользовательского селектора jQuery. Он должен выбирать только текстовый узел без его помеченных братьев и сестер (очень похоже на /text() в XPath).

Предыстория: я работаю над расширением Firefox, которое извлекает определенную информацию (например, имя пользователя) на самых разных веб-сайтах. Теперь я хочу, чтобы мои пользователи могли динамически добавлять определения пути для новых веб-сайтов через максимально простую форму:

Добавить новый сайт:

URL: ________________ (например, "http://stackoverflow.com/questions/")

Путь: ________________ (например, ".user-details>a:eq(0)" для имени пользователя, задавшего вопрос)

Например, в stackoverflow $(path).text() вернет имя пользователя в виде текста. Но на некоторых других сайтах имя пользователя доступно только как текстовый узел с помеченными братьями и сестрами, как в этом примере:

<div id="person">
    johndoe <span id="age">(57)</span>
    <span id="description">Lorem ipsum dolor sit amet…</span>
</div>

Поскольку jQuery не предоставляет селектора для текстовых узлов (например, /text() в XPath), я надеялся найти решение, создающее собственный селектор.

Я знаю, как получить текстовый узел без селектора:

var textNode = $('#person').contents().filter(function(){
    return this.nodeType == 3;
}).text();

alert(textNode); // gives me "johndoe"

Как бы я перевел это в пользовательский селектор? Следующее, очевидно, не работает, поскольку оно всегда возвращает полный элемент, как только одна его часть является текстовым узлом (как объясняет @VinayC в своем ответе):

$.extend($.expr[':'],{
    getText: function(element){
        return $(element).contents().filter(function() {return this.nodeType == 3;}).text();
    }
});

alert($('#person:getText')); //returns the whole DIV element

См. мой jsfiddle

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

Спасибо за вашу помощь.


person modoq    schedule 03.05.2011    source источник
comment
Вы подходите к этой проблеме не в том направлении. И если есть дополнительная информация, о которой мы должны знать, вы должны указать ее в своем вопросе (а не хоронить ее в каком-то комментарии)   -  person Robert Koritnik    schedule 03.05.2011
comment
Извините, это мой первый вопрос о SO. Какое направление было бы лучше? Какую информацию вы бы посоветовали мне перейти к вопросу?   -  person modoq    schedule 04.05.2011
comment
Оба ваших комментария к ответу @VinayC содержат дополнительную информацию о процессе, который вы хотели бы поддержать, и о том, почему вы решили сделать это с помощью селекторных фильтров. Особенно информация из первого комментария очень важна и должна быть включена (возможно, даже более подробно) в исходное сообщение с вопросом.   -  person Robert Koritnik    schedule 04.05.2011
comment
@Robert Koritnik: я отредактировал свой вопрос, пытаясь отразить ваш совет.   -  person modoq    schedule 04.05.2011


Ответы (1)


Что вы делаете, так это создаете селектор jquery, и функция селектора должна возвращать логическое значение, чтобы указать, совпал ли переданный узел или нет. Таким образом, ваша текущая функция возвращает «истину» для div «#person» ((фактическое возвращаемое значение — это текст внутри div, который не является пустым и, следовательно, считается истинным), и, следовательно, вы получаете элемент div в качестве результата.

Вы можете попробовать getText: function(node){ return node.nodeType == 3;}, но это будет работать, только механизм jquery передает все узлы документа, включая текстовые узлы, через функции выбора (я не знаю, работает он или нет). Альтернативой является создание вспомогательной функции вместо пользовательского селектора.

РЕДАКТИРОВАТЬ: как насчет расширения объекта jquery? Например,

$.fn.extend({
    getText: function() {
        return this.contents().filter(function() {return this.nodeType == 3;}).text();
    }
});

alert($('#person').getText());
person VinayC    schedule 03.05.2011
comment
Спасибо за ваш ответ. getText: function(node){ return node.nodeType == 3;}не работает. - Может быть, проблема в том, что селектор клиентов может проходить только через нетекстовые узлы? (в отличие от .contents()) - person modoq; 03.05.2011
comment
Причина, по которой я ищу решение с селекторами: я работаю над расширением Firefox, которое извлекает определенную информацию на очень разных веб-сайтах. Теперь я хочу, чтобы мои пользователи могли динамически добавлять определения пути для новых веб-сайтов. Возможность использовать только селекторы сделала бы это намного проще. Я думаю, если это невозможно с шипением, мне придется найти решение с XPath. есть идеи? - person modoq; 03.05.2011
comment
@modoq, почему бы не расширить jquery вспомогательной функцией — см. отредактированный ответ? - person VinayC; 03.05.2011
comment
Я хочу, чтобы мои пользователи могли расширить функциональность моего дополнения, предоставив 1.) URL-адрес нового веб-сайта и 2.) путь к определенной части информации на этом сайте. С вашим решением мне нужно было бы либо каким-то образом предоставить им доступ ко всему выражению jQuery (проблема: безопасность, неправильное использование?), либо предоставить какой-то способ «укажи и щелкни» для объединения различных селекторов и вспомогательных функций (сложно реализовать и использовать, поскольку я могут потребоваться другие вспомогательные функции). - person modoq; 03.05.2011
comment
Пытаясь решить эту же проблему, сначала провел немного больше исследований. Да, кажется, что методы обхода jQuery почти всегда пропускают текстовые узлы, не отправляя их в селектор . Единственным исключением является .content(), что не делает вещи более удобными... - person Merlyn Morgan-Graham; 06.12.2011