I have the following element stored as a String:
<div class="some-class" id="my-id" data-theme="black">
<strong data-animation="fade" disabled>Hello world!</strong>
</div>
I want to extract all the attributes names like this:
["class", "id", "data-theme", "data-animation", "disabled"]
This is what I tried to do, but I get also the values and dosent match the data-animation and disabled:
http://jsbin.com/hibebezibo/edit?js,console
EDIT:
Manged to get attributes using:
[\w-]+(?=\s*=\s*".*?")
But I still cant get the "disabled" prop.
Can someone explain me how to achieve this?
Thanks!
Using below regex which benefits from a positive lookahead you are able to match attributes' names:
[ ][\w-]+(?=[^<]*>)
Note: Adding - to character class is a must.
javascript code:
const HtmlElement = `<div class="some-class" id="my-id" data-theme="black">
<strong data-animation="fade" disabled>Hello world!</strong>
</div>`
console.log(HtmlElement.match(/ [\w-]+(?=[^<]*>)/g).map(function(element) {
return element.trimLeft();
}));
However it's not bulletproof as it can match words following a >. E.g:
<strong data-animation="fade" disabled>Hello world!></strong>
So it's recommended to accomplish such a task using DOM functionalities:
var html = document.createElement('div');
html.innerHTML = '<div class="some-class" id="my-id" xlink:href data-theme="black"><strong data-animation="fade" disabled>Hello world!</strong></div>';
var attrNodes = document.evaluate('//*/attribute::*', html, null, XPathResult.ANY_TYPE, null)
var nextAttrNode = attrNodes.iterateNext()
var arrAttrs = [];
while (nextAttrNode) {
arrAttrs.push(nextAttrNode.name)
nextAttrNode = attrNodes.iterateNext();
}
console.log(arrAttrs)
This works on even nested structure.
It returns element name and its attributes
\<([^\/\>"]+)\s{1,}([^"]+)=\"[^"]*\"
Test your own regex on https://regex101.com
Related
I would like to get the value of the href i.e. the web link using the data attribute.
I have the following snippet of code
<div class="my-item-details">
<h3 class="my-item-title" data-item_item="x12">
<a href="http://link.com">
My Classic Box
</a>
</h3>
<span class="my-item-price" data-item_item="x12">
38.00
</span>
</div>
The following 2 snippets give the right output.
var price_val = $('.my-item-price[data-item_uuid=x12]').text();
price_val = $.trim(price_val)
console.log(price_val);
38.00
var item_name = $('.my-item-title[data-item_uuid=x12]').text();
item_name = $.trim(item_name)
console.log(item_name);
My Classic Box
However when I run this code
var item_link = $('.my-item-title[data-item_uuid=x12]').attr("href");
item_link = $.trim(item_link)
console.log(item_link);
I get an empty string instead of http://link.com
What am I missing?
.my-item-title[data-item_uuid=x12] selects the h3 element, which doesn't have an href attribute.
Only the a element has that.
Add a descendant combinator and a type selector:
.my-item-title[data-item_uuid=x12] a
You are trying to get the attribute href from a <h3> element without href property:
You could make a change on your selector this way to get the correct result:
var item_link = $('.my-item-title[data-item_uuid=x12] > a').attr("href");
This should give you the correct value.
I have some markup in JS as follows:
<div class="col-sm-4">
<span id="some-media" class="media">Text</span>
</div>
I would like to select the class attribute of the span and prepend its value with lets say the characters: "::". So after the regex replace i would end up with:
<div class="col-sm-4">
<span id="some-media" class="::media">Text</span>
</div>
EDIT: Note that the order of the attributes in the HTML element is variable so my span attributes could very well have different order like so:
<div class="col-sm-4">
<span class="::media" id="some-media" >Text</span>
</div>
You got a regex solution, this is a DOMmy one:
var html = `<div class="col-sm-4">
<span id="some-media" class="media">Text</span>
</div>`
var doc = (new DOMParser()).parseFromString(html, "text/html");
var el = doc.getElementsByTagName('span')[0];
el.setAttribute('class', '::' + el.className);
console.log(
doc.getElementsByClassName('::media').length > 0 // check if modification's done
);
Since you have no way except Regular Expressions this can be considered as a workaround:
(<span[^>]*class=.)([^'"]+)
JS:
var html = `<div class="col-sm-4">
<span id="some-media" class="media">Text</span>
</div>
<span class="media" id="some-media">Text</span>
`;
console.log(
html.replace(/(<span[^>]*class=.)([^'"]+)/g, `$1::$2`)
);
This isn't using regex, but you can do it like this in vanilla JavaScript:
const el = document.getElementsByClassName('media')[0];
el.className = '::' + el.className;
Or in jQuery:
const $el = $('div span.media');
$el.attr('class', '::' + $el.attr('class'));
Hope this helps.
Don't parse html with regex, use DocumentFragment (or DOMParser) object instead:
var html_str = '<div class="col-sm-4"><span class="media">Text</span></div>',
df = document.createRange().createContextualFragment(html_str),
span = df.querySelector('span');
span.setAttribute('class', '::' + span.getAttribute('class'));
console.log(df.querySelector('div').outerHTML);
I think this is what you're after:
var test = $("#some-media")[0].outerHTML();
var test2 = '<div id="some-media" class="media">Text</div>'
if(/span/.test(test)) //Valid as contains 'span'
alert(test.replace(/(class=")/g, "$1::"));
if(/span/.test(test2)) //Not valid
alert(test.replace(/(class=")/g, "$1::"));
Since the order differs, writing a regex that captures all possible combinations of syntax might be rather difficult.
So we'd need a full list of rules the span follows so we can identify that span?
Got some more info about if the span occurs in a longer HTML string? Or is the string this span and this span only?
An alternative would be to use one of the several node DOM modules available, so you can work with HTML nodes and be able to use any of the above solutions to make the problem simpler.
But since you're using node:
1) Are you using any templating engines? If so, why not rerender the entire template?
2) Why does the class name have to change on the server side? Isn't there a workaround on the clientside where you do have access to the DOM natively? Or if it's just to add styling, why not add another css file that overwrites the styling of spans with className 'media'?
3) If all of the above is not applicable and it;s a trivial problem like you say, what error di you get using a simple replace?
strHTML.replace( 'class="media"', 'class="::media"' )
or if it has to be regex:
strHTML.replace( /class=\"(.*)\"/, 'class=\"::$1\"' );
While doing example of JSON, I found that values are overwritten. I want to generate a div for each value but how?
Javascript code:
<script>
var txt = '{"employees":[' +
'{"firstName":"John","lastName":"Doe","nationality":"Pakistani","Age":"24","Salary":"40000" },' +
'{"firstName":"Anna","lastName":"Smith","nationality":"USA","Age":"24","Salary":"40000" },' +
'{"firstName":"Peter","lastName":"Jones","nationality":"UK","Age":"24","Salary":"40000" }]}';
window.onload = function(){
for(var i = 0 ; i< 3 ; i++){
var obj = eval ("("+ txt +")");
document.getElementById("fname").innerHTML=obj.employees[i].firstName;
document.getElementById("lname").innerHTML=obj.employees[i].lastName;
document.getElementById("nationality").innerHTML=obj.employees[i].nationality;
document.getElementById("Age").innerHTML=obj.employees[i].Age;
document.getElementById("Salary").innerHTML=obj.employees[i].Salary;}
}
</script>
Html body:
<div>
<p>
First Name: <span id="fname"></span><br />
Last Name: <span id="lname"></span><br />
Nationality: <span id="nationality"></span><br />
Age: <span id="Age"></span><br />
Salary: <span id="Salary"></span><br />
</p>
</div>
What you are trying to do is typically done through templates. You should look into the new HTML5 template element, which makes the work of templating your data super easy.
Ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template
In your case, just JSON.parse the string to obtain the object array from the text, and then loop through it. With each iteration, clone (copy) the template into an element, replace the fields using an appropriate query selector and append to the document.
Demo: http://jsfiddle.net/abhitalks/VNtdU/1/
Relevant HTML:
<template id="mytemplate">
<div>
<p>
First Name: <span class="fname"></span><br />
Last Name: <span class="lname"></span><br />
...
</template>
Relevant Javascript:
var list = JSON.parse(txt);
list.employees.forEach(function(obj) {
var template = document.getElementById('mytemplate').content.cloneNode(true);
template.querySelector('.fname').innerText = obj.firstName;
template.querySelector('.lname').innerText = obj.lastName;
template.querySelector('.nationality').innerText = obj.nationality;
template.querySelector('.age').innerText = obj.Age;
template.querySelector('.salary').innerText = obj.Salary;
document.body.appendChild(template);
});
Where:
txt is the your json string (same as in your question)
It's preferable to use classes instead of id, otherwise your id gets duplicated and will no longer be unique.
You could also use document.importNode alternatively to content.cloneNode
The true parameter to cloneNode or importNode means deep copy, indicating whether the descendants of the imported node need to be imported.
Important:
template is an HTML5 addition (candidate recommendation) and currently is not supported in IE. Support in Safari is also flaky. Hence, use it carefully.
You may check the support at runtime by:
if ('content' in document.createElement('template')) {...
Aside:
Mostly, script element is also used in the similar way as above:
<script id="mytemplate" type="text/template">...
I have the following string :
var str='
<span class="productName">Basa fillets</span><br>
Brand:
<span class="brandName">COMPLIMENTS</span><br>
400 <abbr title="Gram" lang="en">gr</abbr>
'
I need to get the '400' (could be a word,or even a sentence).
What I have so far is :
d = str.replace(/<br>/g,'').replace(/<.*<\/.*>/g,'').replace(/\n/g,'').replace(/ */g,'').replace(/brand:/i,'');
It works but... well, I'm sure I can do better. i have plenty of similar queued replace in my code, and I'd like to know how to improve that so i'm more looking for a general answer than a particular solution.
Thanks!
Instead of using string tools/regex on this, you can use DOM methods on it (it is HTML).
First you make a "fake" div and add the HTML to it.
var str="\
<span class=\"productName\">Basa fillets</span><br>\
Brand: \
<span class=\"brandName\">COMPLIMENTS</span><br>\
400 <abbr title=\"Gram\" lang=\"en\">gr</abbr>\
";
var fakeDiv = document.createElement('div');
fakeDiv.innerHTML = str;
Then just use normal DOM traversal methods to get the node you need. There are many ways to get to the element, depending on your HTML.
var brandName = fakeDiv.getElementsByClassName('brandName');
var textNode = brandName[0].nextSibling.nextSibling;
console.log(textNode.nodeValue.trim());
DEMO: http://jsfiddle.net/aqpgV/
Or, you can start from the <abbr> element and work backwards.
var gram = fakeDiv.getElementsByTagName('abbr');
var textNode = gram[0].previousSibling;
console.log(textNode.nodeValue.trim());
DEMO: http://jsfiddle.net/aqpgV/1/
However you traverse it is up to you :-)
Regex
class="brandName">[^<]+</span><br>[^\w]+([^<]+) <abbr title=
Debuggex Demo
Notes: Group 1 will contain the item you want.
If you wanted to use regex, you could do something like this.
var str="\
<span class=\"productName\">Basa fillets</span><br>\
Brand: \
<span class=\"brandName\">COMPLIMENTS</span><br>\
400 <abbr title=\"Gram\" lang=\"en\">gr</abbr>\
";
var myRegexp = /COMPLIMENTS<\/span><br>\W(.*?) <abbr /g;
var match = myRegexp.exec(str);
alert(match[1]);
Am now facing an other challenge. Some parts of my html code has the following lines:
<div class="action-body flooded"><p>(In <span class="error">[82681]</span>) refs AGLBD-16096<br/></div>
I have to get the number with-in the [] and then replace it with a hyperlink. I have tried using document.getElementsByClassName('error') but its not working. how can I make it work? and i would also need to iterate in a loop to replace all such numbers if there are more than one in []. e.g: [123] [234] [345]...
This is all what I have written till now with pimvdb's help:
<script type="text/javascript">
var bodyText = document.getElementById('body').innerHTML;
var pattern = /\[.*?\]/g;
var replaceText = "Pradeep";
document.getElementById('body').innerHTML = bodyText.replace(pattern, replaceText);
</script>
This JSFiddle does what you need: http://jsfiddle.net/TNyms/
When you replace getElementById('body') with document.body, the code works for me.
var body = document.body;
var link = "Pradeep";
body.innerHTML = body.innerHTML.replace(/\[.*?\]/g, link);
That replaces all IDs in this with links:
<div class="action-body flooded">
<p>(In
<span class="error">[82681]</span>) refs
AGLBD-16096
<br/>
</div>
<div>[123][abcd]</div>
<div>[456]</div>
<div>[789]</div>
Outputs:
(In Pradeep) refs AGLBD-16096
PradeepPradeep
Pradeep
Pradeep
Try it with this fiddle.
Your question appears to be related to what is asked in the below link. You may refer this
Replace number in a string using regex or something else