четверг, марта 15, 2007

Некоторые тонкости использования E4X

1. Устанавливайте resultFormat="e4x" для HTTPService

По умолчанию, resultFormat для <mx:HTTPService> является "object". Но при получении XML данных, "object" - это не то, что вам нужно. Если же задать "e4x", то lastResult будет являтся XML объектом, который можно парсить с помощью E4X выражений.

2. E4X выражения не ссылаются на самый верхний тег XML

Итак, имеем <mx:HTTPService>, названный myService с resultFormat="e4x", возвращающим следующую структуру:

<?xml version="1.0"?>
<people>
<person>mike</person>
<person>sho</person>
<person>nj</person>
</people>

Эти данные содержатся в myService.lastResult (или в event.result.) Как получить XMLList всех элементов <person>?

Часто думают, что E4X выражения составляют от корневого тега <people>:

var personNodes:XMLList = myService.lastResult.people.person;
// неправильно
А правильно так :
var personNodes:XMLList = myService.lastResult.person;
// правильно

3. Используйте for each, а не for

ECMAScript давно имеет структуру for (ключ в коллекции). Но обратите внимание, что при использовании этого выражения переменной цикла является ключ коллекции, а не значение текущего элемента, поэтому в цикле необходимо писать коллекция[ключ] для ображения к его значению.

E4X добавляет следующую структуру (которую можно использовать на любой коллекции): for each (значение в коллекции). Рассмотрим примеры:

for (var key:* in myService.lastResult.person)  { 

var value:* = myService.lastResult.person[key];
...
}
А теперь for each:
for each (var value:* in myService.lastResult.person)  
{... }


4. Используйте for each (child in parent.*), вместо for each (child in parent)

Итак, есть документ :

var mydocument:XML = 
<root>
<cat>
<mouse />
<mouse />
<mouse />
</cat>
</root>
var cats:XMLList = mydocument.cat; // это только один элемент
Теперь необходимо перебрать всех мышей у этого кота.
Чтобы получить атрибуты объекта ActionScript, можно написать следующее:

var o:Object = ...;  for each (var property:* in o) ...
Вы думаете, что следующим образом вы делаете тоже самое:

for each (var mouse:XML in cats) ... // неправильно

Увы, E4X отличается. В E4X, "cats" - это коллекция -- список узлов <cat>, а в примере есть только один <cat>.

Поэтому, чтобы перебрать всех мышей необходимо использовать следующую структуру:

// перебрать все прямые дочерние элементы
for each (var mouse:XML in cats.*) { ... }
// или перебрать всех прямых потомков, которые являются узлами <mouse>
for each (var mouse:XML in cats.mouse) { ... }

5. E4X специально стирает различия между XML и XMLList

При изучении E4X, вы узнаете, что есть два типа данных: XML и XMLList. Вроде легко, но потом появляются проблемы с неправильной типизацией данных.
var mydocument = 
<root>
<rabbit name="Brownster Johansson McGee" />
</root>;
// 'mydocument.rabbit' - список всех узлов <rabbit>, значит
// myPetRabbit должен быть XMLList? Но я назвал переменную
// 'myPetRabbit', а не 'myPetRabbits',
// потому что я знаю, что заяц только один.
var myPetRabbit:XMLList = mydocument.rabbit;
// Как же его зовут? Почему следующее выражение не вызывает ошибки,
//ведь myPetRabbit - это XMLList?
trace(myPetRabbit.@name);

Причина в том, что E4X намеренно стирает различия между XML и XMLList. Каждый XMLList, который содержит один элемент, будет рассматриваться как XML. (Если 'myPetRabbit' будет содержать несколько узлов, то myPetRabbit.@name будет возвращать список всех атрибутов "name" все узлов <rabbit>.)

Например, рассмотрим документацию по методу XMLList.toString():

  • Если объект XML имеет простую структуру, то метод toString() возвращает содержимое узлов без тегов, атрибутов, пространств имен и т.п.

  • Если объект XML имеет сложную структуру, то метод toString() возвращает все содержимое, вклюяая теги, атрибуты и т.п.

То есть если XMLList содержит <node>hello</node>, то toString() вернет "hello"; но если он содержит <node>hello</node><node>goodbye</node>, toString() вернет "<node>hello</node><node>goodbye</node>" (а не "hellogoodbye"). Если же вам всегда нужен полный XML, используйте toXMLString() вместо of toString().

6. Внимание! Простое выражение может вам дорого обойтись

При использовании простых объектов нет ничего удивительного в использовании следующего кода:

var x:Object = ...;  
if (x.y.z == 3)
foo(x.y.z);

Код работает быстро, проблем не вознкает.

Но в E4X операция типа "x.y.z" будет означать, что цикл проходит через всю XML-структуру и ищет соответствующие совпадения:

var mydocument:XML = ...;  
if (mydocument.cat.mouse.length() == 3)
{foo(mydocument.cat.mouse)};

Итак, если вам потом понадобиться использовать результат, то лучше сохранить его в XMLLis переменнойt:

var mydocument:XML = ...;  
var mice:XMLList = mydocument.cat.mouse;
if (mice.length() == 3)
{foo(mice);}

7. Используйте дебаггер


Отладчик поможет вам разобраться в значениях XML и XMLList переменных.

XML variables


Отсюда

2 комментария:

Peter Karabinovich комментирует...

спасибо, хоть какая-то ясность появилась, а то в Flex2 Developers Guide про e4x практически нефига нет

Andrey Gorbatov комментирует...

полезная статья http://xpoint.ru/know-how/JavaScript/E4X

правда для JS, но e4x и в африке e4x.