原文 : as3 e4x rundown by Roger Braunstein
翻译者 : 雨飞
说明:有很多地方看不懂,或者不好直接翻译,就按照自己的理解写了,所以看的时候请看一下原文。 :roll:
相关资源:introduction to ECMAScript for XML (E4X)[IBM]
e4x - 对xml操作的一些示例[N神]
AS3中e4x纲要
e4x本质上是一种全新的语言,同正则表达式(Regular Expression)一样,它有自己完整的语法,但它们都是as3语法的一部分.
注:作者貌似对e4x很不满意,具体请看原文.
先准备要用的xml:

var thePeople:XML =<people>
<
person name="Mims Wright" suffix="III">
<
age>27</age>
<aka>Mims H Wright<
/aka>
<
aka>Teh AWesoeomes!</aka>
<bio><!--[CDATA[This guy <b>rulz<b>!]]--><
/bio>
<
/person>
<person name="Roger Braunstein">     
<age>26<
/age>
<
aka>Rog</aka>
<aka>That guy<
/aka>
<
bio><!--[CDATA[Likes food.]]--></bio>
<
/person>
 <
/people>;

xmllist 对比 xml

首先,和AS2时候不同的是,在编辑器输入的XML可以作为一个XML类型的变量.然后, 需要了解这两个类: XML和xmllist .了解E4X xmllist是XML节点的列表。
差别是, XML必须有唯一一个根结点;xmllists则比较灵活. 可以有多个根节点。
比如, 上面的例子是XML ,因为它只有一个根结点. .而一个xmllist是由零或更多的根结点组成,如:

<age>27</age>
<age>26<
/age>

因为有两个根节点.所以它不能作为XML, 不过, 由于每个节点本身是一个根结点,可以 认为它是一份XML列表。需要注意, xmllist也可以有一个(同xml )或零个节点.不过,大部份的基本e4x操作都是筛选操作(filter operations).分析xml和查找它的结点。通常,你要找到某个节点. 要做的操作是从很多结点得到这个结点。所以你会发觉,当做这些操作时,XML总是转化为xmllist,且大部分的时间是在处理xmllists .
基本操作
1.

thepeople.person.age

使用dot syntax按节点的名字选择子节点. 变量已经与根结点绑定,所以不用在表达式写 了. 上面的表达式连续进行了两次筛选(filter).
第一,得到根节点下的一切 节点,也就是说, 生成一个xmllist .
第二,在上面的基础上得到所有的节点.同样,也是一个xmllist对象.
两次操作的结果:

<age>27</age>
<age>26<
/age>

2.

thepeople.person.@name

用@符号来选择属性.首先查找根结点下所有 节点;然后查找这些结点下面所有的属性.这次得到不再是子结点的列表,而是结点属性的列表。但返回的仍然是一个xmlList对象,当然,不再是合法的xml。
3.

thePeople.person.(age >= 21)

这个操作很强,你可基于任意的标准来筛选要得到的结点. 再一个例子:

thePeople.person.(@name.charAt(0) == "R"); //Roger's <person> node

4.

thepeople.person [1]

使用括号来获取xmllists对象中的结点 ,同数组的索引类似. 这个办法在XML和XMLList都适用。结果:

<person name="Roger Braunstein">     
<
age>26</age>
<aka>Rog<
/aka>
<
aka>That guy</aka>
<bio><!--[CDATA[Likes food.]]-->
<
/bio>
<
/person>

当查找一个具体的节点,适当的操作可以返回所有匹配的结果. 例如,你可以建立一个筛选(filter)操作,它的返回应该只有一个匹配, 但你可能会发现每次测试都会返回第一个结果
例如,

thePeople.person.(@name == "Roger Braunstein").age; //XMLList with one node
thePeople.person.(@name == "Roger Braunstein")[0].age[0]; //XML

由于复杂e4x表达式会被自动添加[0],造成污染. 第二个表达式表现为XML→XMLList→XMLList→XML→XMLList→XML
5.

thePeople..age

用两个圆点表示在任何层级(而不只是下一层级)查找所有适用的结点, 例如,你可以在一个xhtml文件找到所有div标签,这样. 结果是:

<age>27</age>
<age>26<
/age>

6.

thePeople.*.age

* 操作符会选择所有子节点. 例如有一个结点中并非 , 但它仍有节点.那么这个 结点也将被返回,此表达式并不关心第一代结点的名称.只是返回匹配第二代结点的所有第一代结点. :roll:

字符串和XML
当你对xml元素进行输出操作时,如果没有指明转换函数,那么将会调用toString()函数,你可输出像XML这样的”复杂内容(complex content)”或者字符串那样的”简单内容(simple content)”. 你可以使用hassimplecontent ( )和hascomplexcontent ( )来测试:简单内容是文本节点,属性节点或一个单一XML元素没有xml子节点(例如26) .

trace(thePeople.person.(@name =="Roger Braunstein").age); //26

上面表达式返回XMLList对象 ,但只有一个元素, 一个文本节点,然后XMLList.toString()打印出文本值26 . 同样地,

trace(thePeople.person[0].@name); //Mims Wright

用toString()作为一个简单的方式来获取属性或者单一XML中(如26)的文本的内容.如果你想打印出XML形式的内容,可以使用toXMLString() .

trace(thePeople.person.(@name == "Roger Braunstein").age.toXMLString());//<age>26</age>

可以用text()获得XML中文本节点内容 . 举例来说,thePeople.person[0].@name,得到文本节点值.

trace(thePeople.person[0].age.text()[0]); //27

这个表达式将返回一个XMLList对象中所有文本节点.我们可以像操作数组一样,我们可以得到所有的文本节点值:

trace(thePeople..age.text()); //2726


toString()输出没有增加空格. toXMLString()会增加,但由于他们都是文本节点,所以都同样输出:
27
26

函数形式属性(Function-style Properties)
(注 : 这一段实在是不怎么看的懂,附上原文,能看懂的指点一下。)
【In E4X, using a property name in an expression finds child nodes with the specified name, like thePeople.person. We want to be able to name XML nodes anything we want, so all the filters, calculated properties, and functions of XML nodes are implemented as functions. In other words, thePeople.person.length would look for nodes in the XML; but we can find the number of nodes with:
thePeople.length(); //2
All the tests and filters are implemented as functions, even if corresponding properties in other classes are implemented as implicit accessors.】

在e4x中 , 用特定的节点名称来表示子结点,如thepeople.person.但是, thepeople.person.length表示将在XML中查找节点,而我们可以用这样形式:

thePeople.length(); //2

来得到 节点的个数.

同义表达式(Synonyms) , 轴(Axis)
“轴” 是指运动的方向,如立体空间中x,y和z轴,但在XML中我们可
“轴” 是指运动的方向. 在空间中,我们可以在沿着x , y ,和Z轴移动(travel). 但是,在XML中,我们只可以纵向遍历子节点,以及兄弟节点,等等.
对比E4X 和 XPath ,E4X中的轴远不及(lose out)XPath中的强大,E4X中少了很多重要的东西.

一些基本”轴(Axis)”:
1.

attribute(name), attributes()

这些”轴”可以找到XML中相应的属性 . 第一个查找名称为name的属性,而第二个返回所有属性. 这两个表达式的功能可以简单的用@name和@ *实现 .

重要! “轴” attribute(name)效率比@name好很多! @name只能在所在查找的属性存在于所有节点中时有效. 这样会有很大的局限,
所以最好还是使用前者.

trace(thePeople.person.@suffix); //OK, list of all suffix attributes
 
trace(thePeople.person.(@suffix == "III"));
 
//ReferenceError: Error #1065: 变量 @suffix 未定义.at Untitled_fla::MainTimeline/Untitled_fla::frame1()
 
trace(thePeople.person.(attribute("suffix") == "III")); //OK, Mims' node

2.

child(name), children()

这些轴用来查找给定节点的子节点, 返回第一代后代的节点. 第一个”轴”用来查找一个具体的名字的子节点.第二个”轴”返回所有的子节点,
和前的用的*运算符效果一样.
下面几个”轴”是等价的.

thePeople.child("*") == thePeople.children() == thePeople.*

我们可以使用一个变量名作为参数传递给一个”轴”函数.

var interestedNode:String = "age";
    
trace(thePeople.person[0].child(interestedNode)); //27

你也可以像访问数组一样来使用child(),作者的意见是这样做会造成误解.
3.

descendants(name)

此”轴”返回一个名称与参数相匹配节点的所有子孙(descendants)(子,孙子等),和child()以及children()不相同 ,当没有参数传递的时候,它将返回所有的子孙(descendants). 也就是说,此”轴”默认情况等价于* . 它的简单实现为(..).

thePeople..age == thePeople.descendants("age")
    
thePeople..* == thePeople.descendants() == thePeople.descendants("*")

4.

parent()

此”轴”返回节点的父级,它没有简单实现.一个例子:

var age0:XML = thePeople..age[0]; //<age>27</age>
  
trace(age0.parent().@name); //Mims Wright

到这里,你可能注意到少说了兄弟节点(siblings)的查找,在AS2中可以用nextSibling和previousSibling很容易的实现,而在as3变得比较麻烦,你需要先找到父级节点,再取得父级节点的所有子节点,然后按索引查找兄弟节点.作者的一个方法:

var node:XML = thePeople.person[0];
//in general, for any node:
node.parent().children(); //all siblings
node.parent().*[node.childIndex() + 1]; //next sibling
node.parent().*[node.childIndex() - 1]; //previous sibling

The ancestor axis (parent, grandparent, great-grandparent, etc.) is also missing from E4X.

节点类型(nody types)

除了上面所说的,有些”轴”只能操作特定类型的节点.实际上,XML中的节点类型有:元素(element)、注释(comment),文本(text),或者处理指令(processing instruction)。这意谓着那些输入的XML变量有时候可能并不是有效的XML文档(documents),例如只有一个文本节点的XML变量就不是有效的XML文档.你可以用nodeKind()函数来获得节点的类型,此函数返回”element”,”comment”,”text”,”processing-instruction”,注释(comment)和处理指令(processing instruction)会被忽略(ignore)。

轴elements(), comments(), text(), 和processingInstructions()等同于Children().

创建或者更新值

E4X中XML变量是可写的(writeable),你可以修改已经的属性(attributes)和元素(elements)的值.如:

thePeople.person[1].age = 80; //sets my age to 80
thePeople.person.age = 80; //ERROR! you can't set multiple elements with one assignment
thePeople.person[1].@suffix = "Sr."; //set my suffix to Sr.

当然,你也可以创建新的XML节点,在原来的变量基础上再敲几下键盘而已,不过,e4x 充许像下面这样嵌入变量来定义XML变量:

var names:Array = ["Alice", "Bob", "Ivan"];
var newPerson:XML = <person name={names[int(Math.random() * names.length)]}></person>;

不仅仅在属性中可以使用事先定义的变量,节点名称,整个节点都可以预先定义。

var nodeName:String = "age";
var newAge:XML = <{nodeName}>{Math.round(Math.random() * 100)}</{nodeName}>;
var names:Array = ["Alice", "Bob", "Ivan"];
var newPerson:XML =
<person name={names[int(Math.random() * names.length)]}>
    {newAge}
  <
/person>;

你可以定义一个没有名称的根节点的XMLList对象。

var aliases:XMLList = <>
    <
aka>Elmo</aka>
    <aka>The Fonz<
/aka>
    <
aka>Peanut Butter</aka>
<
/>;

添加值
有很多方法可以给现有的XML添加值.
操作符”+=”

thePeople.person[1].aka += <aka>Rog</aka>;
thePeople.person[1].* += <eyes>Brown<
/eyes>;
thePeople.person[1].children() += <test>hi</test>; //ERROR!

注:作者也不知道最后那个表达式为什么不能正确的执行。me too ! :roll:

也可以像操作数组那样添加节点。如:

thePeople.person[0].eyes[0] = "Green"; //adds <eyes>Green</eyes> to Mims' node.

appendchild ( ) , insertchildbefore ( ) 和insertchildafter ( )方法:

thePeople.person.(@name == "Mims Wright").appendChild(<aka>Von Kaiser</aka>);

删除值
删除值的操作用 “delete 节点/属性” 来实现,没有removeChild()函数。。

delete thePeople.person.bio; //delete all <bio> tags
delete thePeople..bio; //Doesn't work but no error. Why?!?
delete thePeople.person.@suffix; //deletes all suffix attributes of <person> tags
delete thePeople.person.(@name == "Roger Braunstein").*; //clears out children of my node

命名空间

注:作者以后会再写一关于命名空间的详细教程。
在E4X中充许构造一个默认的命名空间,这个命名空间会被应用到你创建的XML节点中。

var xhtml:Namespace = new Namespace("http://www.w3.org/1999/xhtml");
default xml namespace = xhtml;
var xml:XML = <html/>; //notice we didn't set a namespace manually
trace(xml.toXMLString());
//<html xmlns="http://www.w3.org/1999/xhtml"/>