Как я могу преобразовать файл XML в объект документа в Javascript? - PullRequest
0 голосов
/ 01 июня 2018

Я работаю над проектом, в котором мне нужно прочитать длинный (50000 строк) XML-файл.Я решил использовать класс Javascript Document или классы XMLDocument вместо стороннего анализатора XML.И DOM древовидная структура Javascript XML-парсера по умолчанию хорошо подходит для моего проекта, потому что мне нужно свободно перемещаться по дочерним и родительским узлам.

Я попытался использовать 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строки текста в строку, а затем превратить его в объект документа.

Например, 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);

Здесь console.log в «myFunction» работает, а другой - нет.Я полагаю, что xmlDoc обнуляется после send ().

Кроме того, это буквально все, что у меня есть в файле javascript, для тестирования его больше ничего нет.

1 Ответ

0 голосов
/ 05 июня 2018

Проблема была в том, как я не понял, как работают асинхронные функции.Однажды я понял, что вторая строка console.log(xmlDoc.getElementsByTagName("example")[0].getAttributeNode("name").nodeValue); не может быть выполнена сразу, потому что асинхронная функция должна быть завершена.

Я переключился на реализацию обещания, но потом у меня возник вопрос, является ли хорошим вариантом позволить глобальной переменной или переменной класса быть нулевым, пока не завершится асинхронная функция, и я написал для этого еще один вопрос: Каков хороший дизайн для глобальных переменных из асинхронных функций в 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 до того, как пройдет какое-то время.

Чтобы узнать, как мой исходный код не работал, изучите комментарий Дэниела и посмотрите на асинхронные функции и обратные вызовы,Изучение цикла событий в javascript также полезно.

Для хорошего подхода к дизайну я все еще не уверен, но вы можете попробовать ответить на другой мой вопрос, или, возможно, кто-то поможет с комментарием.

PS: Использовать обещание не обязательно, но в моей ситуации это только казалось лучшей практикой.

...