Here's my XML
<?xml version="1.0" encoding="ISO-8859-1" ?>
<book>
<title>My Title</title>
<description></description>
<chapter>
<title>Chapter 1</title>
<description>text inside chapter</description>
</chapter>
</book>
So I try to get information INSIDE the <chapter> tag
here's my code :
function afficheTitres(doc) {
Items = doc.getElementsByTagName("chapter");
elementol = document.createElement("ol");
var longueur = Items.length;
for ( k = 0; k < longueur ; ++k) {
elementli = document.createElement("li");
x=doc.getElementsByTagName("title")[k];
var longueurtitre = x.length;
y=x.childNodes[0];
txt=y.nodeValue;
test = document.createTextNode(txt)
elementli.appendChild( test);
elementretour = document.createElement('br');
elementli.appendChild( elementretour
);
descript=doc.getElementsByTagName("description")[k];
descriptNode=descript.childNodes[0];
txt2=descriptNode.nodeValue;
test2 = document.createTextNode(txt2)
elementli.appendChild( test2);
elementol.appendChild(elementli);
}
body = document.getElementsByTagName("body").item(0);
body.appendChild(elementol);
}
The problem is that these lines :
x=doc.getElementsByTagName("title")[k];
and
descript=doc.getElementsByTagName("description")[k];
get information coming from the "BOOK" section not from the chapter.
I'm sure someone knows how to get this.
thanks
In your code you use doc variable which appears to be something inherited from document object, see the reference.
The .getElementsByTagName("title") method returns an array of tags title which appears not just in the chapter, but also in the root element, book.
Search from chapter node, not from doc
var chapters = doc.getElementsByTagName("chapter");
for(var i=0; i<chapters.length; ++i) {
// search from book, which is what you don't want
// doc.getElementsByTagName("title")[0];
// search from chapter, you want this
chapters[i].getElementsByTagName("title")[0];
}
Note
In newer browsers (IE8+) you can save yourself lots of pain if you use .querySelectorAll() method (which btw renders great portion of jQuery obsolete).
var titles = doc.querySelectorAll("chapter title");
alert(titles[0].innerHTML); // Chapter 1
Have you tried getting the collection of chapters first:
var chapters =doc.getElementsByTagName("chapter");
And then iterating through each chapter to find the child nodes of that instance in the collection?
if (chapters.length > 0)
{
for (i = 0; i < resultList.length; i++)
{
var title = chapters[i].getElementsByTagName("title")[0];
var desc = chapters[i].getElementsByTagName("description")[0];
// do work here
}
}
Related
I'm trying to make a runnable console command through Chrome that searches for the word "takeID", and then grabs the content immediately after it between = and & from a div class.
What I have so far doesn't work because I'm very bad at JS so any help would be appreciated. Below is what I have so far:
var iframe=document.getElementsByClassName("activity activity-container-html5");
var searchValue = "takeID";
for(var i=0;i<iframe.length;i++){ if(iframe[i].innerHTML.indexOf(searchValue)>-1){}};
var subString = iframe.substring( iframe.lastIndexOf("=")+1, iframe.lastIndexOf("&"));
console.log(searchValue+"="+subString);
An example of the div class it would be searching would look like:
<div class="activity activity-container-html5" config="{example text;takeID=cd251erwera34a&more example text}">
There are two issues with the code. The first issue is the searchValue posts to the console as whatever is in between the takeID, and not the actual result from searching. The second issue is that the code to search between = and & doesn't work at all and I don't know why. What is wrong with the code?
I just want an output that would post to the log or a popup window saying:
takeID=cd251erwera34a
EDIT:
Something else I thought of was how would you be able to just parse the div and then search for what is in between "takeID=" and "&"? I tried this but I was getting the error "Uncaught TypeError: iframe.lastIndexOf is not a function".
var iframe=document.getElementsByClassName("activity activity-container-html5");
var subString = iframe.substring( iframe.lastIndexOf("takeId=") + 1, iframe.lastIndexOf("&") );
console.log(subString);
I looked this up and I see this is because what it is trying to process is not a string but I'm not sure why that is or how to fix it.
I don't know about you but the best would be to use json directly inside the html tag like this:
<div class="activity activity-container-html5" config="{'example':'text', 'takeID':'cd251erwera34a', 'other':''}">
Or use an array and check manually if the one you are checking is the one you want, like this:
function config(element, searchValue) {
if (element.hasAttribute('config')) {
var configData = JSON.parse(element.getAttribute('config'));
var res = "";
for (var i = 0; i < configData.length; i++) {
if (configData[i].includes(searchValue)) {
res = configData[i];
break;
}
}
return res;
}
}
el = document.getElementsByClassName('activity activity-container-html5');
for (var i = 0; i < el.length; i++) {
console.log(config(el[i], "takeID"));
}
<div class="activity activity-container-html5" config='["example=text", "takeID=cd251erwera34a", "othertext=here"]'>
The array-type (second example) is most likely to work better than the simple json one (first one).
I figured out what I needed to do. Below is working code:
var iframe=document.getElementsByClassName("activity activity-container-html5");
var div = "";
for(var i=0;i < iframe.length; i++){
div += (iframe[i].outerHTML);
}
var take = /takeID=([a-z0-9]*)&/;
var capture = div.match(take);
var matchID = capture[1];
console.log(matchID);
window.alert("takeID=" + matchID);
I'm trying to write a javascript what is searching for all of the links on the page, then it is adding them to the bottom, under the original content.
"Document.links" seems to do the finding part, it is also listing them, but they are not clickable. So I tried to add some html codes (startHref and endHref lines), which broke the whole thing of course.
My (non-working) script:
var links = document.links;
for(var i = 0; i < links.length; i++) {
var preLink = document.createTextNode("LINK: ");
var linkHref = document.createTextNode(links[i].href);
var lineBreak = document.createElement("br");
var startHref = document.createElement("a href="");
var endHref = document.createElement(""");
document.body.appendChild(preLink);
document.body.appendChild(startHref);
document.body.appendChild(linkHref);
document.body.appendChild(endHref);
document.body.appendChild(lineBreak);
}
If this will work I'd also like to have them listed with a number in front of each line (starting with 1 - could be set in the preLink part) - if not too hard to implement.
Also, is there a way to list not all of the links, but only those matching with something? Like only links with a specific domain. Thank you!
As you have already found out, you can get all links in a document with:
var links = document.links;
Now you have an HTMLCollection. You can iterate through it and display all links. For better layout you can put them in a paragraph (p). This would be the loop:
for (var i = 0; i < links.length; i++) {
var p = document.createElement("p");
p.appendChild(links[i]);
document.body.appendChild(p);
}
Now all links are appended at the end of the page, every link is on its own line and they are clickable. Please try this out.
EDIT: as of your comment, if I understand it right, you have just to put one additional line:
for (var i = 0; i < links.length; i++) {
var p = document.createElement("p");
// the following line is added
links[i].innerHTML = links[i].href;
p.appendChild(links[i]);
document.body.appendChild(p);
}
That line will simply replace the inner HTML of the link with its value for the attribute href.
EDIT:
The variable links just points to document.links. The existing links are therefore removed from their original position and appended to the end. If you try to create new links in the for loop, like document.createElement("a") you will create an endless loop, because you're iterating through all links in the document. You remember, the variable links is not a snapshot of document.links when created, but points to it.
You can work around this with creating an array:
var links = [];
// populate the array links
for (var j = 0; j < document.links.length; j++) {
links.push(document.links[j].cloneNode());
}
Now this is a snapshot of all links on the page. Every links is cloned and pushed to the array. Now run the for loop and the original links aren't removed.
If the original link was something like:
This is an example.
it will become:
http://example.com
But if you want just:
http://example.com
then you have to adapt the code:
for (var i = 0; i < links.length; i++) {
var p = document.createElement("p");
var a = document.createElement("a");
a.href = links[i].href;
a.text = links[i].href; // you can use text instead of innerHTML
p.appendChild(a);
document.body.appendChild(p);
}
If you want to style the output you can add classes like this:
p.classList.add("my-css-class");
I hope this helps you to achieve your goal.
In my project I'm trying to parse rss & atom feeds. I target each feed's link with this:
var feedLink = source.getElementsByTagName('link')[0];
Some feeds start directly with
<link>http://www.url.com</link>
but some start like this:
<atom:link href="http://www.url.com/feed/" rel="self" type="application/rss+xml" />
<link>http://www.url.com</link>
and the selector I'm using targets also the link tags that starts with atom:
Is there a way to avoid them ?
Thanks
Try poping out the link from the end of NodeList, in this case, it will work for both cases.
var x = source.getElementsByTagName('link');
var feedLink = x[(x.length - 1)]
Isn't the best solution, but is the more fastly in this scenario.
You can try using getElementsByTagNameNS instead, but i'm not sure how well it is supported across browsers. Works in latest Chrome.
var xmlString = [
'<?xml version="1.0" encoding="utf-8"?>',
'<feed xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">',
'<atom:link href="http://www.example.com/feed/" rel="self" type="application/rss+xml" />',
'<link>http://www.example.com</link>',
'</feed>'
].join('\n');
var xml = (new DOMParser()).parseFromString(xmlString, "text/xml");
// Try regular search
var found = xml.getElementsByTagName('link');
for (var i = 0; i < found.length; i++) {
console.log('regular', i, found[i].nodeName);
}
// Try namespaced search
var foundNS = xml.getElementsByTagNameNS('http://www.w3.org/2005/Atom', 'link');
for (var i = 0; i < foundNS.length; i++) {
console.log('namespaced', i, foundNS[i].nodeName);
}
So here's the deal: I'm trying to retrieve a NodeList object from an already existing NodeList. Here's a simplified XML example:
<products>
<category>
<name>Category A</name>
<product>
<code>1</code>
<name>Product 1 Category A</name>
<price>10.0</price>
</product>
<product>
<code>2</code>
<name>Product 2 Category A</name>
<price>20.0</price>
</product>
</category>
<category>
<name>Category B</name>
<product>
<code>3</code>
<name>Product 1 Category B</name>
<price>5.0</price>
</product>
...
</category>
</products>
As you can see, the tag name appears twice, once as a child node of category and again as a child node of product. I wish to retrieve only product names. Since I can't read from the XML file but rather receiving it as a string, here's my parse function:
function parseXML(xmlString) {
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(xmlString, "text/xml");
var products = xmlDoc.getElementsByTagName("product");
var names = products.tags("name"); //Here's my problem
for(var i = 0; i < names.length; i++){
var element = names[i];
var name = element.firstChild;
$('#div_products').append(name.data + "<br>");
}
$('#div_main').html($('#div_products').html());
}
This is what I'm using as reference: http://help.dottoro.com/ljtrjxbf.php. Using nodeListObject.tags("tag"), however, will produce the following error:
processMessage failed: Stack: TypeError: Object #<a NodeList> has no method 'tags'
I've trying different approaches, but nothing worked. Even
var names = products["name"];
returns "undefined", which wouldn't work for me in any case, since the documentation says that aside from IE, it will return only the first node and
A) I'm working with Android/Cordova and
B) There's no attribute "name" in the node anyway.
So how do I work this out? I supposed I could try to create a new XMLDocument object from the products NodeList but I haven't looked into it since it must have a more trivial way to solve this problem.
Thank you Teemu, I've managed to achieve what I wanted with a few tweaks in my Javascript code. I'll post it here so that maybe someone might find it helpful in the future:
function parseXML(xmlString) {
var NAME = 5;
var parser = new DOMParser();
var xmlDoc = parser.parseFromString(xmlString, "text/xml");
var products = xmlDoc.getElementsByTagName("product");
for(var i = 0; i < products.length; i++){
var nodeList = produtos[i].childNodes;
$('#div_products').append(nodeList[NAME].textContent + "<br>");
}
$('#div_main').html($('#div_products').html());
}
Please notice that 5 is the index of the DOM TextNode I wanted (the product name itself), hence:
var NAME = 5;
That would be all.
Let's suppose I have an XML file like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<MIDIFile>
<Event>
<Absolute>0</Absolute>
<NoteOn Channel="1" Note="40" Velocity="64"/>
</Event>
<Event>
<Absolute>236</Absolute>
<NoteOff Channel="1" Note="40" Velocity="0"/>
</Event>
</MIDIFile>
Thanks to some great tutorial I now know how to get these values in my javascript.
For example, I can iterate thru all the "Events" tag and get the "Absolute" value like this:
xmlhttp=new XMLHttpRequest();
xmlhttp.open("GET","test.xml",false);
xmlhttp.send();
xmlDoc=xmlhttp.responseXML;
// make an array with all the events from the xml file
var events = xmlDoc.getElementsByTagName("Event")
for (var i = 0; i<events.length; i++)
console.log(events[i].getElementsByTagName("Absolute")[0].childNodes[0].nodeValue)
this will return
0
236
Now, how the hell can I access the "NoteOn" attribute and get its values? I want to iterate thru all the Events in the XML, see if they contains NoteOn or NoteOff and load an array with all the notes, their duration, velocity and channels.
Please help me! getElementsByTagName("NoteOn") just doesn't work... If it might help, here are some screenshot of what happens if I console.log(xmlDoc)
Thanks a lot in advance!
edit in response to an answer. As I try to do this:
var noteon = xmlDoc.getElementsByTagName('noteon');
console.log(noteon)
the result is just this one
[]
re-edit:
If I write "NoteOn" instead of "noteon" it works!
var noteon = xmlDoc.getElementsByTagName('noteon');
var note = new Array;
for(var i = 0; i < noteon.length; i++){
note[i] = noteon[i].getAttribute('Note'); // or any of the attributes you want to get
}
Edit:
If noteon = [] then you have 2 options you can put the whole thing in a try catch, not the best thing to do in javascript, or you can put it in an if statement. Something like this should work:
var noteon = xmlDoc.getElementsByTagName('noteon');
var noteoff = xmlDoc.getElementsByTagName('noteoff');
var note = new Array;
if(noteon != []){
for(var i = 0; i < noteon.length; i++){
note[i] = noteon[i].getAttribute('Note'); // or any of the attributes you want to get
} else if(noteoff != []){
for(var i = 0; i < noteoff.length; i++){
note[i] = noteoff[i].getAttribute('Note'); // or any of the attributes you want to get
} else{
return; //makes sure the function returns to the call even if nothing was found
}
}