#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