今天我们来看看AS3中新的XML处理Ҏ(gu)Q?a hreflang="en" target="_blank">E4XQ? 直到现在QECMA脚本语言规范QECMA-262Q-QAscriptScript 3.0的核心基Qƈ没有提供M的XML数据处理cLҎ(gu)。AcriontScript之前的版本(从Flash 5中的ActionScript开始)(j)有一些处理XML数据的类和方法,但是它们q不是基于ECMAScript标准的?/p>
新的ECMA脚本语言规范W?版草E中定义了一pd新的处理XML数据的类和方法。这些类和方法的集合q命名ؓ(f)E4XQ?ECMAScript for XML"Q,ActionScript 3.0包括如下新的E4Xc:(x) XML?a target="_blank">XMLList?QName?a target="_blank">Namespace?/p>
E4XcȝҎ(gu)、属性和操作的开法基于以下的目标Q?/p>
- 单-QE4X可能的使得处理XML数据的代码容易编写ƈ且易于理解?/li>
- 一致性-QE4X的方法于Actionscript的其它部分协调一致?/li>
- 友好Q-实用非常好理解的操作W处理XML数据Q如点号Q?Q?/li>
注意Qؓ(f)避免与E4X中的新的XMLcdH,原来ActionScript 2.0中的XMLcdActionScript 3.0被重命名?a target="_blank">XMLDocumentQؓ(f)了向前兼容,在ActionScript 3.0中遗留下来的c-QXML、XMLNode、XMLParser和XMLTag--被包含进?a target="_blank">flash.xml包中。新的E4XcL核心c-Q用它们不需要importM包?/p>
初始化XML对象
XML对象可以代表一个XML元素、属性、注释、处理指令或文本元素。在ActionScript 3.0中我们可以直接将XML数据赋值给变量Q?/p>
var myXML:XML =
<order>
<item id='1'>
<menuName>burger</menuName>
<price>3.95</price>
</item>
<item id='2'>
<menuName>fries</menuName>
<price>1.45</price>
</item>
</order>
你也可以使用new 构造器来从XML数据文本创徏一个XML对象实例Q?/p>
var myXML:XML = new XML("<order><item id='1'><menuName>burger</menuName><price>3.95</price></item></order>")
如果XML数据不是格式完好的(如少了结束标{)(j)Q那么将?x)出现运行时错误?/p>
注意Q你也可以将变量实例传入XML数据中:(x)
var tagname:String = "item";
var attributename:String = "id";
var attributevalue:String = 5;
var content:String = "Chicken";
var x:XML = <{tagname} {attributename}={attributevalue}>{content}</{tagname}>;
trace (x.toXMLString())
// Output: <item id="5">Chicken</item>
通常Q我们的应用是从外部源导入XML数据Q如web service或RSS feed,以下是一个从q程URL导入XML数据的例子:(x)
var myXML:XML = new XML();
var XML_URL:String = "http://www.example.com/Sample3.xml";
//创徏URLRequest?br />var myXMLURL:URLRequest = new URLRequest(XML_URL);
//使用URLLoader导入数据?br />var myLoader:URLLoader = new URLLoader(myXMLURL);
//d事g监听器,以在XML数据导入完成后处理XML数据?br />myLoader.addEventListener("complete", xmlLoaded);
//导入完成后,创徏使用导入的数据创建XML对象
function xmlLoaded(evtObj:Event) {
var myXML:XML = XML(myLoader.data);
trace("Data loaded.");
}
Z演示代码的清晰性,本文中的大部份示例都W?U直接用文本的Ҏ(gu)创徏XML对象?/p>
E4X包含一些直观的Ҏ(gu)XML数据的操作符Q如.和@:用于讉K属性)(j)Q?/p>
//获取W?个item的menuName?br />trace(myXML.item[0].menuName); // Output: burger
//获取W?个item的id属性?br />trace(myXML.item[0].@id);//Output:1
//获取id属性ؓ(f)2的item的menuName?br />trace(myXML.item.(@id==2).menuName); // Output: fries
//获取menuName为burger的item的price?br />trace(myXML.item.(menuName=="burger").price); // Output: 3.95
你也可以使用appendChild()Ҏ(gu)lXMLd新的子节点:(x)
var newItem:XML =
<item id="3">
<menuName>medium cola</menuName>
<price>1.25</price>
</item>
myXML.appendChild(newItem);
当然你也可以使用@?操作W来更新数据:
myXML.item[0].menuName="regular burger";
myXML.item[1].menuName="small fries";
myXML.item[2].menuName="medium cola";
myXML.item.(menuName=="regular burger").@quantity = "2";
myXML.item.(menuName=="small fries").@quantity = "2";
myXML.item.(menuName=="medium cola").@quantity = "2";
讉KXML数据
你可以?Q点P(j)?.操作W访问XML对象的子节点Q用@操作W访问某一节点的属性。考虑以下XML对象Q?
var x:XML =
<book ISBN="0942407296">
<title>Baking Extravagant Pastries with Kumquats</title>
<author>
<lastName>Contino</lastName>
<firstName>Chuck</firstName>
</author>
<pageCount>238</pageCount>
</book>
<book ISBN="0865436401">
<title>Emu Care and Breeding</title>
<editor>
<lastName>Case</lastName>
<firstName>Justin</firstName>
</editor>
<pageCount>115</pageCount>
</book>
</order>
对象x.book表示一个包含所有名UCؓ(f)book的子节点的XMLList对象Q该XMLList包含两个XML对象Q两个book节点Q?/p>
对象x..lastName表示一个包含XML?wi)结构下部所有的lastName属性的XMLList对象Q该XMList包含两个XML对象Q两个LastName属性)(j)?/p>
对象x.book.editor.lastName表示一个包含所有x对象的所有名UCؓ(f)book的子节点的所有名UCؓ(f) editor的子节点的所有lastName节点的XMLList对象Q该XMLList只包含一个XML对象(gؓ(f)"Case"的lastName? ??/p>
讉K父节点和子节?/strong>
parent()Ҏ(gu)q回XML对象的父节点?/p>
你可以用子节点列表的顺序烦(ch)引值来讉K特定的子节点Q例如,假定某一XML对象x有两个名UCؓ(f)book的子节点Q你可以如下讉K它们Q?/p>
//W?个book节点
x.book[0]
//W?个book节点
x.book[1]
要访问孙子节点,我们可以如下直接使用儿子和孙子节点的索引值来讉KQ?/p>
x.book[0].title[0]
不过如果x.book[0]只有一个名UCؓ(f)title的子节点的话Q那么可以省略烦(ch)引:(x)
x.book[0].title
cM的,如果x对象只有一个book子节点,q且该book节点的子节点对象只有一个title对象Q那么两个烦(ch)引值都可以省略Q?/p>
x.book.title
注意Q你也可以用child()Ҏ(gu)Q直接用名U访问特定的子节点:(x)
var x.XML =
<order>
<book>
<title>Dictionary</title>
</book>
</order>
var childName:String = "book";
trace (x.child(childName).title) // Output: Dictionary
讉K属?/strong>
我们使用使用@操作W访问XMLNode属性:(x)
var myXML:XML =
<order>
<item id='1'>
<menuName>burger</menuName>
<price>3.95</price>
</item>
<item id='2'>
<menuName>fries</menuName>
<price>1.45</price>
</item>
</order>
//获取W?个item的id属性?br />trace(myXML.item[0].@id);//Output:1
使用属性或元素D滤XML数据
我们可以使用特定的元素名U和属性值来定位到特定的元素考虑以下XML对象Q?/p>
var x:XML =
<employeeList>
<employee id="347">
<lastName>Zmed</lastName>
<firstName>Sue</firstName>
<position>Data analyst</position>
</employee>
<employee id="348">
<lastName>McGee</lastName>
<firstName>Chuck</firstName>
<position>Jr. data analyst</position>
</employee>
</employeeList>
以下是正的讉KҎ(gu)Q?/p>
//lastName为“McGee”的employee对象Q第1个employee节点
x.employee.(lastName == "McGee") // The first employee node
//lastName为“McGee”的employee对象的firstName节点Q第1个employee节点的节?br />x.employee.(lastName == "McGee").firstName // The firstName property of that node
//lastName为“McGee”的id属?br />x.employee.(lastName == "McGee").@id // The value of the id attribute
//所有id属性gؓ(f)347的employee对象列表
x.employee.(@id == 347)
//id属性gؓ(f)347的employee对象的lastName子节?br />x.employee.(@id == 347).lastName
//所有id属性值大?47的employee对象列表
x.employee.(@id > 300) // An XML list with both employee properties
//所有position子节点值包含“analyst”的employee对象列表
x.employee.(position.toString().search("analyst") > -1)
使用for ... in和for each ... in 语句
ActionScript 3.0 包括了一个新用来遍历XMLList对象的的for ... in语句和for each ... in语句。例如,考虑以下XML对象QmyXML和myXML..item XMLList对象Q包含两个item XML对象节点的XML列表Q:(x)
var myXML:XML =
<order>
<item id='1' quantity='2'>
<menuName>burger</menuName>
<price>3.95</price>
</item>
<item id='2' quantity='2'>
<menuName>fries</menuName>
<price>1.45</price>
</item>
</order>
for ... in语句可以让我们遍历XMLList的所有属性名U?实际上就是个节点的烦(ch)引|(x)
var total:Number = 0;
for (var pname:String in myXML..item)
{
total += Number(myXML.item.@quantity[pname]) * Number(myXML.item.price[pname]);
}
for each ... in语句遍历XMLList的所有节点:(x)
var total2:Number = 0;
for each (var item:XML in myXML..item)
{
total2 += Number(item@quantity) * Number(item.price);
}
使用with语句
我们可以使用with语句Q来指明后箋的属性和节点值都是基于某一XML对象Q前面的for each ... inCZ代码Q用with语句的代码如下:(x)
var total:Number = 0;
for each (var item in myXML..item)
{
with (item)
{
//{内的属性和节点对象都是Zitem XML对象的,所有不需要用item.来访问?br /> total += Number(@quantity) * Number(price);
}
}
trace(total);
修改XML对象
我们可以使用prependChild()Ҏ(gu)或者appendChild()Ҏ(gu)在XML对象的子节点列表的前面或者最后面d节点Q?/p>
var x1:XML = <p>Paragraph 1</p>
var x2:XML = <p>Paragraph 2</p>
var x:XML = <body></body>
x = x.appendChild(x1);
x = x.appendChild(x2);
x = x.prependChild(<p>Paragraph 0</p>);
// x == <body><p>Paragraph 0</p><p>Paragraph 1</p><p>Paragraph 2</p></body>
使用insertChildBefore()Ҏ(gu)或者insertChildAfter()Ҏ(gu)在特定的节点前面zȝ回后面添加节点:(x)
var x:XML =
<body>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</body>
var newNode:XML = <p>Paragraph 1.5</p>
x = x.insertChildAfter(x.p[0], newNode)
x = x.insertChildBefore(x.p[2], <p>Paragraph 1.75</p>)
注意Q我们也可以在构造XML对象的时候用大括号Q{和}Q来引用变量Q?/p>
var ids:Array = [121, 122, 123];
var names:Array = [["Murphy","Pat"],["Thibaut","Jean"], ["Smith","Vijay"]]
var x:XML = new XML("<employeeList></employeeList>");
for (var i:int = 0; i < 3; i++) {
var newnode:XML = new XML();
newnode =
<employee id={ids[i]}>
<last>{names[i][0]}</last>
<first>{names[i][1]}</first>
</employee>
x = x.appendChild(newnode)
}
我们也可以?操作W来lXML对象节点赋|(x)
var x:XML =
<employee>
<lastname>Smith</lastname>
</employee>
x.firstname = "Jean";
x.@id = "239";
以上代码把XML对象X讄成如下:(x)
<employee id="239">
<lastname>Smith</lastname>
<firstname>Jean</firstname>
</employee>
我们也可以??=操作W来q结XMLListQ?/p>
var x1:XML = <a>test1</a>
var x2:XML = <b>test2</b>
var xList:XMLList = x1 + x2;
xList += <c>test3</c>
删除XML对象
E4X规范中定义有delete和deleteByIndexҎ(gu)用来删除特定的XML节点Q但是在当前版本? ActionScript 3.0实现中,q没有实现这两个Ҏ(gu)Q所有我们不能直接用这两个Ҏ(gu)Q不q我们可以用遍历XML?wi),剔除特定的节点,重新构造新的XML对象的方法来 删除某一特定节点Q以下我们将删除employee的lastname子节点:(x)
private function deleteByIndex(xmlNode:XML,index:Number):XML{
var newStr:String='';
newStr+='<'+xmlNode.localName();
for each (var att:XML in xmlNode.attributes()){
newStr+=' '+att.localName()+'="'+att.toString()+'"';
}
newStr+='>';
var i:Number=0;
for each(var node:XML in xmlNode.children()){
if(i!=index)
newStr+=node.toXMLString();
i++;
}
newStr+='</'+xmlNode.localName()+'/>';
return new XML(newStr);
}
var myXML:XML=
<employee id="239">
<lastname>Smith</lastname>
<firstname>Jean</firstname>
<address>
<city>shangrao</city>
<load>daihu</load>
<no>5</no>
</address>
</employee>
myXML=deleteByIndex(myXML,0);
以上的deleteByIndex函数有两个参敎ͼW?的参数是被删除节点的父节点,W?的参数是被删除节点的在父节点的子节点列表中烦(ch)引倹{先遍历父节点的索引属性,然后遍历其所有的子节点,跌我们要删除的节点Q然后将它们l合成新的XML对象q回?/p>
如果XML对象非常复杂Q数据量必较大的话,以上删除节点的实现方法效率是非常好低Q所有正的选择q是使用E4X定义的删除方法,不过q个功能要等到ActionScript 3.0的下一个测试版本才能够实现?/p>
XMLcd转换
我们可以XML对象和XMLList对象转换为字W串Q同L(fng)Q我们也可以字W串转换为XML对象和XMLList对象。顺便,误住所有的XML属性倹{名U和文本值都是字W串?/p>
转换XML和XMLList对象为字W串
XML对象和XMLList对象都有有两个成员方法:(x)toString()和toXMLString()Ҏ(gu)? toXMLString()Ҏ(gu)q回包含所有标{、属性、命名空间声明和XML对象内容的字W串Q对与复杂的XML对象Q包含有子元素)(j)Q? toString()Ҏ(gu)的效果和toXMLString()Ҏ(gu)的效果一P但是对与单的XML对象Q只包含一个文本元素)(j)QtoString()? 法只q回元素的文本内容:(x)
var myXML:XML =
<order>
<item id='1' quantity='2'>
<menuName>burger</menuName>
<price>3.95</price>
</item>
<order>
trace(myXML.item0.menuName.toXMLString())
// Output: <menuName>burger</menuName>
trace(myXML.item0.menuName.toString())
// Output: burger
文本字W串转换为XML对象
我们可以使用new构造方法从字符串创Z个XML对象
var x:XML = new XML('<a>test<b>');
但是如果我们试图一个非XML或者结构不完整的字W串转换为XML对象Q那么将?x)报q行旉误:(x)
var x:XML = new XML('<a>test'); // Throws an error
从InternetdRss Fead数据
以下代码读取本站的rss fead数据Q?/p>
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2005/mxml" xmlns="*" creationComplete="doInit()">
<mx:Script>
<![CDATA[
private function doInit():Void{
getRssData("http://blog.eshangrao.com/rss.php",ta_view);
}
public function getRssData(url:String, outTxt:TextArea):Void
{
private var myXMLURL:URLRequest = new URLRequest(url);
private var myLoader:URLLoader = new URLLoader(myXMLURL);
myLoader.addEventListener("complete", xmlLoaded);
}
private function xmlLoaded(event:Event):Void{
ta_view.text='load ok';
var myLoader:URLLoader = URLLoader(event.target);
XML.ignoreProcessingInstructions=false;
var myXML:XML =new XML(myLoader.data);
private var outStr:String = "";
for each (var item:XML in myXML.children()) {
if(item.localName()=='item'){
outStr += "<p><b>" + item.children()0.toString() + ":</b></p><p>";
outStr += item.children()6.toString() ;
outStr += " <br/><a href='" + item.children()1.toString();
outStr += "'><font color='#008000'>More...</font></a></p>";
}
}
//ta_view.text=myXML.toString();
ta_view.htmlText = outStr;
}
]]>
</mx:Script>
<mx:Canvas width="100%" height="100%">
<mx:TextArea id="ta_view">
<mx:layoutConstraints>
<mx:EdgeAnchor bottom="10" top="10" left="10" right="10"/>
</mx:layoutConstraints>
</mx:TextArea>
</mx:Canvas>
</mx:Application>
q行CZ(FlashPlayer8.5 required)
注意Q我们没有直接用节点名U访问节点(不知道ؓ(f)什么,如果使用item.title讉Ktitle节点的话Q返回是 I的Q可能跟我的RSS XML的中rdf指o(h)有关Q如果有朋友知道解决的办法,请告诉我Q,而是使用了children()Ҏ(gu)Q该Ҏ(gu)q回某一XML对象的所有子节点对象Q?/p>
获取更多AS3中E4Xcȝ使用信息Q请查看Adobe在线文档Q详lAPI参考:(x)Adobe Flex 2 API文档