XML - прогулка по дереву

 

Покопавшись в узлах XML в предыдущем уроке и отложив в голове смутные представления о XML, как о то ли веревке с узлами, то ли дереве с веревками, попробуем поползать по этому дереву и понять что это такое.

Когда мне пришлось искать хоть какой-нибудь примерчик по обходу дерева, я перепробовал многие исходники для этих целей. Но к сожалению 100% работающего не нашел.

Есть два основных пути обхода дерева: рекурсией и в трехкадровом цикле.

От рекурсии пришлось практически сразу отказаться, поскольку при большом количестве записей Flash начинает ругаться на медленную работу скрипта.

Оставался обход в трехкадровом цикле. Но исходники, использовавшие этот способ имели существенный недостаток: мое дерево из 350 записей обходилось за 30-35 секунд. Это было неприемлемо. В конце концов был найден способ, условно назовем его "ограничитель итераций", который и будет использован при обходе дерева.

 

Что из себя представляет обход дерева? Это последовательный поиск следующего по порядку узла XML и применение его атрибутов к объектам Flash..

Логика реализации примерно такова: в переменную помешаем ссылку на первый узел, применяем атрибуты к объекту, смотрим, есть ли дочерние узлы, если есть то в переменную помешаем ссылку на первого ребенка, с ним производим те-же действия, а если нет дочерних узлов, то переходим на брата, если нет брата то переходим на родительский узел и затем на его следующего брата...... даааа... семейка получается не малая... но в скрипте это смотрится проще. В скрипте вообще всё проще чем в жизни. Поэтому предлагаю в него погрузиться.

Этот пример использует функцию applyProp и XML из прошлого урока, поэтому здесь я это не комментирую.

 

 

xmlTmp = new XML("<tree><mc1 _x='10' _y='20' _rotation='-10' status='busy'></mc1><mc2 _x='20' _y='40' _rotation='40'></mc2><mc3 _x='30' _y='50' _rotation='60'></mc3><mc4 _x='80' _y='80' _rotation='-115' status='busy'></mc4><mc5 _x='150' _y='120' _rotation='20' status='busy'></mc5></tree>");

XMLNode.prototype.applyProp = applyProp;

function applyProp (to) {

// © Ivan Dembicki, dembicki@narod.ru

var a = this.attributes;

var b = eval(to);

var vars;

var val;

for (vars in a) {

val = a[vars];

if (isNaN(Number(val))) {

b[vars] = val;

} else {

b[vars] = Number(val);

}

}

}

XMLNode.prototype.fncNextNode = function() {// помещаем в прототип узла функцию вычислениЯ следующего узла

// © Ivan Dembicki, dembicki@narod.ru

if (this.firstChild != null) { // если у текущего узла есть ребенок

return this.firstChild; // возвращаем ребенка

}

var n = this; // во временную переменную помещаем текущий узел

while (n.nextSibling == null) { // пока нет брата

if (n.parentNode) { // если есть родитель

n = n.parentNode; // временной переменной задаем значение родителЯ

} else { // иначе, то есть если нет ни брата ни родителЯ, значит

return null; // мы добрались до конца XML и возвращаем null

}

}

return n.nextSibling; // поскольку ранее нашли узел у которого есть брат, возвращаем брата найденного узла

};

xmlTmp.ignoreWhite = true; // просим игнорировать пробелы в нашем XML

nod = xmlTmp.firstChild; // задаем первый узел

 

это был скрипт первого кадра, второй кадр оставим пустым, а в третьем пишем:

 

for (z=0; z<50; z++) { // это и есть ограничитель итераций ® *

nod = nod.fncNextNode(); // задаем переменной значение следующего узла

if (nod) { // если следующий узел не пустой

_root.attachMovie("mc", nod.nodeName, i++); // аттачим мувик

nod.applyProp(nod.nodeName); // и присваиваем ему свойства из узла

} else { // а если мы добрались до конца дерева

delete i; // удалЯем ненужные переменные

delete nod;

delete z;

gotoAndStop("park"); // переходим на кадр с меткой park

break; // прерываем цикл

}

}

prevFrame();// если обработались очередные 50 интераций и не перешли в кадр park, то переходим в предыдущий кадр

play(); // и заходим в этот кадр заново

 

 

* - мы в одном кадре обрабатываем не более 50 узлов. 50 - цифра весьма условная. ее стоит подбирать в зависимости от нагруженности операций с каждым узлом, добиваясь максимальной производительности обработки.

1. Вкупе с выходом из кадра и повторным заходом в кадр мы добиваемся того, что во время генерации не висим в одном кадре, обнуляя встроенный счетчик максимального количества итераций, как если бы мы обрабатывали все узлы в одном кадре, и не налетаем на сообщение о медленной работе скрипта. При этом можно настроить ограничитель итераций так, чтобы нагруженность скрипта не тормозила анимацию, что тоже очень важно.

2. Обработка происходит не как в обычном трехкадровом цикле: один кадр - одна операция, а пакетами по 50 (в нашем случае), что дает почти 20-30 кратное увеличение производительности !!! в некоторых случаях эти показатели могут быть и большими.

 

Глубина. Этот пример по своим результатам не будет отличаться от предыдущего. Но попробуйте протестировать на другом XML документе, имеющем большие глубины: более глубокие (вложенные) дочерние узлы будут пропущены, в то время как текущий пример правильно обработает всё дерево.

Глубина вложений узлов очень важна, например при генерации вложенных меню. Но об этом в следующий раз.

 

Hosted by uCoz