I had a quick question regarding RegEx...
I have a string that looks something like the following:
"This was written by <p id="auth">John Doe</p> today!"
What I want to do (with javascript) is basically extract out the 'John Doe' from any tag with the ID of "auth".
Could anyone shed some light? I'm sorry to ask.
Full story:
I am using an XML parser to pass data into variables from a feed. However, there is one tag in the XML document () that contains HTML passed into a string. It looks something like this:
<item>
<title>This is a title</title>
<description>
"By <p id="auth">John Doe</p> text text text... so on"
</description>
</item>
So as you can see, I can't use an HTML/XML parser for that p tag, because it's in a string, not a document.
Here's a way to get the browser to do the HTML parsing for you:
var string = "This was written by <p id=\"auth\">John Doe</p> today!";
var div = document.createElement("div");
div.innerHTML = string; // get the browser to parse the html
var children = div.getElementsByTagName("*");
for (var i = 0; i < children.length; i++)
{
if (children[i].id == "auth")
{
alert(children[i].textContent);
}
}
If you use a library like jQuery, you could hide the for loop and replace the use of textContent with something cross-browser.
No need of regular expressions to do this. Use the DOM instead.
var obj = document.getElementById('auth');
if (obj)
{
alert(obj.innerHTML);
}
By the way, having multiples id with the same value in the same page is invalid (and will surely result in odd JS behavior).
If you want to have many auth on the same page use class instead of id. Then you can use something like:
//IIRC getElementsByClassName is new in FF3 you might consider using JQuery to do so in a more "portable" way but you get the idea...
var objs = document.getElementsByClassName('auth');
if (objs)
{
for (var i = 0; i < objs.length; i++)
alert(obj[i].innerHTML);
}
EDIT: Since you want to parse a string that contain some HTML, you won't be able to use my answer as-iis. Will your HTML string contain a whole HTML document? Some part? Valid HTML? Partial (broken) HTML?
Perhaps something like
document.getElementById("auth").innerHTML.replace(/<^[^>]+>/g, '')
might work. innerHTML is supported on all modern browsers. (You may omit the replace if you don't care about removing HTML bits from the inner content.)
If you have jQuery at your disposal, just do
$("#auth").text()
What I want to do (with javascript) is
basically extract out the 'John Doe'
from any tag with the ID of "auth".
You can't have the same id (auth) for more than one element. An id should be assigned once per element per page.
If, however, you assign a class of auth to elements, you can go about something like this assuming we are dealing with paragraph elements:
// find all paragraphs
var elms = document.getElementsByTagName('p');
for(var i = 0; i < elms.length; i++)
{
// find elements with class auth
if (elms[i].getAttribute('class') === 'auth') {
var el = elms[i];
// see if any paragraph contains the string
if (el.innerHTML.indexOf('John Doe') != -1) {
alert('Found ' + el.innerHTML);
}
}
}
Assuming you only have 1 auth per string, you might go with something like this:
var str = "This was written by <p id=\"auth\">John Doe</p> today!",
p = str.split('<p id="auth">'),
q = p[1].split('</p>'),
a = q[0];
alert(a);
Simple enough. Split your string on your paragraph, then split the second part on the paragraph close, and the first part of the result will be your value. Every time.
If the content of the tag contains only text, you could use this:
function getText (htmlStr, id) {
return new RegExp ("<[^>]+\\sid\\s*=\\s*([\"'])"
+ id
+ "\\1[^>]*>([^<]*)<"
).exec (htmlStr) [2];
}
var htmlStr = "This was written by <p id=\"auth\">John Doe</p> today!";
var id = "auth";
var text = getText (htmlStr, id);
alert (text === "John Doe");
Related
I have a string containing names which could be dynamic(1 or more).....i want to convert those names to hyperlinks...and those hyperlinks will contain those names ..
eg. In string "john,jim,jean".....john will be hyperlinked and redirects to "www.abc.com/john" and so on......
I have already accessed the elements by jquery using....as the are inside elements i used .children().text() the split and save them in regs[]
<label>Ids: <span> john,jim,jean</span></label>
var strr=$('label:contains("IDs:")').children().text();
var regs = strr.split(",")
var reg_length = regs.length;
I dont want to change the text in html, just want to convert them in hyperlinks.
like when click on john will redirect towww.abc.com/john and so on the others name.
without changing the visible string john,jim,jean
i see you used jquery, so i will also
regs = regs.map( s => $(`<a href='www.abc.com/${s}'>${s}</a>`) )
uses map to create the elements from each item of the array, with the help of string templates and jquery.
I hope this is what you are looking for
let spanDom = $("label").find("span");
let str = $(spanDom).text().trim();
let s = str.split(",");
$(spanDom).empty();
s.forEach(function( name ) {
$(spanDom).append("<a href='www.abc.com/"+name+"'>"+name+"</a>,");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<label>Ids: <span> john,jim,jean</span></label>
try
let w = ["john", "jim", "jean" ]; // list of known words to link
data.innerHTML = data.innerHTML.replace(/\w+/g,
x=> w.includes(x) ? `${x}` : x)
<label id='data'>Ids: <span> john,jim,jean</span></label>
This is totally achievable provided your strings follow a common separation pattern like a comma (,) or a space. I'll assume that your names in the string are separated by commas and spaces ", " I'll show it without jQuery.
Firstly the <span> element containing the string needs to have an ID. Also, I'm adding a <p> as a placeholder for the hyperlinks.
<span id="names">John, Jim, Jean </span>
<p id="hps"></p>
Now the JavaScript:
nameString = document.getElementById("names").innerHTML; //get the string from <span>
nameArray = nameString.split(", ");
//This method will take the string and break it down wherever it finds the occurrence of the argument (here ", ") and remove these characters and the individual broken down strings are returned as an array
//nameArray has all the names stored in an array
//Let's create an array links that will hold all your <a> elements
links = new Array();
len = nameArray.length; //Get the length of the array i.e. number of names
for (i = 0; i < len; i++) {
links[i] = document.createElement("a"); //create an <a> tag
links[i].setAttribute("href", "www.abc.com/"+nameArray[i]); //Set its href
links[i].innerHTML = nameArray[i]; //Add Link names i.e. contents inside <a></a>
document.getElementById("hps").appendChild(links[i]); //append these links as childs to the <p> parent tag
}
Hi guys i got an <a> tag which look like this:
<a class="js-swatch-item-link swatch__item-inner-image" data-layer-click="{"event":"interaction","interaction":{"category":"colorPattern","action":"Select","label":"DARK GREY MELANGE","value":"DARK GREY MELANGE"}}}" href="#">DARK GREY MELANGE</a>
I am trying to fetch the value of the interaction section of the JSON string, and then afterwards assigning this value to the innerHTML of the <a> tag.
My JavaScript code looks like this:
var SWATCH_COLOR_LINK = '.swatch.colorpattern a';
var swatchColorLink = document.querySelectorAll(SWATCH_COLOR_LINK);
var swatchColorTitle = JSON.parse(swatchColorLink.getAttribute('data-layer-click')).interaction.value;
for (var i = 0; i < swatchColorLink.length; i++) {
swatchColorLink[i].innerHTML = swatchColorTitle;
}
The function is giving me the following error: swatchColorLink.getAttribute is not a function
However if I try to just select the first element like this: document.querySelectorAll(SWATCH_COLOR_LINK)[0]
The function works fine and sets the right value from the JSON string to the innerHTML of the <a> tag.
Im guessing im doing something wrong in my loop to go over all <a> tags and assigning them the value of their JSON string.
Your mistake is laying in swatchColorLink.getAttribute(). Because your swatchColorLink's value is a NodeList which is returned from querySelectorAll() method. When you are doing document.querySelectorAll(SWATCH_COLOR_LINK)[0] you are getting the first element from this NodeList so in this case your swatchColorLink is the single node.
var SWATCH_COLOR_LINK = '.swatch.colorpattern a';
var swatchColorLink = document.querySelectorAll(SWATCH_COLOR_LINK);
for (var i = 0; i < swatchColorLink.length; i++) {
var swatchColorTitle = JSON.parse(swatchColorLink[i].getAttribute('data-layer-click')).interaction.value;
swatchColorLink[i].innerHTML = swatchColorTitle;
}
Correct your JSON string {"event":"interaction","interaction":{"category":"colorPattern","action":"Select","label":"DARK GREY MELANGE","value":"DARK GREY MELANGE"}}}
you should escape the quotes " in the string and remove the last }
<a class="js-swatch-item-link swatch__item-inner-image" data-layer-click="{\"event\":\"interaction\",\"interaction\":{\"category\":\"colorPattern\",\"action\":\"Select\",\"label\":\"DARK GREY MELANGE\",\"value\":\"DARK GREY MELANGE\"}}"href="#">DARK GREY MELANGE</a>
Assuming I have the following:
var s = "This is a test of the battle system."
and I had an array:
var array = [
"is <b>a test</b>",
"of the <div style=\"color:red\">battle</div> system"
]
Is there some function or way I could make it such that I can process the string s such that the output would be:
var p = "This is <b>a test</b> of the <div style=\"color:red\">battle</div> system."
Based on the arbitrary elements in the array?
Note that the array elements should be executed in sequence. So looking at the first element in array 1, find the correct place to "replace" in string "s". Then looking at array element 2, find the correct place to "replace" in string "s".
Note that the string could contain numbers, brackets, and other characters like dashes (no <> though)
Update: after Colin DeClue's remark I think you want to do something different than I originally thought.
Here is how you can accomplish that
//your array
var array = [
"is <b>a test</b>",
"of the <div style=\"color:red\">battle</div> system"
];
//create a sample span element, this is to use the built in ability to get texts for tags
var cElem = document.createElement("span");
//create a clean version of the array, without the HTML, map might need to be shimmed for older browsers with a for loop;
var cleanArray = array.map(function(elem){
cElem.innerHTML = elem;
return cElem.textContent;
});
//the string you want to replace on
var s = "This is a test of the battle system."
//for each element in the array, look for elements that are the same as in the clean array, and replace them with the HTML versions
for(var i=0;i<array.length;i++){
var idx;//an index to start from, to avoid infinite loops, see discussion with 6502 for more information
while((idx = s.indexOf(cleanArray[i],idx)) > -1){
s = s.replace(cleanArray[i],array[i]);
idx +=(array[i].length - cleanArray[i].length) +1;//update the index
}
}
//write result
document.write(s);
Working example: http://jsbin.com/opudah/9/edit
Original answer, in case this is what you meant after all
Yes. Using join
var s = array.join(" ");
Here is a working example in codepen
I suppose you've an array of original --> replacement pairs.
To extract the text from an HTML a trick that may work for you is actually creating a DOM node and then extract the text content.
Once you have the text you can use the replace method with a regular expression.
One annoying thing is that searching for an exact string is not trivial because there is no escape predefined function in Javascript:
function textOf(html) {
var n = document.createElement("div");
n.innerHTML = html;
return n.textContent;
}
var subs = ["is <b>a test</b>",
"of the <div style=\"color:red\">battle</div> system"];
var s = "This is a test of the battle system"
for (var i=0; i<subs.length; i++) {
var target = textOf(subs[i]);
var replacement = subs[i];
var re = new RegExp(target.replace(/[\\[\]{}()+*$^|]/g, "\\$&"), "g");
s = s.replace(re, replacement);
}
alert(s);
var text='<div id="main"><div class="replace">< **My Text** ></div><div>Test</div></div>'
I want to replace div with class="replace" and html entities < > comes inside that div with some other text.
I.e the output :
'<div id="main"> Hello **My Text** Hello <div>Test</div> </div>'
I've tried
var div = new RegExp('<[//]{0,1}(div|DIV)[^><]*>', 'g');
text = text.replace(div, "Hello");
but this will replace all div.
Any help gratefully received!
If a Jquery solution is acceptable:
text = $(text) // Convert HTML string to Jquery object
.wrap("<div />") // Wrap in a container element to make...
.parent() // the whole element searchable
.find("div.replace") // Find <div class="replace" />
.each(function() // Iterate over each div.replace
{
$(this)
.replaceWith($(this).html() // Replace div with content
.replace("<", "<sometext>")
.replace(">", "</sometext>")); // Replace text
})
.end().html(); // return html of $(text)
This sets text to:
<div id="main"><sometext> My Text </sometext><div>Test</div></div>
And to replace it back again:
text = text.replace('<sometext>', '<div class="replace"><')
.replace('</sometext>', '></div>');
http://api.jquery.com/jquery/#jQuery2
http://api.jquery.com/each/
http://api.jquery.com/find/
http://api.jquery.com/html/
In pure JS it will be something like this:
var elements = document.getElementsByClassName('replace');
var replaceTag = document.createElement('replacetext');
for (var i = elements.length - 1; i >= 0; i--) {
var e = elements[i];
e.parentNode.replaceChild(replaceTag, e);
};
Here is one crazy regex which matches what you want:
var text='<div id="main"><div class="replace">< **My Text** ></div><div>Test</div></div>'
var r = /(<(div|DIV)\s+class\s*?=('|")\s*?replace('|")\s*?>)(\s*?<)(.*?)(>\s*?)(<\/(div|DIV)\s*?>)/g;
The whole replacement can be made with:
text.replace(r, function () {
return 'Hello' + arguments[6] + 'Hello';
});
Please let me know if there are issues with the solution :).
Btw: I'm totally against regexes like the one in the answer...If you have made it with that complex regex there's probably better way to handle the problem...
Consider using the DOM instead; you already have the structure you want, so swap out the node itself (borrowing heavily from #maxwell's code, but moving children around as well):
var elements = document.getElementsByClassName('replace');
for(var i = elements.length-1; i>= 0; --i) {
var element = elements[i];
var newElement = document.createElement('replacetext');
var children = element.childNodes;
for(var ch = 0; ch < children.length; ++i) {
var child = children[ch];
element.removeChild(child);
newElement.appendChild(child);
}
element.parentNode.insertBefore(newElement,element);
element.parentNode.removeChild(element);
}
For each element of the given class, then, it will move each of its children over to the new element before using that element's position to insert the new element and finally removing itself.
My only questionmark is whether the modification of items in the array return by getElementByClassName will cause problems; it might need an extra check to see if the element is valid before processing it, or you may prefer to write this as a recursive function and process the tree from deepest node first.
It may seem like more work, but this should be faster (no re-parsing of the html after you've changed it, element moves are just reference value assignments) and much more robust. Attempting to parsing HTML may damage your health.
Rereading the question (always a good plan), you begin with the text in a string. If that is truly the start point (i.e. you're not just pulling that out of an innerHTML value), then to use the above just create a temporary parent element:
var fosterer = document.createElement('div');
fosterer.innerHTML = text; // your variable from the question
And then proceed using fosterer.getElementsByClassName.
Note: I do NOT want to use any framework.
The goal is just to create a function that will return an element based on an HTML string.
Assume a simple HTML Document like such:
<html>
<head></head>
<body>
</body>
</html>
All functions mentioned are in included the head section and all DOM creation/manipulation is done at the end of the body in a script tag.
I have a function createElement that takes a well formed HTML String as an argument. It goes like this:
function createElement(str)
{
var div = document.createElement('div');
div.innerHTML = str;
return div.childNodes;
}
Now this functions works great when you call it like such:
var e = createElement('<p id="myId" class="myClass">myInnerHTML</p>');
With the minor (possibly HUGE) problem that the element created isn't a 'true' element, it still has a parentNode of 'div'. If anyone knows how to fix that, then that would be awesome.
Now if I call the same function with a more complex string:
var e = createElement('<p id="myId" class="myClass">innerHTML<h2 id="h2ID" class="h2CLASS">Heading2</h2></p>');
It creates TWO children instead of ONE child with another child having another child.Once you do div.innerHTML = str. The innerHTML instead of
`<p id="myId" class="myClass">innerHTML <h2 id="h2ID" class="h2CLASS">Heading2</h2> </p>`
turns to
`<p id="myId" class="myClass">innerHTML</p> <h2 id="h2ID" class="h2CLASS">Heading2</h2>`
Questions:
Can I somehow get an element without a parent node after using .innerHTML?
Can I (in the case of the slightly complex string) get my function to return ONE element with the appropriate child instead of two elements. [It actually returns three, <p.myClass#myId>,<h2.h2CLASS#h2ID>, and another <p>]
This is similar to the answer from palswim, except that it doesn't bother with creating a clone, and uses a while() loop instead, always appending the node at [0].
function createElement( str ) {
var frag = document.createDocumentFragment();
var elem = document.createElement('div');
elem.innerHTML = str;
while (elem.childNodes[0]) {
frag.appendChild(elem.childNodes[0]);
}
return frag;
}
You'd have to attach the new element somewhere. Try using a DocumentFragment object in conjunction with the div you created:
function createElement(str) {
var div = document.createElement('div');
div.innerHTML = str;
var container = document.createDocumentFragment();
for (var i=0; i < div.childNodes.length; i++) {
var node = div.childNodes[i].cloneNode(true);
container.appendChild(node);
}
return container.childNodes;
}
It's more overhead, but it does what you want. Note that DOM elements' .insertAdjacentHTML member function is coming in HTML5.
For that complex string you passed, it isn't valid XHTML syntax - you can't have a block element as a child of <p> (<h2> is a block level element).