Flex 3入门教程: 加载 XML 数据

Actionscript 3.0办好一组类,基于ECMAScript for XML(E4X)说明(ECMA-357 2第二版)。这些类功能强大,使用简单,对处理XMLdata数据非常有用。使用E4X,使用XML数据更快的开发代码称为可能,对比以前的编程技术。作为一个好处,你生产的代码更容易读懂了。

  • 介绍XML
  • 对XML元素与属性赋值
  • 通过传递数据引用创建XML对象
  • 装配与改变XML对象
  • 查询XML数据


介绍XML
许多服务器端应用程序使用XML数据结构,那么你可以在ActionScript中使用XML类来创建优雅的富互联网应用程序。例如那些链接到Web service的应用。web service是连接应用程序的重要的方法,例如,一个Adobe Flash Player9 应用程序和一个在web服务器上的应用程序通过公共标准,例如Simple Object Access Protocol(SOAP)

在Adobe Flex中,ECMAScript for XML说明书定义了一系列的类和功能来处理XML数据。这些类和函数的集合被称为E4X.两个主要的类是XML和XMLList。

注意:在ActionScript 2.0中有一个XML类。在ActionScript 3.0中,它被重命名为XMLDocument这样就不会与新的,作为E4X一部分的XML类发生冲突了。在ActionScript 3.0中,上一个版本遗留的类——XMLDocument,XMLNode,XMLParser和XMLTag——都被包含在flash.xml包中,主要是为了向下兼容。E4X类是核心类;你需要导入包才能使用他们。本快速说明没有设计对传统的ActionScript 2.0的类逐一细说。想了解他们,查看flash.xml包,在Flex 3 Language Reference中

在下边的例子中,你创建了一个XML文档,命名为myBooks。创建一个XML文档在ActionScript,通过在Actionscript块中书写XML并赋值给一个变量。由于在Flex中,XML是本地数据类型,就像Number或Boolean一样。

myBooks的XML文档包含两个book元素(element)(也被称为node(节点))。第一个book元素拥有4个子元素,名称值title,author,amazonUrl和pageCount。

要通过XML实例访问元素,使用点标示(.)就像存取一个对象的属性一样。那么,举个例子,要获得book节点的引用,你要写成myBooks.book。这就返回了一个XMLList时间,他包含了myBooks的XML中的2个book节点。要存取列表中指定节点,你需要使用数组表示法。例如,要获得第一本数节点的引用,可以写为myBooks.book[0]。如果你使用过ActionScript中的对象和数组,你应该对点操作符和数组语法风格比较熟悉。然而,E4X比这更进一步,可以按指定属性名在XML中搜索节点。

下边的例子中,使用搜索ISBN属性获得第一本书的引用。属性在 E4X中at-sign(@)为前缀描述属性,写为@ISBN。语句myBooks.book.(@ISBN==”159059181”)翻译为“找到一个属性ISBN值等于159059181的book节点”。另一个例子描述更高级的查找技术。


例子

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
width="440" height="400"
initialize="initializeHandler();"
>

<mx:Script>
<![CDATA[

[Bindable] public var a:XMLList;
[Bindable] public var b:XMLList;
[Bindable] public var c:XMLList;
[Bindable] public var d:XMLList;

// Model: XML structure describing
// some of the books in my collection.
[Bindable]
private var myBooks:XML =
<books>

<book ISBN="1590595181">
<title>Foundation ActionScript Animation: Making Things Move</title>
<author>Keith Peters</author>

<amazonUrl>http://tinyurl.com/npuxt</amazonUrl>
<pageCount>470</pageCount>
</book>

<book ISBN="1582346194">
<title>Send in the Idiots: Stories from the Other Side of Autism</title>

<author>Kamran Nazeer</author>
<amazonUrl>http://tinyurl.com/lo5ts</amazonUrl>
<pageCount>500</pageCount>

</book>
</books>

private function initializeHandler():void

{
// An XML list that contains both book nodes.
a = myBooks.book;

// Keith Peters
b = myBooks.book[0].author;

// 470

c = myBooks.book.(@ISBN=="1590595181").pageCount;

// Delete the first book node.
delete myBooks.book[0];

// Send in the Idiots...
d = myBooks.book[0].title;
}
]]>
</mx:Script>


<!-- User interface -->
<mx:Panel
title="XML lookup results"
paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10">

<mx:Text text="{'a: ' + a}" width="300"/>
<mx:Label text="{'b: ' + b}"/>
<mx:Label text="{'c: ' + c}"/>

<mx:Label text="{'d: ' + d}"/>
</mx:Panel>

</mx:Application>

运行结果

对XML元素与属性赋值


使用@和点( . )操作符不只可以从XML结构中读取数据的值,也可以为其赋值。

在下边的例子中,创建一个XML结构master-detail视图。master视图包含一个DataGrid 组件,用来显示书的列表。detail视图包含控件,用来编辑master视图中当前选中的图书。

master 和detail视图使用数据绑定和E4X来读取和更新XML中的数据。

下边的例子通过一下方法使用E4X:

  • myBooks.book引用book元素的XMLList对象。
  • myBook.book[selectedBookIndex]引用当前被选中的book元素。
  • myBook.book[selectedBookIndex].title引用当前被选中book元素的子元素title

要使用当前被选中图书的title更新TestInput控件tiltleInput,需要绑定TestInput控件tiltleInput的text属性到myBooks.book[selectedBookIndex].title。类似地,要使用用户最终输入更新XML,当TestInput控件tiltleInput的text属性改变时,将TestInput控件tiltleInput的text属性的值赋值给myBooks.book[selectedBookIndex].title。

detail视图中的另一个组件使用同样的方法正确的工作。


例子

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
width="500" height="470"
creationComplete="myDataGrid.selectedIndex=0;"
>

<mx:Script>
<![CDATA[
// Model: XML structure describing
// some of the books in my collection.
[Bindable]

private var myBooks:XML =
<books>
<book ISBN="1590595181">

<title>Foundation ActionScript Animation: Making Things Move</title>
<author>Keith Peters</author>
<amazonUrl>http://tinyurl.com/npuxt</amazonUrl>

</book>
<book ISBN="1582346194">
<title>Send in the Idiots: Stories from the Other Side of Autism</title>

<author>Kamran Nazeer</author>
<amazonUrl>http://tinyurl.com/lo5ts</amazonUrl>
</book>

</books>
]]>
</mx:Script>

<!-- Keep track of the currently selected book -->
<mx:Number id="selectedBookIndex">{myDataGrid.selectedIndex}</mx:Number>


<!-- User interface -->
<mx:Panel
title="Assigning XML data"
paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10"
>

<!-- Master view: Display all books -->
<mx:DataGrid id="myDataGrid" dataProvider="{myBooks.book}">

<mx:columns>
<mx:DataGridColumn dataField="@ISBN" headerText="ISBN" width="85"/>
<mx:DataGridColumn dataField="title" headerText="Title"/>

<mx:DataGridColumn dataField="author" headerText="Author"/>
<mx:DataGridColumn dataField="amazonUrl" headerText="Web site">

<mx:itemRenderer>
<mx:Component>
<mx:LinkButton
label="Visit"
click="navigateToURL(new URLRequest(data.amazonUrl), 'blank');"
/>
</mx:Component>

</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>

<!-- Detail view: Display currently selected book for editing -->

<mx:Form width="100%" autoLayout="false">
<mx:FormHeading label="Edit book details"/>

<mx:FormItem label="ISBN:" width="100%">
<mx:TextInput
id="isbnInput"
width="100%"
text="{myBooks.book[selectedBookIndex].@ISBN}"
change="{myBooks.book[selectedBookIndex].@ISBN = isbnInput.text}"
/>

</mx:FormItem>
<mx:FormItem label="Title:" width="
100%">
<mx:TextInput
id="titleInput"
width="100%"
text="{myBooks.book[selectedBookIndex].title}"
change="{myBooks.book[selectedBookIndex].title = titleInput.text}"
/>

</mx:FormItem>
<mx:FormItem label="Author:" width="100%">
<mx:TextInput
id="authorInput"
width="100%"
text="{myBooks.book[selectedBookIndex].author}"
change="{myBooks.book[selectedBookIndex].author = authorInput.text}"
/>

</mx:FormItem>
<mx:FormItem label="Amazon Url" width="100%">
<mx:TextInput
id="amazonUrlInput"
width="100%"
text="{myBooks.book[selectedBookIndex].amazonUrl}"
change="{myBooks.book[selectedBookIndex].amazonUrl = amazonUrlInput.text}"
/>

</mx:FormItem>
</mx:Form>
</mx:Panel>
</mx:Application>

运行结果

通过传递数据引用创建XML对象


前边介绍XML的例子展示了使用XML文档初始化XML对象的方法。当创建一个XML文档时,你也可以通过引用(来自其他变量的引用)传递数到XML对象中,通过大括号扩起来的变量值引用。

如果你创建的XML结构不是有效的XML,你会看到类型错误的运行时错误。

下边的例子动态的创建了一个XML对象。它基于用户提供的变量来创建属性名,属性值,标签名和标签内容。例子检查了TypeError的情况,通过使用try…catch块环绕XML初始化代码。

例子

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
width="500" height="400"
initialize="createXML();"
>
<mx:Script>
<![CDATA[
[Bindable]
public var XML:XML

private function createXML():void

{
try
{
// Create the XML object using the values provided
// by the user for the tag name, attribute name,
// attribute value and the tag's contents.
XML =
<{tagName.text}
{attributeName.text}={attributeValue.text}

>
{content.text}
</{tagName.text}>;
}
catch (e:TypeError)

{
// Type error encountered while trying to create the
// XML object. The form must not be valid. Inform
// the user.
XML = <note>Fill the form to see the tag here.</note>;
}

}
]]>
</mx:Script>

<!-- User interface -->
<mx:Panel
title="Passing XML data by reference"
layout="horizontal"
>

<mx:Form>
<mx:FormItem label="Tag name:">
<mx:TextInput id="tagName" change="createXML();"/>
</mx:FormItem>

<mx:FormItem label="Attribute name:">
<mx:TextInput id="attributeName" change="createXML();"/>

</mx:FormItem>
<mx:FormItem label="Attribute value:">
<mx:TextInput id="attributeValue" change="createXML();"/>
</mx:FormItem>

<mx:FormItem label="Tag content:">
<mx:TextInput id="content" change="createXML();"/>
</mx:FormItem>


<mx:HRule width="100%"/>

<!-- Display the resulting XML -->
<mx:TextArea
editable="false"
width="300" height="50"
text="{xml.toXMLString()}"
/>

</mx:Form>
</mx:Panel>
</mx:Application>

运行结果

装配与改变XML对象


出可以对XML元素与对象赋值外,你也可以通过使用E4X组装与传递XML对象。

下边的例子中,你可以使用prependChild()和append()方法来向XML对象的列表中的前边或后边增减一个属性。类似的,使用insertChildBefore()方法和insertchildAfter()方法来增加属性在指定的属性之前或之后。要删除元素,使用delete()方法从XML中移除节点。

例子

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
width="500" height="600"
creationComplete="myDataGrid.selectedIndex=0; validateForm();"

>

<mx:Script>
<![CDATA[

import mx.controls.Alert;

// Constants
private const SELECTED_ITEM:uint = 0;
private const THE_LIST:uint = 1;
private const BEFORE:uint = 0;
private const AFTER:uint = 1;

// Flag: is the form valid?
[Bindable]
private var formIsValid:Boolean;

// Flag: does a selection exist in the data grid?
[Bindable]

private var selectionExists:Boolean;

// Holds the index of the next item in the
// data grid following the deletion of a book item.
private var newSelectedIndex:int;

// Model: XML structure describing
// some of the books in my collection.
[Bindable]
private var myBooks:XML =
<books>

<book ISBN="1590595181">
<title>Foundation ActionScript Animation: Making Things Move</title>
<author>Keith Peters</author>

<amazonUrl>http://tinyurl.com/npuxt</amazonUrl>
</book>
<book ISBN="1582346194">
<title>Send in the Idiots: Stories from the Other Side of Autism</title>

<author>Kamran Nazeer</author>
<amazonUrl>http://tinyurl.com/lo5ts</amazonUrl>
</book>

</books>

// Add a new book.
private function addBookHandler():void
{

// Create a new XML Object from the form information
var newBook:XML =
<book ISBN={isbnInput.text}>
<title>{titleInput.text}</title>

<author>{authorInput.text}</author>
<amazonUrl>{amazonUrlInput.text}</amazonUrl>
</book>;

// Save the selected book's index so it can be reselected

// in the grid once the new book is added.
var selectedBookIndex:uint = myDataGrid.selectedIndex;

// Does the user want to add the new
// book relative to the selected book in the
// data grid or relative to the list itself?
if (addRelativeTo.selectedIndex == SELECTED_ITEM)

{
// Add the new item relative to the selected item.

var selectedBook:XML = myBooks.book[selectedBookIndex];

// Does the user want to add it before or after

// the selected item?
if (addPosition.selectedIndex == BEFORE)
{
// Add new item before selected item
myBooks = myBooks.insertChildBefore(selectedBook, newBook);
}

else
{
// Add new item after selected item
myBooks = myBooks.insertChildAfter(selectedBook, newBook);
}

}
else
{
// Add the new item relative to the whole list of books.
if (addPosition.selectedIndex == BEFORE)

{
// Add new item at the start of the list.
myBooks = myBooks.prependChild(newBook);
}
else

{
// Add new item at the end of the list.
myBooks = myBooks.appendChild(newBook);
}
}

// Select the previously selected item in the grid
// so the user doesn't lose their position. (If a new book was
// added before the currently selected item, that item's
// new index will be one greater, so select that.)
var newSelectedIndex:uint = (addPosition.selectedIndex == BEFORE) ? selectedBookIndex + 1: selectedBookIndex;
myDataGrid.selectedIndex = newSelectedIndex;

}

// Delete selected book

private function deleteBookHandler():void
{
// Save the currently selected index.
var selectedBookIndex:int = myDataGrid.selectedIndex;

// Delete the currently selected book.

delete (myBooks.book[selectedBookIndex]);

// Reselect the next logical item in the data grid.
newSelectedIndex = (selectedBookIndex==0) ? 0 : selectedBookIndex - 1;

// Change the selected index of the data grid

// at a later frame. See note on changeDataGridIndex()
// method for more details on this workaround.
callLater ( changeDataGridIndex );
}

// This is a workaround for a known issue with
// List-based components where deleting an item
// from the control's dataProvider leaves the

// selectedIndex at an incorrect value. The workaround
// is to reassign the data provider at least a
// frame later and to change the index there.
private function changeDataGridIndex ():void
{

// Reassign the data grid's data provider.
myDataGrid.dataProvider = myBooks.book;

// Set the selected index.
myDataGrid.selectedIndex = newSelectedIndex;

// Validate the form to make sure that there
// is actually a selection (that the grid is
// not empty).

validateForm();
}

// Perform simple form validation.
private function validateForm():void

{
// Is the form valid?
formIsValid =
isbnInput.text != ""
&& titleInput.text != ""

&& authorInput.text != ""
&& amazonUrlInput.text != "";

// Does a selection exist in the data grid?
selectionExists = myDataGrid.selectedIndex != -1;
}

]]>

</mx:Script>

<!-- User interface -->
<mx:Panel
title="Assigning XML data"
paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10"
>

<!-- List of books -->
<mx:DataGrid
id="myDataGrid"
dataProvider="{myBooks.book}"
change="validateForm();"
>

<mx:columns>
<mx:DataGridColumn dataField="@ISBN" headerText="ISBN" width="85"/>
<mx:DataGridColumn dataField="title" headerText="Title"/>

<mx:DataGridColumn dataField="author" headerText="Author"/>
<mx:DataGridColumn dataField="amazonUrl" headerText="Web site">

<mx:itemRenderer>
<mx:Component>
<mx:LinkButton
label="Visit"
click="navigateToURL(new URLRequest(data.amazonUrl), 'blank');"
/>
</mx:Component>

</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>

<!-- New book form. Prepopulated with a book for easier testing. -->

<mx:Form width="100%" autoLayout="false">
<mx:FormHeading label="New book details"/>

<mx:FormItem label="ISBN:" width="
100%">
<mx:TextInput
id="isbnInput"
width="100%"
text="1590596196"
change="validateForm();"
/>

</mx:FormItem>
<mx:FormItem label="Title:" width="100%">
<mx:TextInput
id="titleInput"
width="100%"
text="Object Oriented Actionscript for Flash 8"
change="validateForm();"
/>

</mx:FormItem>
<mx:FormItem label="Author:" width="100%">
<mx:TextInput
id="authorInput"
width="100%"
text="Peter Elst"
change="validateForm();"
/>

</mx:FormItem>
<mx:FormItem label="Amazon Url" width="100%">
<mx:TextInput
id="amazonUrlInput"
width="100%"
text="http://tinyurl.com/qxon2"
change="validateForm();"
/>

</mx:FormItem>
</mx:Form>

<mx:TextArea id="deb" width="100%"/>

<mx:ControlBar>

<mx:Button
label="Add book"
click="addBookHandler();"
enabled="{formIsValid}"
/>
<mx:ComboBox id="addPosition" enabled="{formIsValid}">

<mx:String>before</mx:String>
<mx:String>after</mx:String>
</mx:ComboBox>
<mx:ComboBox
id="addRelativeTo"
enabled="{formIsValid}"
>

<mx:String>selected item.</mx:String>
<mx:String>the list.</mx:String>
</mx:ComboBox>
<mx:VRule height="15"/>

<mx:Button
label="Delete book"
click="deleteBookHandler();"
enabled="{selectionExists}"
/>
</mx:ControlBar>

</mx:Panel>
</mx:Application>

查询XML数据


在E4X中,查询XML数据有几种方式。下边的例子展示了一下几种方式:

  1. 使用逻辑操作搜索数字范围(例如,所有大于300页的图书)
  2. 在元素或属性上查询字符串(例如,标题包含ldiots的图书)
  3. 从重复的节点请求元素(例如,从books中title元素)


当你拥有了查询结果,你可以使用for..in和 for each..in循环来遍历结果。

例子


<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
viewSourceURL="src/XMLQuery/index.html"
width="450" height="290"
initialize="initializeHandler();"
>

<mx:Script>
<![CDATA[
// Model: XML structure describing
// some of the books in my collection.
[Bindable]

private var myBooks:XML =
<books>
<book ISBN="1590595181">

<title>Foundation ActionScript Animation: Making Things Move</title>
<author>Keith Peters</author>
<amazonUrl>http://tinyurl.com/npuxt</amazonUrl>

<pageCount>470</pageCount>
</book>
<book ISBN="1582346194">
<title>Send in the Idiots: Stories from the Other Side of Autism</title>

<author>Kamran Nazeer</author>
<amazonUrl>http://tinyurl.com/lo5ts</amazonUrl>
<pageCount>500</pageCount>

</book>
<book ISBN="1590592212">
<title>Flash 3D Cheats Most Wanted</title>
<author>Aral Balkan et. al.</author>

<amazonUrl>http://tinyurl.com/gsd7b</amazonUrl>
<pageCount>256</pageCount>
</book>

</books>

private function initializeHandler():void
{

// Line length to truncate strings at when
// displaying them
var lineLength:uint = 50;

//
// Find books with more than 300 pages.
//

var resultA:XMLList;
resultA = myBooks.book.(pageCount > 300);

// Display the found books using a for each..in
// loop.

var tempString:String = "<ul>";
for each (var book:XML in resultA)

{
tempString += "<li>" + truncate(book.title, lineLength) + "</li>";
}

tempString += "</ul>";
aText.htmlText = tempString;

//
// Find book with "Idiots" in the title.
//
var resultB:XMLList;
resultB = myBooks.book.(title.toString().search("Idiots")>-1);

// Display the title of the found book.

bText.htmlText = "<ul><li>" + truncate(resultB.title, lineLength) + "</li></ul>";

//

// Get the titles of all the books.
//
var resultC:XMLList;
resultC = myBooks.book..title;

// Display the titles using a for..in loop
tempString = "<ul>";
for (var bookTitle:String in resultC)

{
tempString += "<li>" + truncate(resultC[bookTitle], lineLength) + "</li>";
}

tempString += "</ul>";
cText.htmlText = tempString;
}

// Helper method: Truncate a string at a given character count. Tries
// to do this intelligently by truncating at a space if one exists in

// the string (so that words are not truncated in the middle).
private function truncate ( str:String, numChars:uint, symbol:String = "..." ):String
{

// Don't do anything if the string is shorter than the maximum value.
if (str.length <= numChars) return str;

// Search backward for a space in the string, starting with
// the character position that was requested.

var charPosition:uint = numChars-1;
while (str.charAt(charPosition) != " " && charPosition != 0)

{
charPosition--;
}
var truncateAt:uint = charPosition == 0 ? numChars : charPosition;

// If the space is right before a punctuation mark, crop the

// punctuation mark also (or else it looks weird).
var charBefore:String = str.charAt(truncateAt-1);
if (charBefore == ":" || charBefore == ";"
|| charBefore == "." || charBefore == ",")

{
truncateAt--;
}

// Truncate the string.
var newString:String = str.substr(0, truncateAt);
newString += symbol;

// Return the truncated string.

return newString;
}

]]>
</mx:Script>

<!-- User interface -->

<mx:Panel
title="XML lookup results" width="100%"
paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10">

<mx:Label text="Query A - Books found:" fontWeight="bold"/>
<mx:Text id="aText" width="100%"/>

<mx:Label text="Query B - Books found:" fontWeight="bold"/>
<mx:Text id="bText" width="100%"/>

<mx:Label text="Query C - Books found:" fontWeight="bold"/>
<mx:Text id="cText" width="100%"/>

</mx:Panel>
</mx:Application>

你可能感兴趣的:(Flex)