Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 07.09.2011, 15:21
Аспирант
Отправить личное сообщение для Hag1989 Посмотреть профиль Найти все сообщения от Hag1989
 
Регистрация: 25.10.2009
Сообщений: 50

Парсинг локально подключаемого xml файла объемом более 17 мб
Здравствуйте!

Пишу функции для справочника в формате chm. Задача - локально подключить и отпарсить xml файл объёмом 17-25 мб (следовательно выполнить это на движке IE6). В результате получил огромную нагрузку на процессор (если решитесь запустить index.html на слабом компе, то запаситесь терпением на время обработки. Chm работает быстрее и выведет данные, примерно, через 5-10 сек).
Помогите найти более логичное и быстрее работающее решение задачи чем то, что я своял:

Теперь всё по порядку.
xml имеет следующую структуру:

Код:
<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
	<Row>
		<Col>text</Col>
		<Col>text</Col>
                         ...
		<Col>img/name1.jpg</Col>
		<Col>img/name2.jpg</Col>
	</Row>
...
	<Row>
		<Col>text</Col>
		<Col>text</Col>
		<Col>-</Col>

                         ...
		<Col>img/name.jpg</Col>
		<Col>img/name.jpg</Col>
	</Row>
</Root>
*! Опытным путем выяснил, что документ с пустыми тегами типа <Col></Col> не проходит обработку, функция стопарится на firstChild.data, пришлось заменять пустые элементы на <Col>-</Col>.

С подключением 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. Прошу простить если моя задача покажется Вам слишком абсурдной, с радостью приму любые советы по решению изложенной проблемы.
Вложения:
Тип файла: zip files.zip (233.0 Кб, 24 просмотров)

Последний раз редактировалось Hag1989, 07.09.2011 в 16:00.
Ответить с цитированием
  #2 (permalink)  
Старый 07.09.2011, 16:00
Профессор
Отправить личное сообщение для ваый Посмотреть профиль Найти все сообщения от ваый
 
Регистрация: 29.06.2011
Сообщений: 445

Занятно. А не пробовали делать парсинг с помощью Dom парсера?
ActiveXObject("Microsoft.XMLDOM") в ИЕ, DomParser в остальных?
(javascript, sql, xml)
Может, будет быстрее?
Ответить с цитированием
  #3 (permalink)  
Старый 07.09.2011, 16:32
Аспирант
Отправить личное сообщение для Hag1989 Посмотреть профиль Найти все сообщения от Hag1989
 
Регистрация: 25.10.2009
Сообщений: 50

Только что обновил сообщение прикрепив ссылку на 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>
Ответить с цитированием
  #4 (permalink)  
Старый 07.09.2011, 16:49
Аватар для Snipe
Профессор
Отправить личное сообщение для Snipe Посмотреть профиль Найти все сообщения от Snipe
 
Регистрация: 06.05.2008
Сообщений: 765

Слышал, но не проверял, что обратные цыклы работают быстрее.
Т.е. 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++)
Ответить с цитированием
  #5 (permalink)  
Старый 07.09.2011, 17:10
Профессор
Отправить личное сообщение для ваый Посмотреть профиль Найти все сообщения от ваый
 
Регистрация: 29.06.2011
Сообщений: 445

Сообщение от Snipe Посмотреть сообщение
Слышал, но не проверял, что обратные цыклы работают быстрее.
Т.е. 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
Ответить с цитированием
  #6 (permalink)  
Старый 07.09.2011, 17:33
Аватар для Snipe
Профессор
Отправить личное сообщение для Snipe Посмотреть профиль Найти все сообщения от Snipe
 
Регистрация: 06.05.2008
Сообщений: 765

Сообщение от ваый Посмотреть сообщение
Сравнение:
http://jsperf.com/caching-array-length/12
Ну ок, обратные цыклы не особо зажгли (хотя у них в примере опечатка, не знаю как в коде), однако кеширование длины в моем случае увеличило производительность почти в два раза.
Ответить с цитированием
  #7 (permalink)  
Старый 07.09.2011, 17:44
Аспирант
Отправить личное сообщение для Hag1989 Посмотреть профиль Найти все сообщения от Hag1989
 
Регистрация: 25.10.2009
Сообщений: 50

Спасибо за совет! Значене length конечно можно заранее объявить, но вся вся нагрузка на проц. ложится при разборе arr[i][j] = xmlCols[j].firstChild.data, т. е. когда извлекаются текстовые данные.
Ответить с цитированием
  #8 (permalink)  
Старый 07.09.2011, 17:47
Аватар для Magneto
Люмус, Емаксос Developer!
Отправить личное сообщение для Magneto Посмотреть профиль Найти все сообщения от Magneto
 
Регистрация: 06.05.2010
Сообщений: 677

Сообщение от ваый
Сравнение:
http://jsperf.com/caching-array-length/12
Интересно, похоже что в современных браузерах обратные цыклы работают медленне обычных.
Ответить с цитированием
  #9 (permalink)  
Старый 07.09.2011, 18:58
Новичок на форуме
Отправить личное сообщение для Kolyaj Посмотреть профиль Найти все сообщения от Kolyaj
 
Регистрация: 19.02.2008
Сообщений: 9,177

Да какая разница какие циклы быстрее, сам цикл никогда не будет слабым звеном, если только вы не проверяете, какие циклы быстрее.
Ответить с цитированием
  #10 (permalink)  
Старый 07.09.2011, 19:08
Профессор
Отправить личное сообщение для DjDiablo Посмотреть профиль Найти все сообщения от DjDiablo
 
Регистрация: 04.02.2011
Сообщений: 1,815

А обязательно использовать XML ???
Может получится хранить инфу в json ????

Тогда и преобразовывать из массива в массив не надо, храни сразу так как планируешь использовать.
__________________
Лучше калымить в гандурасе чем гандурасить на колыме
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Передача xml файла в js не через HTTP. prowoke Общие вопросы Javascript 9 30.06.2011 02:36
Сохранение файла XML zeraid Общие вопросы Javascript 2 12.05.2011 02:08
не работает парсинг XML в IE Enxiro jQuery 6 25.08.2010 12:26
Размер загруженного XML файла Mefisto AJAX и COMET 3 15.03.2010 00:05
Как узнать какие ошибки произошли при парсинге xml файла faunder Events/DOM/Window 0 12.09.2008 14:17