Парсинг локально подключаемого xml файла объемом более 17 мб
Вложений: 1
Здравствуйте!
Пишу функции для справочника в формате chm. Задача - локально подключить и отпарсить xml файл объёмом 17-25 мб (следовательно выполнить это на движке IE6). В результате получил огромную нагрузку на процессор (если решитесь запустить index.html на слабом компе, то запаситесь терпением на время обработки. Chm работает быстрее и выведет данные, примерно, через 5-10 сек). Помогите найти более логичное и быстрее работающее решение задачи чем то, что я своял: Теперь всё по порядку. xml имеет следующую структуру: Код:
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> С подключением xml я справился следующим образом (эксперимента ради реализовал поддержку и для Firefox с помощью объекта XMLHttpRequest): //см. рекомендации на w3schools.com // 1. делаем запрос к БД, т.е. загружаем xml function createDocument() { //Temporary DOM object. var xmlDoc; //Create the DOM object for IE if (window.ActiveXObject) { var versions = [ "Msxml2.DOMDocument.6.0", "Msxml2.DOMDocument.3.0" ]; for (var i = 0; i < versions.length; i++) { try { xmlDoc = new ActiveXObject(versions[i]); xmlDoc.load("data_01.xml"); return xmlDoc; } catch (error) { //do nothing here } } } //Cтроим DOM для Firefox else if (window.XMLHttpRequest) {// локально работае везде кроме Chrome и Opera 11 xmlDoc=new XMLHttpRequest(); xmlDoc.open("GET","data_01.xml",false); xmlDoc.send(); xmlDoc=xmlDoc.responseXML; return xmlDoc; } return null; } Далее, парсим xml в двухмерный массив arr[i][j] var xmlDoc = createDocument(); // 2. парсим тело полученного документа в массив извлекая текстовые данные посредством свойств firstChild.data var arr = [], xmlRows = xmlDoc.getElementsByTagName('Row'); // log log("Загружено элементов Row: "+xmlRows.length+". "); for(var i=0; i<xmlRows.length; i++) { var xmlCols = xmlRows[i].getElementsByTagName('Col'); arr[i] = []; for(var j=0; j<xmlCols.length; j++) { arr[i][j] = xmlCols[j].firstChild.data; // log // log("Загружено элементов Col: "+arr[i][j].length+". "); } } // Возвращаем массив Arr return arr; Потом вывожу данные построчно в динамически формируемый список. На этом, пока, всё. В дальнейшем предполагается разбить полученный массив arr на множество двухмерных массивов, данные которых будут выводиться на экран в зависимости от действий пользователей. Вот весь рабочий код: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> <title>Chm справочник на xml базе данных</title> <body> <div id="logDiv" style="position: relative; clear:both; margin: 0px auto; width: 334px; height: 100px; overflow: auto; white-space: pre-wrap; border: 1px solid black; left: 9px; margin-top: 0px;"></div> <center><input type="button" value="Очистить журнал" onclick="clearLog();"/></center> <script type="text/javascript"> function log(str) { document.getElementById("logDiv").innerHTML += str+"\n"; } function clearLog() { document.getElementById("logDiv").innerHTML = ""; } // Чтобы не засорять пространство глобальных переменных все делаем в безымянной функции var DBArray = (function() { // 1. делаем запрос к БД, т.е. загружаем xml function createDocument() { //Temporary DOM object. var xmlDoc; //Create the DOM object for IE if (window.ActiveXObject) { var versions = [ "Msxml2.DOMDocument.6.0", "Msxml2.DOMDocument.3.0" ]; for (var i = 0; i < versions.length; i++) { try { xmlDoc = new ActiveXObject(versions[i]); xmlDoc.load("data_01.xml"); return xmlDoc; } catch (error) { //do nothing here } } } //Cтроим DOM для Firefox else if (window.XMLHttpRequest) {// локально работае везде кроме Chrome и Opera 11 xmlDoc=new XMLHttpRequest(); xmlDoc.open("GET","data_01.xml",false); xmlDoc.send(); xmlDoc=xmlDoc.responseXML; return xmlDoc; } return null; } var xmlDoc = createDocument(); // 2. парсим тело полученного документа в массив var arr = [], xmlRows = xmlDoc.getElementsByTagName('Row'); // log log("Загружено элементов Row: "+xmlRows.length+". "); for(var i=0; i<xmlRows.length; i++) { var xmlCols = xmlRows[i].getElementsByTagName('Col'); arr[i] = []; for(var j=0; j<xmlCols.length; j++) { arr[i][j] = xmlCols[j].firstChild.data; // log // log("Загружено элементов Col: "+arr[i][j].length+". "); } } // Возвращаем массив Arr return arr; })(); // выводим списком текстовое содержимое элементов Col которое отпарcили в массив arr функции DBArray function createList(data) { var list = document.createElement("ul"); for (var i = 0; i < data.length; i++) { var newItem = document.createElement("li"); var newText = document.createTextNode(data[i]); newItem.appendChild(newText); list.appendChild(newItem); } return list; } window.onload = function() { var list = createList(DBArray); document.body.appendChild(list); } </script> </body> </html> P. S. К сожалению я специализируюсь, в основном, на верстке и пока плохо владею javascript. Прошу простить если моя задача покажется Вам слишком абсурдной, с радостью приму любые советы по решению изложенной проблемы. |
Занятно. А не пробовали делать парсинг с помощью Dom парсера?
ActiveXObject("Microsoft.XMLDOM") в ИЕ, DomParser в остальных? (http://javascript.ru/forum/misc/2090...tml#post121722) Может, будет быстрее? |
Только что обновил сообщение прикрепив ссылку на w3schools.com
DOM parser предполагает наличие тегов в теле документа с функцией, что уже не очень удобно, к тому же все данные обрабатываются в одну текстовую строку, у меня никак не удалось запихнуть их в в духмерный массив: <script> txt="<note>"; txt=txt+"<from>Jani</from>"; txt=txt+"<from>Anne</from>"; txt=txt+"<from>Jolie</from>"; txt=txt+"<from>Susanne</from>"; txt=txt+"<from>Marie</from>"; txt=txt+"<to>Tove</to>"; txt=txt+"<from>Marie</from>"; txt=txt+"<from>Anne</from>"; txt=txt+"<from>Jolie</from>"; txt=txt+"<from>Анна</from>"; txt=txt+"<from>Вера</from>"; txt=txt+"</note>"; txt="<note>"; txt=txt+"<from>Jolie</from>"; txt=txt+"<from>Susanne</from>"; txt=txt+"<from>Marie</from>"; txt=txt+"<to>Tove</to>"; txt=txt+"<from>Marie</from>"; txt=txt+"<from>Anne</from>"; txt=txt+"<from>Jolie</from>"; txt=txt+"<from>Marie</from>"; txt=txt+"<from>Инна</from>"; txt=txt+"</note>"; txt="</root>"; var xmlDoc; if (window.DOMParser) { parser=new DOMParser(); xmlDoc=parser.parseFromString(txt,"text/xml"); } else // Internet Explorer { xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async="false"; xmlDoc.loadXML(txt); } var arr = [], xmlRows = xmlDoc.getElementsByTagName('note'); for(var i=0; i<xmlRows.length; i++) { var xmlCols = xmlRows[i].getElementsByTagName('from'); arr[i] = []; for(var j=0; j<xmlCols.length; j++) { arr[i][j] = xmlCols[j].firstChild.data; } } document.getElementById("from").innerHTML=arr; </script> |
Слышал, но не проверял, что обратные цыклы работают быстрее.
Т.е. i меняется не от 0 к length, а от length к 0 и проверяется при этом во втором условии i. Т.е. как-то так: for (var i=xmlCols.length; i; i--) Но даже если делать с прямым циклом, то length лучше посчитать заранее (у вас в каждой итерации цикла data.length пересчитывается вроде как): for (var i = 0, l = data.length; i < l; i++) |
Цитата:
http://jsperf.com/caching-array-length/12 |
Цитата:
|
Спасибо за совет! Значене length конечно можно заранее объявить, но вся вся нагрузка на проц. ложится при разборе arr[i][j] = xmlCols[j].firstChild.data, т. е. когда извлекаются текстовые данные.
|
Цитата:
|
Да какая разница какие циклы быстрее, сам цикл никогда не будет слабым звеном, если только вы не проверяете, какие циклы быстрее.
|
А обязательно использовать XML ???
Может получится хранить инфу в json ???? Тогда и преобразовывать из массива в массив не надо, храни сразу так как планируешь использовать. |
Часовой пояс GMT +3, время: 00:54. |