azeemofwalsall
azeemofwalsall

Reputation: 75

XML DOM Looping through element nodes

I'm doing the W3 XML DOM tutorial. I can't understand why the iteration produces 1, 3, 5, 7 in the output. I understand everything else ( I think !) Can someone help to explain? Thanks.

<!DOCTYPE html>
<html>
<body>

<p id="demo"></p>

<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        myFunction(this);
    }
};
xhttp.open("GET", "books.xml", true);
xhttp.send();

function myFunction(xml) {
    var x, y, i, xlen, xmlDoc, txt;
    xmlDoc = xml.responseXML;
    x = xmlDoc.getElementsByTagName("book")[0];
    xlen = x.childNodes.length;
    y = x.firstChild;
    txt = "";
    for (i = 0; i < xlen; i++) {
        if (y.nodeType == 1) {
            txt += i + " " + y.nodeName + "<br>";
        }
        y = y.nextSibling;
    }
    document.getElementById("demo").innerHTML = txt; 
}
</script>

</body>
</html>

Output is:

1 title
3 author
5 year
7 price

Hello Andy, here is the xml DOM file, It's from https://www.w3schools.com/xml/dom_nodes.asp

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="cooking">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>
  <book category="children">
    <title lang="en">Harry Potter</title>
    <author>J K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
  <book category="web">
    <title lang="en">XQuery Kick Start</title>
    <author>James McGovern</author>
    <author>Per Bothner</author>
    <author>Kurt Cagle</author>
    <author>James Linn</author>
    <author>Vaidyanathan Nagarajan</author>
    <year>2003</year>
    <price>49.99</price>
  </book>
  <book category="web" cover="paperback">
    <title lang="en">Learning XML</title>
    <author>Erik T. Ray</author>
    <year>2003</year>
    <price>39.95</price>
  </book>
</bookstore>

Additional comments in response to Carlos22's answer. I'm sorry Carlos, I still don't understand.

(y.nodeType ==1) will always return true because the children of the first occurrence of <book> are all of type element (nodeType = 1)

first loop i = 0 so value of txt should be 0 title

second loop i = 1 so 0 title should concatenate with 1 author so value of string txt is now 0 title 1 author

third loop i = 2 txt contains the string 0 title 1 author 2 year and so on.

I am sometimes capable of being incredibly stupid, so please forgive !!

Upvotes: 0

Views: 708

Answers (3)

azeemofwalsall
azeemofwalsall

Reputation: 75

With the help of Anton and Andy Meissner, I have learned and understood something very useful! Also after studying this source: [[What You Need to Know About Whitespace in XML]][1][1]

The behaviour of the code can be explained by how the parser treats white space in XML DOM

in the following XML DOM:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="cooking">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>

It would be tempting to think that the element node <book> has four children, namely four elements <title>, <author>, <year> and <price> but in fact it has 7 children because the parser treats the white space (carriage return + line feed) after each element node as an empty text node.

So, as Anton demonstrated the element actually has 7 children:

child       Type
0           text node (or white space node)
1           element node <title>
2           text node
3           element node <author>
4           text node
5           element node <year>
6           text node
7           element node <price>

The code seeks only element nodes (nodeType =1) so processing proceeds only if (y.nodeType == 1);

Et voila, the output is:

1 title
3 author
5 year
7 price


  [1]: https://oracle.com/technical-resources/articles/wang-whitespace.html

Upvotes: 0

Anton
Anton

Reputation: 2703

Your code evaluates only "element nodes" because of if (y.nodeType == 1).

Here is example with all nodes:

const xml = `<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="cooking">
    <title lang="en">Everyday Italian</title>
    <author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>
  <book category="children">
    <title lang="en">Harry Potter</title>
    <author>J K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
  <book category="web">
    <title lang="en">XQuery Kick Start</title>
    <author>James McGovern</author>
    <author>Per Bothner</author>
    <author>Kurt Cagle</author>
    <author>James Linn</author>
    <author>Vaidyanathan Nagarajan</author>
    <year>2003</year>
    <price>49.99</price>
  </book>
  <book category="web" cover="paperback">
    <title lang="en">Learning XML</title>
    <author>Erik T. Ray</author>
    <year>2003</year>
    <price>39.95</price>
  </book>
</bookstore>`;

function getXmlFromText(xml) {
  parser = new DOMParser();
  return parser.parseFromString(xml, "text/xml");
}

function getNodeTypeStr(nodeType) {
  if (nodeType == 1) return 'ELEMENT_NODE';
  if (nodeType == 3) return 'TEXT_NODE';
  return 'Read the DOCS: https://www.w3schools.com/xml/dom_nodetype.asp';
}

function myFunction(xmlDoc) {
  var x, y, i, xlen, txt;
  //xmlDoc = xml.responseXML;
  x = xmlDoc.getElementsByTagName("book")[0];
  xlen = x.childNodes.length;
  y = x.firstChild;
  txt = ""; var txt2 = '';
  for (i = 0; i < xlen; i++) {
    if (y.nodeType == 1) {
      txt += i + " " + y.nodeName + "<br>";
    }
    txt2 += i + ' - ' + y.nodeName + ' - ' + getNodeTypeStr(y.nodeType) + ' - ' + y.nodeValue + '<br>';
    y = y.nextSibling;
  }
  document.getElementById("demo").innerHTML = txt;
  document.getElementById("allnodes").innerHTML = txt2;
}

myFunction(getXmlFromText(xml));
div {
 padding: 2px;
 border: 1px solid gray;
 margin-bottom: 4px;
}
Only element nodes:
<div id="demo"></div>
All nodes:
<div id="allnodes"></div>

Packed XML example:

const xml = `<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="cooking">
    <title lang="en">Everyday Italian</title><author>Giada De Laurentiis</author>
    <year>2005</year>
    <price>30.00</price>
  </book>
  <book category="children">
    <title lang="en">Harry Potter</title>
    <author>J K. Rowling</author>
    <year>2005</year>
    <price>29.99</price>
  </book>
  <book category="web">
    <title lang="en">XQuery Kick Start</title>
    <author>James McGovern</author>
    <author>Per Bothner</author>
    <author>Kurt Cagle</author>
    <author>James Linn</author>
    <author>Vaidyanathan Nagarajan</author>
    <year>2003</year>
    <price>49.99</price>
  </book>
  <book category="web" cover="paperback">
    <title lang="en">Learning XML</title>
    <author>Erik T. Ray</author>
    <year>2003</year>
    <price>39.95</price>
  </book>
</bookstore>`;

function getXmlFromText(xml) {
  parser = new DOMParser();
  return parser.parseFromString(xml, "text/xml");
}

function getNodeTypeStr(nodeType) {
  if (nodeType == 1) return 'ELEMENT_NODE';
  if (nodeType == 3) return 'TEXT_NODE';
  return 'Read the DOCS: https://www.w3schools.com/xml/dom_nodetype.asp';
}

function myFunction(xmlDoc) {
  var x, y, i, xlen, txt;
  //xmlDoc = xml.responseXML;
  x = xmlDoc.getElementsByTagName("book")[0];
  xlen = x.childNodes.length;
  y = x.firstChild;
  txt = ""; var txt2 = '';
  for (i = 0; i < xlen; i++) {
    if (y.nodeType == 1) {
      txt += i + " " + y.nodeName + "<br>";
    }
    txt2 += i + ' - ' + y.nodeName + ' - ' + getNodeTypeStr(y.nodeType) + ' - ' + y.nodeValue + '<br>';
    y = y.nextSibling;
  }
  document.getElementById("demo").innerHTML = txt;
  document.getElementById("allnodes").innerHTML = txt2;
}

myFunction(getXmlFromText(xml));
div {
 padding: 2px;
 border: 1px solid gray;
 margin-bottom: 4px;
}
Only element nodes:
<div id="demo"></div>
All nodes:
<div id="allnodes"></div>

Upvotes: 1

Carlos1232
Carlos1232

Reputation: 815

It is because of the validation y.nodeType == 1 when that's true it storages in txt += i + " " + y.nodeName + "<br>";; this means that when y.nodeType == 1is true i is 1 in the next loop when i is 2 y.nodeType == 1 is false, then on next loop when i is 3 y.nodeType == 1 is true and so.

Upvotes: 0

Related Questions