querySelector, wildcard element match? - javascript

Is there a way to do a wildcard element name match using querySelector or querySelectorAll?
The XML document I'm trying to parse is basically a flat list of properties
I need to find elements that have certain strings in their names.
I see support for wildcards in attribute queries but not for the elements themselves.
Any solution except going back to using the apparently deprecated XPath (IE9 dropped it) is acceptable.

[id^='someId'] will match all ids starting with someId.
[id$='someId'] will match all ids ending with someId.
[id*='someId'] will match all ids containing someId.
If you're looking for the name attribute just substitute id with name.
If you're talking about the tag name of the element I don't believe there is a way using querySelector

I was messing/musing on one-liners involving querySelector() & ended up here, & have a possible answer to the OP question using tag names & querySelector(), with credits to #JaredMcAteer for answering MY question, aka have RegEx-like matches with querySelector() in vanilla Javascript
Hoping the following will be useful & fit the OP's needs or everyone else's:
// basically, of before:
var youtubeDiv = document.querySelector('iframe[src="http://www.youtube.com/embed/Jk5lTqQzoKA"]')
// after
var youtubeDiv = document.querySelector('iframe[src^="http://www.youtube.com"]');
// or even, for my needs
var youtubeDiv = document.querySelector('iframe[src*="youtube"]');
Then, we can, for example, get the src stuff, etc ...
console.log(youtubeDiv.src);
//> "http://www.youtube.com/embed/Jk5lTqQzoKA"
console.debug(youtubeDiv);
//> (...)

Set the tagName as an explicit attribute:
for(var i=0,els=document.querySelectorAll('*'); i<els.length;
els[i].setAttribute('tagName',els[i++].tagName) );
I needed this myself, for an XML Document, with Nested Tags ending in _Sequence. See JaredMcAteer answer for more details.
document.querySelectorAll('[tagName$="_Sequence"]')
I didn't say it would be pretty :)
PS: I would recommend to use tag_name over tagName, so you do not run into interferences when reading 'computer generated', implicit DOM attributes.

I just wrote this short script; seems to work.
/**
* Find all the elements with a tagName that matches.
* #param {RegExp} regEx regular expression to match against tagName
* #returns {Array} elements in the DOM that match
*/
function getAllTagMatches(regEx) {
return Array.prototype.slice.call(document.querySelectorAll('*')).filter(function (el) {
return el.tagName.match(regEx);
});
}
getAllTagMatches(/^di/i); // Returns an array of all elements that begin with "di", eg "div"

i'm looking for regex + not + multiClass selector, and this is what I got.
Hope this help someone looking for same thing!
// contain abc class
"div[class*='abc']"
// contain exact abc class
"div[class~='abc']"
// contain exact abc & def(case-insensitively)
"div[class~='abc'][class*='DeF'i]"
// contain exact abc but not def(case-insensitively)
"div[class~='abc']:not([class*='DeF'i])"
css selector doc: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors
simple test: https://codepen.io/BIgiCrab/pen/BadjbZe

I liked many of the answers above, but I prefer my queries run only on classes/IDs so they don't have to iterate over every element. This is a combination of code from both #bigiCrab and #JaredMcAteer
// class exactly matches abc
const exactAbc = document.querySelectorAll("[class='abc']")
// class begins with abc
const startsAbc = document.querySelectorAll("[class^='abc']")
// class contains abc
const containsAbc = document.querySelectorAll("[class*='abc']")
// class contains white-space separated word exactly matching abc
const wordAbc = document.querySelectorAll("[class~='abc']")
// class ends with abc
const endsAbc = document.querySelectorAll("[class$='abc']")
Substitute "class" with "id" or "href" to get other matches. Read the article linked below for further examples.
Reference:
CSS attribute selectors on MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors

There is a way by saying what is is not. Just make the not something it never will be. A good css selector reference:
https://www.w3schools.com/cssref/css_selectors.asp which shows the :not selector as follows:
:not(selector) :not(p) Selects every element that is not a <p> element
Here is an example: a div followed by something (anything but a z tag)
div > :not(z){
border:1px solid pink;
}

Related

Get element by a word it contains

Is there a way to get an element by its content(a word it contains?)
For example, get all the elements with the letter "F," and put it in a array of elements
I highly recommand you to use jQuery for these kind of DOM elements searching.
Then you can use this:
var foos = $("div:contains('foo')" )
will make an array with all divs containing the word 'foo'.
One fairly easy way is to select the elements you're interested in and then use 'filter' to look at the innerText. You can make this case insensitive with toLowerCase
var result = $('div').filter( (i,e) => e.innerText.toLowerCase().indexOf("f")>-1);
console.log("Items with 'F':",result.length);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>Forest</div>
<div>Fortnight</div>
<div>Trees</div>
<div>Africa</div>
The simpler way is using :contains('F') as a selector - but that is always case sensitive (which may be fine for your case).
You can use :contains as a selector. For example, to filter all divs of a special class that also contains your text, you can use $("div.myclass:contains('searched text')")
I think you can "bruteforce" it by iterating all DOM items. e.g.:
let arrayDom = Array.from(document.getElementsByTagName("*"));
arrayDom.forEach(element => {
if (element.innerHTML.contains('F')){
// Do something
}
})

Javascript RegExp unknown repeated matches

It's difficult to describe because I'm not an expert with regular expressions. So I tell you my case.
In HTML want to contribute class attributes into different data-xyz attributes. The problem is to get always all classes per match. For example the following HTML:
<span class="note-123 index-3 green">Hello</span> <span class="index-456 red">World<span>
Until now my regular expression is /<span class="([^\"\s]*)\s*/ and it matches the first class. In this case note-123 and index-456
But if I want to get all classes per element I could use /<span class="([^\"\s]*)\s*([^\"\s]*)\s*([^\"\s]*)\s*/. That works until three classes and the result for the second class return index-456, red and an empty string.
Is there a possibility to always get all classes per match no matter how many classes there are? Similar to a nested loop in Javascript?
I would be pleased to get any help from you guys.
You could get the classes without using a regex making use of querySelectorAll to find the elements that you want and use classList to get the class names.
Then use for example the add or remove methods.
Or use a DOMParser.
Note to close the last span.
let elms = document.querySelectorAll("span");
elms.forEach(e => {
for (let value of e.classList.values()) {
console.log(value);
}
});
<span class="note-123 index-3 green">Hello</span> <span class="index-456 red">World</span>
Use the regex to extract the value of the class attribute and split it at whitespace sequences:
let as_classes
, as_matches
, n_i
, re_classes
, s_test
;
re_classes = new RegExp ( "<span class=\u0022([^\\u0022]*)", "g" );
s_test = '<span class="note-123 index-3 green">Hello</span> <span class="index-456 red">World<span>';
n_i=0;
while ((as_matches = re_classes.exec(s_test)) !== null) {
n_i++;
s_classes = as_matches[1];
as_classes = s_classes.split(/[\s]+/g);
console.log(`match #${n_i}, classes: ${JSON.stringify(as_classes)}.`);
}
Warning
It is in general never a good approach to extract information from html with regexen.

Can I use the % symbol in javascript or it is considered aspecial character?

I need some help.
I need to know if it is possible to use the % symbol in javascript.
I ask this question because I have an html table with the following ID= MRRMFBSY_%_CEC.
When I try to keep the TD of the second TR of this table the results is undefined, so it seems that it doesnt find the Table with this ID and also when it is defined well.
See my code below:
function getColumnsVal(id) {
var header = $("table#" + id + " thead tr:eq(1)");
var header_fields = $("td", header);
// If ID = MRRMFBSY_%_CEC when I try to do an alert of one of my TD,
// example the firstone it returns undefined
alert(header_fields[0]);
}
The question if you think that the problem is the % symbol or not, because when I have the other ID it works perfectly.
Thanks in advance
% is a reserved character, since its an operator (see).
It's not recommended, but you can use it as ID in an HTML element.
See this example:
const element = document.getElementById('MRRMFBSY_%_CEC');
console.log(element); // returns the div element
<div id="MRRMFBSY_%_CEC">
My div with a specific ID
</div>
ISSUE:
There is a problem when using certain special symbols %, ^, +, #, and so on, inside a jquery selector. They should be escaped with a backslash(\) when used because they are also used in forming the queries for the selector.
For instance '#divid' is a valid string in JavaScript but would be confusing to use in jQuery if the string was an actual id of an element. To get this element you have to use
$('#\#divid').
So, in your case to get your target element, $('#MRRMFBSY_\%_CEC') will get the element easily. However, you can either insert the escape character(\) manually or programmatically as done in this post with regular expression. Therefore, using the square brackets or the native getElementById in this answer, is just another way out of this problem.
You can definitely use % symbol in an id attribute (or in any string) as you would use the dash symbol -. However, you cannot use either of both for JavaScript variable names as they are reserved symbols.
SOLUTION:
Though this question has its own intricacies, #misorude has pointed out a solution here. So there lies your answer. use the square brackets [] or document.getElementById like this.
function getColumnsVal(id) {
// var element = $('[id="' + id + '"]'); // this line is equivalent to the next line.
var element = $(document.getElementById(id));
var header = element.find($("thead tr:eq(1)"));
var header_fields = $("td", header);
// If ID = MRRMFBSY_%_CEC when I try to do an alert of one of my TD,
// example the firstone it returns undefined
alert(header_fields[0]);
}

Select all divs that contains a certain string in class name [duplicate]

Is there a way to do a wildcard element name match using querySelector or querySelectorAll?
The XML document I'm trying to parse is basically a flat list of properties
I need to find elements that have certain strings in their names.
I see support for wildcards in attribute queries but not for the elements themselves.
Any solution except going back to using the apparently deprecated XPath (IE9 dropped it) is acceptable.
[id^='someId'] will match all ids starting with someId.
[id$='someId'] will match all ids ending with someId.
[id*='someId'] will match all ids containing someId.
If you're looking for the name attribute just substitute id with name.
If you're talking about the tag name of the element I don't believe there is a way using querySelector
I was messing/musing on one-liners involving querySelector() & ended up here, & have a possible answer to the OP question using tag names & querySelector(), with credits to #JaredMcAteer for answering MY question, aka have RegEx-like matches with querySelector() in vanilla Javascript
Hoping the following will be useful & fit the OP's needs or everyone else's:
// basically, of before:
var youtubeDiv = document.querySelector('iframe[src="http://www.youtube.com/embed/Jk5lTqQzoKA"]')
// after
var youtubeDiv = document.querySelector('iframe[src^="http://www.youtube.com"]');
// or even, for my needs
var youtubeDiv = document.querySelector('iframe[src*="youtube"]');
Then, we can, for example, get the src stuff, etc ...
console.log(youtubeDiv.src);
//> "http://www.youtube.com/embed/Jk5lTqQzoKA"
console.debug(youtubeDiv);
//> (...)
Set the tagName as an explicit attribute:
for(var i=0,els=document.querySelectorAll('*'); i<els.length;
els[i].setAttribute('tagName',els[i++].tagName) );
I needed this myself, for an XML Document, with Nested Tags ending in _Sequence. See JaredMcAteer answer for more details.
document.querySelectorAll('[tagName$="_Sequence"]')
I didn't say it would be pretty :)
PS: I would recommend to use tag_name over tagName, so you do not run into interferences when reading 'computer generated', implicit DOM attributes.
I just wrote this short script; seems to work.
/**
* Find all the elements with a tagName that matches.
* #param {RegExp} regEx regular expression to match against tagName
* #returns {Array} elements in the DOM that match
*/
function getAllTagMatches(regEx) {
return Array.prototype.slice.call(document.querySelectorAll('*')).filter(function (el) {
return el.tagName.match(regEx);
});
}
getAllTagMatches(/^di/i); // Returns an array of all elements that begin with "di", eg "div"
i'm looking for regex + not + multiClass selector, and this is what I got.
Hope this help someone looking for same thing!
// contain abc class
"div[class*='abc']"
// contain exact abc class
"div[class~='abc']"
// contain exact abc & def(case-insensitively)
"div[class~='abc'][class*='DeF'i]"
// contain exact abc but not def(case-insensitively)
"div[class~='abc']:not([class*='DeF'i])"
css selector doc: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors
simple test: https://codepen.io/BIgiCrab/pen/BadjbZe
I liked many of the answers above, but I prefer my queries run only on classes/IDs so they don't have to iterate over every element. This is a combination of code from both #bigiCrab and #JaredMcAteer
// class exactly matches abc
const exactAbc = document.querySelectorAll("[class='abc']")
// class begins with abc
const startsAbc = document.querySelectorAll("[class^='abc']")
// class contains abc
const containsAbc = document.querySelectorAll("[class*='abc']")
// class contains white-space separated word exactly matching abc
const wordAbc = document.querySelectorAll("[class~='abc']")
// class ends with abc
const endsAbc = document.querySelectorAll("[class$='abc']")
Substitute "class" with "id" or "href" to get other matches. Read the article linked below for further examples.
Reference:
CSS attribute selectors on MDN: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors
There is a way by saying what is is not. Just make the not something it never will be. A good css selector reference:
https://www.w3schools.com/cssref/css_selectors.asp which shows the :not selector as follows:
:not(selector) :not(p) Selects every element that is not a <p> element
Here is an example: a div followed by something (anything but a z tag)
div > :not(z){
border:1px solid pink;
}

Complex jquery selector that looks for a token in a string.split

I have an html table where one of the columns contains <span>s with comma-delimited data. I want to come up with a jQuery selector that returns all of the rows (<tr>s are preferable, but the <span>s will work for now) where one of the comma-delimited tokens <span> in a span tag matches a supplied string.
I started with something like the following:
$('td.col_8 span:contains("duck")')
which will get me all spans in a particular column containing the word 'duck'. However, it could also match <span>fox, mallard-duck</span>. Since 'duck' is not a unique token in that span, I wouldn't want that included in the match.
Is there a way to narrow my result set so I'm only including results where there's an exact match to a particular token in a column-delimited list?
(I'm using jQuery 1.2.3)
This is where the beauty of jQuery expressions come in.
You can add your own custom selector. I'm going to call it tag in this case
jQuery.expr[":"].tag = function(elem, index, match, nodeList) {
var tags = $(elem).text().replace(/(?:\ +)?,(?:\ +)?/g, ",").split(",");
return tags.indexOf(match[3]) > -1;
}
This will check each previously matched element against this selector. Fist it flattens the , seperations (so something like "firstTag , onotherer, badly , spaced, tag" will work). jQuery already takes care of parsing the selector and passes it in as match. match[3] is what you're interested in. With the following usage match[3] will be 'duck'
$('td.col_8 span:tag("duck")')
the return line will return true of false based on the tag being in the list.
I think this should do it
$('td.col_8 span').filter(function() {
return $(this).text().match(/^duck$/);
});
Now you just need to define the regex that you need, or implement a string split and array search to return a boolean value to indicate if the <span> should be included.
Going off of Russ Cam's answer, here's what I came up with:
$('td.col_8 span').filter(function() {
return $.inArray('quiet',$(this).html().split(', ')) !== -1;
});
Of course, this assumes that the list will always be delimited with ,[space], but it should work for my immediate use case.

Categories

Resources