Заголовок сообщения: разбираемся с ХМЛ Добавлено: 23 Май 2008, 12:22:46
пытаюсь освоить потихоньку, на текущий момент имею вот что,
для парсинга использую готовый класс:
Код:
class XML2Obj { static function toObj(x){ //trace(x.toString()) var obj = {} if (x.childNodes.length>0){ for (var v=0; v<x.childNodes.length; v++){ var o = x.childNodes[v] var n = o.nodeName if (n==undefined){ obj._$text = o.nodeValue }else{ if (obj[n]==undefined) obj[n] = [] obj[n].push(toObj(o)) } } } for (var v in x.attributes){ obj[v] = x.attributes[v] } //trace(obj) return obj } }
во флэше соответственно
Код:
stop(); _root.myXML = new XML();//определяем место под ХМЛ myXML.ignoreWhite = true;//пропуск пробелов. _root.myXML.load("_xml/ru_data.xml");//путь к нашему ХМЛ //загружаем ХМЛ, если загрузился - парсим его в массив _root.myXML.onLoad = function(success) { if (success) { _root.myXMLObj = XML2Obj.toObj(this); //определяем количество разделов //_root.razdelquant = _root.myXMLObj.razdel.length; play();
} }; //Функция назначения текстовым полям сождержимого из элементов массива. function setVars() { _root.pagelink = _root.myXMLObj.razdel[_root.rzdnum].mainText[_root.textnum].pagelink; text_title.text = _root.myXMLObj.razdel[_root.rzdnum].mainText[_root.textnum].titl; text_about.text = _root.myXMLObj.razdel[_root.rzdnum].mainText[_root.textnum].about; text_data.text = _root.myXMLObj.razdel[_root.rzdnum].mainText[_root.textnum].dat;
bNode — переменная ветвь, которая принимает новое значение каждую итерацию, просматривает все содержимое (родителя) Самый гуманный на мой взгляд метод перебора внутренностей ветки, хотя конечно может быть я не до конца вник в суть проблемы.
Ну и если воспользоваться хитрым программистским маневром при помощи этого же цикла for, он же while, можно создать рекурсивную функцию, но только я не до конца понял зачем парсить объект XML, когда он уже в принципе довольно удобен для использования или нет?
вот сам ХМЛ не удобен - там же чайлды какието - а в обьекте уже структура осмысленно поименованная.
"рекурсивная" - это для меня ругательство иначе бы я этот топик не завел. Мне бы пальцем показать.
То ись указанный класс - это не я писал и вообще не понимаю как он работает.
Решил до конца вникнуть в суть проблемы... и...
парсер нафик не нужен объясню почему, допустим так случиться что вам прийдется отправлять серверу в обратку то что нашпиляли во флеше, придется депарсить по новой, оно нам надо? поэтому делаем так.
у папаши myXML отрываем ребеночка
ourNode:XMLNode = myXML.firstChild (может быть myXML.firstChild.firstChild ((проверяйте трейсом)))
и так как у нас уже есть номер раздела, то!
ourNode.childNodes(_root.rzdnum) - это наш ребеночек-веточка нужный(по идее..)
в него мы внедряемся выше описанным циклом, или проще если у нас в XML все позиции строги как в армии
ourNode.childNodes(_root.rzdnum).childNodes[1].nodeName — titl
ourNode.childNodes(_root.rzdnum).childNodes[1].nodeValue— Содержимое titl... только и всего.
ну и далее меняем цифру 1 на последующие 2 3 и 4. чтобы пройтись по всем позициям содержимого.
Опять же настаиваю на том, что этот ваш парсер в классе вреден для здоровья. Еще есть витееватая idMap, которая готова прибежать нам на помощь, но она работала у меня как-то через раз, наверное я кривоват )) Ну и напоследок, забавное чтиво по теме
А и кстати, метод загрузки XML стоит объявить после того как мы описали функцию событию onLoad, вроде всё равно, но так гуманнее. Этакий олдскул ) т.е. если недогрузился кусок кода флеша в функции а лоад уже сработал и загрузился, звучит зверски неправдоподобно, но ВДРУГ ))))
без парсера оно и так все понятно, мне то как раз с парсером хочется.
В свое время адаптировал кучу сложных сайтов для БМВ - там везде аналогичный парсер ,только контент весь в атрибуты они пихали, соотвественно спец символы - наборами, что какбы некрасиво и неправильно.
Ну если парсер обязательное условие, тогда вам необходимо его немного адаптировать под задачу.
Делаем внутри рекурсивную функцию...
Вставляем вот эту намазолившую глаза ересь
Теперь когда мы натыкаемся на ветку родитель, нам нужно заново запустить цикл уже внутри нее, т.е. мы проверяем на отцовство routNode.nodeType, параметр, который нам об этом расскажет, и запускаем функцию по новой но уже с родителем routNode (т.е.
if nodeType=="ветка_папка" тогда пускаем функцию заново с параметром ветки родителя...
Не забываем, что все повторные назначения типа rout2Node=routNode это всего лишь создание ссылки, а не копирование объекта (спасибо и на этом)), а следовательно в нашем создаваемом объекте нам нужно тоже раскинуть ветви шире. и следовательно мы запоминаем в какую-нибудь еще одну переменную текущий объект. Как-то так. Подробнее написать есть написать код. Старался написать подробнее, но устал, конец рабочего дня. Если что-то до сих пор не стало ясно, я напишу еще, когда освежусь.
а почему так сложно? Парсер уже все обходит как надо, с любой вложенностью. Атрибуты берет, нельзя ли просто чтото чуть поправить чтоб видимо nodeValue из него выводился так же, как сейчас атрибут.
содержимое функции класса (toObj), хотя для теста я сделал просто функцию...
Код:
var obj:Object = {}; var kimo=0;
// if (x.childNodes.length>0) { // Вместо этого бреда вставляем адекватный говор: if (x.hasChildNodes()) { //И вместо того фора, вставляем мой любимый этот )))) for (var b:XMLNode = x.firstChild; b != null; b = b.nextSibling){
// var o = b; // заменяем последствия ужасного цикла: бред да? поэтому вместо замены будем использовать просто b: // var n = b.nodeName; // да и тут тоже, чего греха таить ))
Таким образом мы избегаем корявых случаев, во :) */ //trace(b + " " + b.nodeName + " " + b.nodeType); if (b.nodeType==3) { // впихаем суть в содержание )) obj = b.nodeValue;
} if (b.nodeType==1) { /*просто если nodeType - 1, то у ветки по любому есть имя. (obj[b.nodeName] == undefined) { obj[b.nodeName] = []; создаем если не создано.… НО!!!!!! БАБАХ!!!
тег mainText, повторился дважды, а значит он не будет создан как отдельный объект, и все атрибуты и содержимое перекроют поверх содержимое предыдущего такого же... поэтому для случаев повтора мы врубили счетчик... а так как мы врубили объект вместо масива то нам больше не нужны строки с пустыми скобками вот так хм... */
if (obj[b.nodeName] != undefined) { kimo++; obj[b.nodeName+kimo]=toObj(b); }else{ obj[b.nodeName] = toObj(b); } // а вот и рекурсия которую я просмотрел в прошлые посты ))) внутри push вызывается вот эта вся функция } } } // а тут оставим всё как есть :) for (var v in x.attributes) { obj[v] = x.attributes[v]; }
var obj:Object = {}; var kimo=0; if (x.hasChildNodes()) { for (var b:XMLNode = x.firstChild; b != null; b = b.nextSibling){ if (b.nodeType==3) { obj = b.nodeValue; } if (b.nodeType==1) { if (obj[b.nodeName] != undefined) { kimo++; obj[b.nodeName+kimo]=toObj(b); }else{ obj[b.nodeName] = toObj(b); } } } } for (var v in x.attributes) { obj[v] = x.attributes[v]; } return obj;
for (var i in myXMLObj.razdel.mainText) {
trace(i+" = "+myXMLObj.razdel.mainText[i]);
}
от переменной _$text мы избавились, и поэтому сам объект если он просто тупой стал нести в себе текст. ))
в принципе парсер остался универсальным, но нахрен он нужен я так и не понял ))
еще мы врубили счетчик kimo, который освобождает нас от тихого ужаса который мог происходить у нас за спиной.
загвоздка была в том что прошлый класс создавал массив, а нам нужен было ОБЪЕКТ!
в любом случае, с вас eddy444, часть гонорара (всего лишь 20%). Шучу, конечно.))
И это правильно, так или иначе при обучении все равно выходит слегка коряво или немного неверно.
У вас всё заработало?
Вчера уже в конце я обнаружил небольшую оплошность в нашем парсере,
поясню: если в тэг, вида <tits>4sized</tits> вставить отрибут, т.е. <tits owner="Monica">4sized</tits> то, аттрибут пропадет пропадом, потому что в нашем случае если тэг что-то содержит, то в объекте он становится просто переменной, а не объектом. obj = b.nodeValue; поэтому таки для универсальности стоит оставить ту самую переменную _$text, но назвать ее более человечным образом...
Поэтому меняем
Код:
obj = b.nodeValue;
на
Код:
obj.value = b.nodeValue;
value — переменная которая содержит текст. Кстати, глупо что в нашей структуре аттрибуты называются таким же образом как и внутренние объекты, из за этого может возникнуть путанница или пересекающиеся названия, а для нас это недопустимо. Поэтому в названиях создаваемых внутри объекта переменных аттрибутов создадим префикс "_". просто и по флешевски ))
Код:
obj[v] = x.attributes[v]
поменяем на
Код:
obj["_" + v] = x.attributes[v]
теперь все аттрибуты будут названы в виде _attr1, _attr2
И в нашем примерчике
<tits owner="Monica">4sized</tits>
вместо таких справедливух равенств(это не приравнивание ))) object.tits=="4sized", у нас будет object.tits== (object Object), а object.tits._owner=="Monica" и соответственно object.tits.value=="4sized", вот такие пироги )
тут еще зависит от вашей нумерации, как вы у себя в интерфейсе меняется РЖД нумер, от нуля или от еденицы...
оно должно в структуре соответствовать "", "1","2"… и т.д.
конечно намбер, оно присваивается из переменной цикла каждой кнопке в момент генерации кнопки раздела, количество которых определяется количеством соотвествующих нод ХМЛ
наконец дошли руки продолжить разбирательство. строчка не работала из за лишней точки, работает вот так titl.text = myXMLObj["razdel" + _root.rzdnum.toString()].titl;
теперь другая хрень - не определяется длинна массива. ни _root.myXMLObj.razdel.length ни _root. myXMLObj.firstChild.length; неопределяются.
Кроме того как избежать "", "1","2" ? то есть нужен перебор элемента массива с первого а не с "безымянного". Если поставить в цикле 1, то неработает обращение к 2му элементу. А безымянный все равно остается.
Короче это полный идиотизм. Измучил упомянутые куски кода вдоль и поперек. В итоге - вернулся к изначальному, опубликованному в топике, доступ к nodeValue оказался прост до тупости _root.myXMLObj.razdel[_root.rzdnum].mainText[_root.textnum].subtitl[0]._$text; вот жеж.
не знаю не сталкивался. Парсер мне лично нужен только для более удобного и наглядного, чем через "чайлды" обращения к текстовому массиву. Ведь в нем имена веток сам назначаешь и они могут соответствовать именам тегов ХМЛ и собсно структуре данных.
так вот… более удобного и наглядного (внедрённого ещё, оказывается, в Mactomedia Flash 8 ) я не встречал:
Код:
import mx.xpath.XPathAPI; var rssfeed_xml = new XML(); rssfeed_xml.ignoreWhite = true; rssfeed_xml.onLoad = function(success) { if (success) { var titlePath:String = "/rss/channel/title"; //путь к конкретному месту в XML. title_array = mx.xpath.XPathAPI.selectNodeList(this.firstChild, titlePath); for (var i = 0; i<title_array.length; i++) { trace(title_array[i].firstChild.nodeValue); // показывает текст тега <title> (Flash-MX: News) } trace(title_array.length); // показывает количество выбранных элементов (1) } else { trace("error loading XML"); } }; rssfeed_xml.load("http://www.flash-mx.com/news/index.xml");
покажет "26" — это количество элементов внутри тега <title>. Но эти звёздочки и прочее, как раз таки особенности синтаксиса XPath, а там всего 10 знаков для изучения
ок посмотрим на досуге. Хотя пока я не вижу чтоб оно было кардинального удобнее чем заголовок статьи.text = _root.myXMLObj.razdel[номер раздела].mainText[номер статьи в разделе].заголовок;
ок посмотрим на досуге. Хотя пока я не вижу чтоб оно было кардинального удобнее чем заголовок статьи.text = _root.myXMLObj.razdel[номер раздела].mainText[номер статьи в разделе].заголовок;
Punk T-34, ну да, суть этого класса в преобразовании ХМЛ в упорядоченный "обьект-массив" причем обходится любая вложенность дерева ХМЛ. Запись вида "/rss/channel/title" тоже конечно удобная.
но нашёл большой минус: не читает атрибуты!! Может делать сортировку по атрибутам, тоесть использовать как фильтр, но не читает.
нашёл палочку, которая зачёркивает минус и делает из него плюс: XPath4AS2 — класс, который действует на основе XPath ATI от Макромедии, только не такой кастрированный. Нормально воспринимает и атрибуты, и содержимое тегов. Единственное нормальное описание синтаксиса, которое смог найти: http://www.ultrashock.com/blog/holaso/x … t-261.html
Уровень доступа: Вы не можете начинать темы. Вы не можете отвечать на сообщения. Вы не можете редактировать свои сообщения. Вы не можете удалять свои сообщения. Вы не можете добавлять вложения.