Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Помогите с xml (http://www.flasher.ru/forum/showthread.php?t=213793)

0l3 17.01.2017 22:52

Помогите с xml
 
Привет братство. Первый раз пытаюсь создать xml-структуру на as3 и не получается..=/
Вот код..
Код AS3:

var xml:XML = new XML(<TEST />);
xml.appendChild(<lvl1 />);
xml.lvl1.appendChild(<lvl2 />);
xml.lvl1.appendChild(<lvl2 />);
xml.appendChild(<lvl1 a="1" />);
//xml.lvl1.appendChild(<lvl2 />);
xml.appendChild(<lvl1 a="2" />);
//xml.lvl1.appendChild(<lvl2 />);
 
trace(xml);

.. который создает это..
Код:

<TEST>
  <lvl1>
    <lvl2/>
    <lvl2/>
  </lvl1>
  <lvl1 a="1"/>
  <lvl1 a="2"/>
</TEST>

Проблема в том, что не получается добавить <lvl2> после каждого <lvl1>.. Первый добавляет, на втором кидает ошибку #1086.. как я не пытался, ну воще не идет.. помогите побороть =)

ZackMercury 17.01.2017 23:09

Код AS3:

var xml:XML = new XML(<TEST />);
xml.appendChild(<lvl1 />);
xml.lvl1.appendChild(<lvl2 />);
xml.lvl1.appendChild(<lvl2 />);
xml.appendChild(<lvl1 a="1" />);
xml.appendChild(<lvl2 />);
xml.appendChild(<lvl1 a="2" />);
xml.appendChild(<lvl2 />);
 
trace(xml);

Код:

<TEST>
  <lvl1>
    <lvl2/>
    <lvl2/>
  </lvl1>
  <lvl1 a="1"/>
  <lvl2/>
  <lvl1 a="2"/>
  <lvl2/>
</TEST>


0l3 17.01.2017 23:13

тут не правильно написал..
Цитата:

не получается добавить <lvl2> после каждого <lvl1>
<lvl2> должен быть вложен в <lvl1> как в первых строках.

ZackMercury 17.01.2017 23:26

Код AS3:

var xml:XML = new XML(<TEST />);
xml.appendChild(<lvl1 />);
xml.lvl1.appendChild(<lvl2 />);
xml.lvl1.appendChild(<lvl2 />);
xml.appendChild(<lvl1 a="1" />);
xml.lvl1[xml.lvl1.length()-1].appendChild(<lvl2 />);
xml.appendChild(<lvl1 a="2" />);
xml.lvl1[xml.lvl1.length()-1].appendChild(<lvl2 />);

Код:

<TEST>
  <lvl1>
    <lvl2/>
    <lvl2/>
  </lvl1>
  <lvl1 a="1">
    <lvl2/>
  </lvl1>
  <lvl1 a="2">
    <lvl2/>
  </lvl1>
</TEST>

http://help.adobe.com/ru_RU/FlashPla...3/XMLList.html

0l3 17.01.2017 23:33

Маны - это первое куда я полез за ответами, но до меня не дошло в чем была ошибка..=) Ведь на момент добавления субноды <lvl2> родитель <lvl1> уже существовал..
.. получается строкой xml.lvl1[xml.lvl1.length()-1] мы добавляем <lvl2> к последнему <lvl1> в дереве.. без этого мы лепим <lvl2> к последнему закрывающему тегу </lvl1>, который неявно представлен как /> или как?

ZackMercury 17.01.2017 23:47

Цитата:

Если вы попытаетесь использовать методы класса XML в отношении объекта XMLList, содержащего более одного объекта XML, возникнет исключение. Вместо этого следует выполнить итерацию в коллекции XMLList (например, с помощью оператора for each..in) и применить эти методы к каждому объекту XML в коллекции.
Цитата:

.. если я правильно понимаю, то строкой xml.lvl1[xml.lvl1.length()-1] мы добавляем <lvl2> к последнему <lvl1> в дереве.. без этого мы лепим <lvl2> к последнему закрывающему тегу </lvl1>, который неявно представлен как /> ???
В DOM нет открывающих и закрывающих тегов, есть объект, внутри него дети, а у объекта - атрибуты.
Тоесть, закрывающие и открывающие теги добавляются при преобразовании XML-DOM-модели в текст.

Коротко о том, почему ошибка - у вас в TEST 1 lvl1, вы обращаетесь xml.lvl1.appendChild. Вы добавляете в TEST ещё один lvl1(их теперь 2). Теперь XMLList не знает, к какому объекту вы обращаетесь из двух, и поэтому теперь он является списком, и содержит 2 элемента. При обращении к списку как к XML, он генерирует исключение.
__________________
There is no thing in this world that is not simple.

0l3 18.01.2017 00:00

Это капец какой-то.. пол-дня псу под хвост из-за того, что в один прекрасный момент xml превратился в xmllist и я по незнанию должен был это вовремя заметить... почему флеш сам не сделает свои нужные "итерации в коллекции" так чтобы я об этом не знал и выдаст то, что хочу я =)) Боже дай мне сил побороть эту гору as3-подводных камней.. куда ни ткнись - бетонная плита.. пока все сложно.. =/
Спасибо за решение, буду пилить дальше.

ZackMercury 18.01.2017 00:03

А чего хотите вы? У вас проблемы с логикой в коде, флеш не причём.
Код AS3:

var xml:XML = new XML(<TEST />);
xml.appendChild(<lvl1 />);
xml.lvl1.appendChild(<lvl2 />);
xml.lvl1.appendChild(<lvl2 />);
xml.appendChild(<lvl1 a="1" />);
//xml.lvl1.appendChild(<lvl2 />); //какой это будет элемент lvl1 из двух?
xml.appendChild(<lvl1 a="2" />);
//xml.lvl1.appendChild(<lvl2 />); //а это - какой lvl1 из трёх?
 
trace(xml);

Можно вручную указывать, какой именно
Код AS3:

var xml:XML = new XML(<TEST />);
xml.appendChild(<lvl1 />);
xml.lvl1.appendChild(<lvl2 />);
xml.lvl1.appendChild(<lvl2 />);
xml.appendChild(<lvl1 a="1" />);
xml.lvl1[1].appendChild(<lvl2 />); //какой это будет элемент lvl1 из двух?
xml.appendChild(<lvl1 a="2" />);
xml.lvl1[2].appendChild(<lvl2 />); //а это - какой lvl1 из трёх?
 
trace(xml);

Про итерацию в коллекции вы что-то не так поняли.

Также можно обращаться по атрибуту a, но для этого все элементы должны содержать этот атрибут:
Код AS3:

var xml:XML = new XML(<TEST />);
xml.appendChild(<lvl1 a="0" />);
xml.lvl1.appendChild(<lvl2 />);
xml.lvl1.appendChild(<lvl2 />);
xml.appendChild(<lvl1 a="1" />);
xml.lvl1.(@a == 1).appendChild(<lvl2 />);
xml.appendChild(<lvl1 a="2" />);
xml.lvl1.(@a == 2).appendChild(<lvl2 />);
 
trace(xml);


0l3 18.01.2017 00:19

В мане написано appendChild добавляет ноду в конец дерева.. это наверно и сбило меня с толку.. хочет добавляет, а хочет не добавляет объясняя это появлением других сущностей.. зачем все так сложно. Если я уже создал xml и наполняю его нодами, зачем меня тыкать в xmllist или другую хрень о которой я не знаю.. это тоже самое что поднять крышку унитаза на ракете а не на унитазе перед тем как на него сесть.. почему я должен знать что крышка доступа к унитазу который находится в моей ванной на самом деле находится на ракете что на мысе Канаверал.

ZackMercury 18.01.2017 00:24

Вы запутались. appendChild действительно добавляет ноду в конец дерева. Откуда XMLList знать, в какую конкретно ноду вы хотите добавить ребёнка, если таких нод несколько?
Я думаю, запутало вас то, что вы можете обращаться к XMLList как к XML, если элемент один. Это действительно немного сбивает с толку.

0l3 18.01.2017 00:26

в последнюю. Последняя хоть тресни их несколько, но последняя - одна... с точки зрения всего xml-дерева. А xmlList пытается разбить это дерево на несколько групп и спросить меня, "а тебе в какой группе последнюю ноду найти"? а кто его просит это делать и задавать мне вопрос когда я этого не жду. И если XMLList явно не создавался, то и пускай бы себе тихонько сидел пока его не позовут.
Все это конечно от не досконально изученного материала манов, но о какой открытости и удобстве для новичка может идти речь, если такая простая задача как построение xml-дерева выполняется с такими боями.. =/ прям квест безумный.. и таких моментов в as3 сплошь и рядом.. как по джунглям ползешь..

ZackMercury 18.01.2017 00:29

Пф, с чего бы именно в последнюю? Вы обращаетесь к тегу, которым обозначено несколько элементов, и хотите, чтобы возвращался последний? А это никого с толку ещё сильнее не собьёт?) А как же тогда обратиться не к последнему, если возвращаться всегда будет только последний?
К тому же, почему именно последнюю? У каждого разработчика цели разные, что, весь мир под вас должен подстроиться?)

Цитата:

и таких моментов в as3 сплошь и рядом.. как по джунглям ползешь.
Не могу не согласиться, но такое есть во всех языках. Не всегда ожидания оправдываются, и мнения о том, как должно быть реализовано у вас и разработчиков языка расходятся.

0l3 18.01.2017 00:50

Цитата:

Сообщение от ZackMercury (Сообщение 1198647)
Пф, с чего бы именно в последнюю? Вы обращаетесь к тегу, которым обозначено несколько элементов, и хотите, чтобы возвращался последний?

А как это понимать тогда
Цитата:

appendChild(child:Object):XML
Добавляет данный дочерний элемент в конце свойств объекта XML.
Я создал объект xml и пошагово начал добавлять в него ноды через appendChild() ожидая их появление в конце дерева.. пока дело не дошло до 2 уровня вложенности.. и ни один кукбук не написал как сделать это "правильно".. у всех примеры с одноуровневой структурой..=/

Nooob 18.01.2017 00:56

можно еще вот так
Код AS3:

var xml:XML = <TEST/>;
xml.* += <lvl1/>;
xml.lvl1.* += <lvl2/>;
xml.lvl1.* += <lvl2/>;
xml.* += <lvl1 a="1"/>;
xml.lvl1[1].* += <lvl2/>;
xml.* += <lvl1 a="1"/>;
xml.lvl1[2].* += <lvl2/>;

но лучше так
Код AS3:

var xml:XML = <TEST/>;
xml.appendChild(<lvl1/>);
xml.lvl1.appendChild(<lvl2/>);
xml.lvl1.appendChild(<lvl2/>);
xml.appendChild(<lvl1 a="1"/>.appendChild(<lvl2/>));
xml.appendChild(<lvl1 a="2"/>.appendChild(<lvl2/>));


0l3 18.01.2017 01:06

Спасибо братцы за решения.. надеюсь допишу этот эпический проект.

Wolsh 18.01.2017 08:58

Цитата:

А как это понимать тогда
Это объяснение того, что делает appendChild(). У Вас проблема не в appendChild(), а в том, у какого объекта Вы пытаетесь вызвать этот метод. Проблема с пониманием, что XML это не просто какой-то текст, для которого "добавить" означает "добавить после последней буквы". XML это многоуровневый объект, да еще с такой неочевидной возможностью, как одинаковые названия уровней. Ни в каких других объектах языка этого нет. Никто не может иметь два РАЗНЫХ свойства с одинаковым названием. XML может. Поэтому, если Вы в ноду <человек/> добавили две ноды <рука/> и теперь хотите к рукам добавить пальцы, Вам необходимо как-то конкретизировать, на какую именно руку. И здесь "Добавляет данный дочерний элемент в конце свойств объекта XML" означает, что палец будет добавлен в конце свойств (то есть — нод) руки. Не в конце "текста" всего XML, а в конце объекта XML <рука/>, потому что Вы вызываете метод appendChild() у объекта человек.рука
Код AS3:

человек.рука.appendChild(палец); // свойство палец будет добавлено в свойства руки

И вот, если рука у человека одна, то разночтений не возникает и обращение через оператор "точка" возвращает эту единственную руку, которая имеет тип XML и appendChild() вызывается у этой руки.
Но если рук две и больше, то человек.рука не может вернуть ссылку на конкретный объект "рука", и возвращает список всех рук, принадлежащих данному объекту "человек", в виде коллекции типа XMLList.
И вот теперь, чтобы вызвать appendChild(<палец/>) у какой-то конкретной "руки", Вам необходимо выбрать её из этого списка, указать на одну конкретную руку, "в конец свойств" которой и будет добавляться новый палец. "В конец свойств" здесь подразумевает, что если у этой руки уже есть какие-то свойства (ноды), то новое свойство окажется в конце этого списка, а не в начале, как в случае вызова метода prependChild(), только и всего. Надо только понимать, о списке свойств КАКОГО объекта идет речь. Под "объектом XML" в данной справке подразумевается тот, у которого вызывается метод appendChild(), а не весь XML-документ и не "та нода, которую я создал последней" ;)

0l3 18.01.2017 16:30

Ок, две руки у человека это XMLList. 1 рука и ее пальцы это тоже XMLList. Значит структура XML-объекта "человек" будет выглядеть так?
http://image.prntscr.com/image/cba8a...50ddc57214.png

Wolsh 18.01.2017 21:35

Структура объекта здесь не причем. К слову сказать, у XMLList нет никакой структуры, это линейный пронумерованный список ссылок на узлы XML. То есть, у XMLList не бывает вложенности или каких-то внутренних отношений элементов, а значит и структуры.
Ваш рисунок показывает, что именно вернет оператор "точка". То есть, человек.рука будет списком из двух элементов. А человек.рука[0] будет конкретным XML в самом начале этого списка.
Далее, человек.рука[0].палец будет списком пальцев на этой руке.
А человек.рука[0].палец[2] будет средним пальцем на этой руке.

Еще раз: XMLList не является частью объекта XML.
XML не содержит в себе никаких XMLList. Он содержит только ноды, которые сами по себе также являются самостоятельными XML.
XMLList это промежуточный формат данных, существующий только во время обработки XML. Это, если хотите, одномерный массив ссылок на отдельные ноды объекта XML. Закладки)) В нем находятся даже не ноды, а только ссылки на них. Иначе, если бы Вы изменили что-то в ноде, обратившись через XMLList, это изменение не затронуло бы "настоящую" ноду в XML. XMLList содержит не копии узлов XML, а только ссылки на узлы, принадлежащие объекту XML.
Всегда, когда Вы обращаетесь к свойству объекта XML через точку, Вы получаете XMLList. Это тип данных, который возвращает "точка" применительно к XML. Всегда!
Неочевидный нюанс только в том, что если в списке XMLList содержится только одна ссылка на ноду XML, то XMLList позволяет обращаться к себе так, будто он и есть эта нода XML, то есть плеер не выкинет ошибку несоответствия Типов.

0l3 18.01.2017 22:26

Спасибо. В моем случае понимание тонких материй придет только с практикой =) А где почитать про "у XMLList нет никакой структуры, это линейный пронумерованный список ссылок..".. может есть материал с описанием реализации класса XML в as3? Я имею ввиду не те барыжные буржуйские книжонки, в которых тема начинается с "для чего нужен XML", а возможно какие то техдоки?

Nooob 18.01.2017 23:52

Еще если сложно разобраться с работой E4X, то есть аналогичная реализация с помощью методов, по которым можно узнать что они возвращают XML или XMLList
Код AS3:

var xml:XML = new XML("<TEST/>");
xml.appendChild(new XML("<lvl1/>"));
xml.child("lvl1").appendChild(new XML("<lvl2/>")); //xml.lvl1.appendChild(<lvl2/>)
xml.child("lvl1").appendChild(new XML("<lvl2/>"));

Но использование E4X предпочтительнее, потому что работает быстрее

Резюмирую все что нужно помнить:
XMLList это промежуточный временный объект, который создается при обращении к любым вложенным элементам XML (будь-то атрибут, другая нода или текстовое содержимое). Если XMLList содержит один элемент, то обращение к методам и свойствам будет таким же как будто обращение идет к методам и свойствам этого элемента пруф, это сделано для удобства чтоб не писать постоянно [0] в примитивных случаях например:
Код AS3:

var xml:XML = <xml><c><d>3</d></c></xml>;
xml.@a = "1";
xml.b = "2";
var a:String = xml.@a;
var b:String = xml.b;
var d:String = xml.c.d;
//эквивалентно
var xml:XML = <xml><c><d>3</d></c></xml>;
xml.@a[0] = "1";
xml.b[0] = "2";
var a:String = xml.@a[0];
var b:String = xml.b[0];
var d:String = xml.c[0].d[0];

Если идет обращение к несуществующему элементу, то создается пустой XMLList.
А если выполнить присвоение, то несуществующие элементы создадутся
Код AS3:

var xml:XML = <xml/>;
xml.c1.ch2.ch3.* = <a b="1"/>; //<xml><c1><ch2><ch3><a b="1"/></ch3></ch2></c1></xml>

Содержимое в виде текста также является элементом XMLList под 0 индексом
Код AS3:

var xml:XML = <xml>123</xml>;
xml.*[0] = 321; //<xml>321</xml>

В целом при обращении к API XML все возвращает XMLList в котором может быть XML,XMLList,String

Чтобы удостовериться что XMLList каждый раз создается и содержит ссылки (даже на parent) можно провести такой опыт:
Код AS3:

var xml:XML    = <xml><c><d></d></c></xml>;
var d1:XMLList = xml.c.d;
var d2:XMLList = xml.c.d;
trace(d1 === d2); //false
d1.appendChild(<a>1</a>);
trace(d2.toXMLString()); //<d><a>1</a></d>


0l3 19.01.2017 00:35

Такой вопрос меня волнует, опять пол дня ушло на безуспешные попытки:
как мне прочитать значение атрибута @b в неком елементе, если я знаю что значение его атрибута @a="10"?
Код:

<xml>
  <lvl1 a="10" b="100" />
  <lvl1 a="20" b="200" />
</xml>

Пытаюсь использовать xml.lvl1.(@a == "10") ..а дальше как лепить .@b? Или нужно создавать XMLList для результата или что, не пойму..

Ага ,вот по вашей ссылочке E4X прошел, там решение:
Код AS3:

var sales:XML = <sales vendor="Джон">
    <item type="горох" price="4" quantity="6"/>
    <item type="морковь" price="3" quantity="10"/>
    <item type="чипсы" price="5" quantity="3"/>
  </sales>;
 
trace(sales.item.(@type == "морковь").@quantity );


Nooob 19.01.2017 01:42

Чтобы точно узнать что возвращается используй toXMLString(), чтобы понять что делать дальше
Код AS3:

//вместо
trace(xml.lvl1.(@a == "10")); //
//использовать
trace(xml.lvl1.(@a == "10").toXMLString()); //<lvl1 a="10" b="100"/>
trace(<lvl1 a="10" b="100"/>.@b); //100
//значит
trace(xml.lvl1.(@a == "10").@b); //100


0l3 19.01.2017 02:08

Ложусь спать с надеждой на завтрашний день и новые знания =) Благодарю.

Не удержался, проверил полезность .toXMLString(), этого инструмента мне не хватало =)

0l3 23.01.2017 16:50

Казалось бы простая задача, но у меня вызывает трудности.. Пытаюсь обойти каждый узел дерева.
Когда делаю так..
Код AS3:

var xml:XML = <xml>
  <LVL0 name="lvl0">
    <LVL1 name="lvl1"/>
    <LVL1 name="lvl1"/>
      <LVL2 name="lvl2"/>
      <LVL2 name="lvl2"/>
    <LVL1 name="lvl1">
  </LVL0 name="lvl0">
</xml>
 
for each (var item:XML in xml..*.*)
{
  trace("=>", item.toXMLString(), "Parent:", item.parent().@name);
}

.. получаю только список LVL1. Маркер "=>" показывает обращение к узлу и оказался нужен так как trace() показывает не только елемент, а и его потомков, к которым реально обращения не происходит. Как это побороть и перебрать пошагово все узлы xml-дерева? Вариант с вложенными циклами мне не подходит так как я не знаю глубины дерева.. точнее она может измениться (LVL0.. LVLn).

_______________________
Нашел тему (http://www.flasher.ru/forum/showthread.php?t=123545) изучаю..

Wolsh 24.01.2017 01:35

Код AS3:

                        for each (var node:XML in xml.descendants())
                        {
                                trace(node.name().localName, "parent:", node.parent().name().localName);
                        }

Добавлено через 1 минуту
ну, или просто .@name если нужны атрибуты а не имена нод.

0l3 24.01.2017 02:33

И как я его не заметил =/ не внимательный.
Код:

descendants(name:Object = *):XMLList
Возвращает все потомки (дочерние объекты всех уровней) объекта XML, обладающие данным параметром имени.

Спасибо.

Nooob 24.01.2017 22:52

для обхода дерева c неизвестной глубиной используют рекурсию
Код AS3:

function print (xml:XML):void
{
        trace(xml.toXMLString());
        for each (var child:XML in xml.*)
        {
                print(child);
        }
}
print(xml);

или цикл со стеком
Код AS3:

var stack:Vector.<XML> = new <XML>[xml];
while (stack.length > 0)
{
        var node:XML = stack.pop();
        trace(node.toXMLString());
        var children:XMLList = node.*;
        for (var i:int = children.length() - 1; i >= 0; i--)
        {
                stack.push(children[i]);
        }
}

в зависимости от задачи

0l3 25.01.2017 01:49

А почему для стека используется Vector а не Array?

ZackMercury 25.01.2017 01:50

0l3, разница лишь в том, что Vector - типизированный. В любом случае можно использовать оба варианта.

0l3 25.01.2017 16:29

Я встречал код, в котором объекты экрана тоже добавлялись в список типа Vector и я подумал, что у него есть некие преимущества перед Array о которых я не знаю.. но это уже тема отдельного топика. Спасибо.

undefined 25.01.2017 16:56

Вектор быстрее array вот и все преимущества


Часовой пояс GMT +4, время: 18:26.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.