XML DOM, перебирающий узлы элементов

#javascript #xml #dom

#javascript #xml #dom

Вопрос:

Я делаю учебное пособие по W3 XML DOM. Я не могу понять, почему итерация выдает 1, 3, 5, 7 на выходе. Я понимаю все остальное (я думаю!) Может кто-нибудь помочь объяснить? Спасибо.

 <!DOCTYPE html>
<html>
<body>

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

<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 amp;amp; 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>
  

Вывод:

 1 title
3 author
5 year
7 price
  

Привет, Энди, вот файл xml DOM, он из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>
  

Дополнительные комментарии в ответ на ответ Carlos22. Прости, Карлос, я все еще не понимаю.

(y.nodeType ==1) всегда возвращает true, потому что дочерние элементы первого вхождения <book> имеют тип element (nodeType = 1)

первый цикл i = 0 поэтому значение txt должно быть 0 title

второй цикл i = 1 so 0 title должен быть объединен с 1 author таким образом, значение строки txt теперь 0 title 1 author

третий цикл i = 2 txt содержит строку 0 title 1 author 2 year и так далее.

Иногда я способен быть невероятно глупым, поэтому, пожалуйста, прости!!

Комментарии:

1. Можете ли вы включить свой xml в этот пример?

2. Привет, Энди, вот xml DOM:

Ответ №1:

Ваш код оценивает только «узлы элементов» из-за if (y.nodeType == 1) .

Вот пример со всеми узлами:

 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>  

Пример упакованного XML:

 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>  

Комментарии:

1. Это все объясняет. Чего я не понимаю, почему текстовый узел находится перед узлом элемента?

2. @andymeissner потому что каждый текст, который не находится внутри тега, обрабатывается как текстовый узел. В нашем случае это просто … пробелы и переводы строк.

3. О, вот и все. Потому что я пытался воспроизвести это с помощью jsfiddle и не смог, потому что я удалил пробелы и переводы строк: D

4. @andymeissner Я добавил упакованный пример XML к своему ответу. Взгляните. Я удалил 1 текстовый узел, удалив ненужный перевод строки 🙂

5. Спасибо вам всем, я начинаю понимать. Просто нужно переварить ваши комментарии дальше. Спасибо.

Ответ №2:

Это происходит из-за проверки, y.nodeType == 1 когда это правда, в которой это сохраняется txt = i " " y.nodeName "<br>"; ; это означает, что когда y.nodeType == 1 is true i равно 1 в следующем цикле, когда i равно 2 y.nodeType == 1 , это false, затем в следующем цикле, когда i равно 3 y.nodeType == 1 , это true и так далее.

Комментарии:

1. Привет, Карлос, я все еще не понимаю. Смотрите мои дополнительные комментарии, добавленные к сообщению.

2. Спасибо вам всем. Я вроде как начинаю понимать. Время переварить ваши комментарии!. Спасибо.

Ответ №3:

С помощью Антона и Энди Мейснеров я узнал и понял кое-что очень полезное! Также после изучения этого источника: [[Что вам нужно знать о пробелах в XML]][1][1]

Поведение кода можно объяснить тем, как анализатор обрабатывает пробелы в XML DOM

в следующем 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>
  

Было бы заманчиво думать, что у узла элемента <book> есть четыре дочерних элемента, а именно четыре элемента <title>, <author>, <year> and <price> , но на самом деле у него 7 дочерних элементов, потому что анализатор обрабатывает пробел (возврат каретки перевод строки) после каждого узла элемента как пустой текстовый узел.

Итак, как продемонстрировал Антон, элемент на самом деле имеет 7 дочерних элементов:

 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>
  

Код ищет только узлы элементов (nodeType = 1), поэтому обработка продолжается только if (y.nodeType == 1);

И вуаля, результат таков:

 1 title
3 author
5 year
7 price


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