我正在开发一个需要读取长(50,000行)XML文件的项目。我决定使用默认的Javascript Document或XMLDocument类而不是第三方XML解析器。默认Javascript XML解析器的DOM树结构适用于我的设计,因为我需要自由遍历子节点和父节点。
我尝试以下列方式使用XMLHttpRequest:
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myFunction(this);
}
};
xhttp.open("GET", "xmls/EXAMPLE.xml", true);
xhttp.send();
function myFunction(xml) {
var xmlDoc = xml.responseXML;
console.log(xmlDoc.getElementsByTagName("example")[0].getAttributeNode("name").nodeValue);
}
这尤其适用于xmlDoc
对象,但在xhttp.send()
之后,该文档不再可访问。我希望文档保持可用,因为我需要根据客户的选择在不同的时间访问它的不同部分。
我也研究过DOMParser,但我不确定它是否是将50,000行文本转换为字符串然后将其转换为Document对象的有效方法。
例如var xmlDoc = new DOMParser().parseFromString(xml, "application/xml");
我一直在研究堆栈溢出和MDN中的一些问题但是还没有找到一种简单的方法来做到这一点。
编辑:当我将xmlDoc变量设为全局时,我收到错误"无法读取属性' getElementsByTagName'未定义"。以下是我尝试将其设为全局的方法:
var xmlDoc;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
xmlDoc = this.responseXML;
myFunction(this);
}
};
xhttp.open("GET", "xmls/EXAMPLE.xml", true);
xhttp.send();
function myFunction(xml) {
console.log(xmlDoc.getElementsByTagName("example")[0].getAttributeNode("name").nodeValue);
}
console.log(xmlDoc.getElementsByTagName("example")[0].getAttributeNode("name").nodeValue);
这里是" myFunction"中的console.log;有效,但另一个没有。我相信在send()之后xmlDoc变为null。
这也就是我在javascript文件中所拥有的一切,没有其他任何可用于测试它。
答案 0 :(得分:0)
问题在于我如何理解异步函数的工作原理。一旦我意识到第二行console.log(xmlDoc.getElementsByTagName("example")[0].getAttributeNode("name").nodeValue);
不能立即执行,因为异步函数需要完成。
我已经切换到一个promise实现但是它让我怀疑在异步函数完成之前让全局变量或类变量为空是一个好的设计,我写了另一个问题: What is a good design for global variables from Async functions in Javascript?
但是,目前我正在做的是:
self.xmlDoc = null;
this.promiseXML = new Promise(function(resolve, reject){
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "xmls/EXAMPLE.xml", true);
xhttp.onload = function(){
if(xhttp.status == 200){
self.xmlDoc = xhttp.responseXML;
resolve();
}else{
reject(xhttp.statusText);
}
};
xhttp.onerror = function(){
reject(xhttp.statusText);
}
xhttp.send();
})
this.promiseXML.then(function(){
console.log(self.xmlDoc.getElementsByTagName("parameter")[0].getAttributeNode("name").nodeValue);
}).catch(function(err){
console.log(err);
});
似乎我的重用xmlDoc
的问题不一定得到解决,因为如果你在承诺之后尝试console.log(self.xmlDoc.getElementsByTagName("example")[0].getAttributeNode("name").nodeValue);
,它仍然会为空。但是,我将在承诺范围内完成所有我需要的工作,一旦应用程序启动,肯定会启动self.xmlDoc
。
因此,如果需要在用户进行更改后使用它,它将正常工作。我最初的错误是因为我在任何时间过去之前试图运行console.log
。
关于我的原始代码是如何工作的,请查看Daniel的评论并查看异步函数和回调。在javascript中了解事件循环也很有用。
对于一个好的设计方法,我仍然不确定,但你可以尝试关注我的另一个问题,或者有人会帮忙发表评论。
PS:没有必要使用承诺,但对我的情况来说,这似乎是一种更好的做法。