问题
I would like to extract text from a DOM element using a jQuery custom selector. It should only select the text node without it's tagged siblings (much like /text() in XPath).
Background: I am working on a Firefox extension, that extracts some specific information (e.g. a username) on very different websites. Now I want my users to be able to dynamically add path definitions for new websites over a form as simple as possible:
Add new Website:
URL: ________________ (e.g. "http://stackoverflow.com/questions/")
Path: ________________ (e.g. ".user-details>a:eq(0)" for the name of the user asking a question)
On stackoverflow for instance, $(path).text() will return the username as text. But on some other sites the username is available only as text node with tagged siblings, as in this example:
<div id="person">
johndoe <span id="age">(57)</span>
<span id="description">Lorem ipsum dolor sit amet…</span>
</div>
Since jQuery doesn't provide a selector for text nodes (like /text() in XPath), I was hoping to find a solution creating a custom selector.
I know how to get the text node the 'non-selector' way:
var textNode = $('#person').contents().filter(function(){
return this.nodeType == 3;
}).text();
alert(textNode); // gives me "johndoe"
How would I translate this into a custom selector? The following obviously doesn't work, since it always returns the complete element as soon as one part of it is a text node (as @VinayC explains in his answer):
$.extend($.expr[':'],{
getText: function(element){
return $(element).contents().filter(function() {return this.nodeType == 3;}).text();
}
});
alert($('#person:getText')); //returns the whole DIV element
See my jsfiddle
Maybe it's not possible to do this with jQuery custom selectors. That's why I'm thinking about going 'back' to XPath which seems more versatile.
Thanks for your help.
回答1:
What you are doing is to create a jquery selector and the selector function is supposed to return boolean to indicate if the passed node has matched or not. So your current function returns a "true" for "#person" div ((actual return value is text within div which is non-empty and hence considered as true) and hence you get the div element as result.
You may try getText: function(node){ return node.nodeType == 3;}
but this will work only jquery engine passes all document nodes including text nodes via selector functions (I am unaware if it does or does not). Alternate is to create an helper function instead of custom selector.
EDIT: how about extending jquery object? For example,
$.fn.extend({
getText: function() {
return this.contents().filter(function() {return this.nodeType == 3;}).text();
}
});
alert($('#person').getText());
来源:https://stackoverflow.com/questions/5866763/jquery-custom-selector-for-text-nodes