在一部分AS3項目
中XML是我們經常使用的一種儲存資料
的手段,我們經常用XML來儲存一些資料或者一些參數的設定。使用FLEX的朋友更是對MXML這個XML的加強定製版非常熟悉。那麼在編寫代碼
的時候我們就不得不經常寫一些解析XML內容的代碼。今天我要講的有個小技巧也是剛整理出來的一種命名空間來方便解析XML的方法。有朋友已經從LEX的MXML中領悟到這種使用方法的話請勿見笑。
一、複雜類型變數值的轉換
在XML中我們都知道在用AS3的XML類讀取進來後,其各種值基本都是以String
的形式存在的。所以在想存放一些比如數組或者在製作
UI的時候的一些複合屬性
時我們需要
對這些字串進行加工以便轉換成AS3的其他變數類型
。比如下面的一個XML:
<object>
<id>1000</id>
<name>test</name>
<childIdList>23,23,523,5,235,23,52,35,235,235,4646</childIdList>
</ object >
在內部我們要把XML轉換資料到myClass類中的具體屬性的話可能會寫以下形式的函數 :
首先是myClass類:
package{
public class myClass{
public var id:int;
public var name:String;
public var childIdList:Array = new Array;
public function myClass(){
}
}
}
第一種寫法:
public function buildObjectByXML(data:XML):void{
var myObject:myClass = new myClass;
myObject.id = data.id as int;
myObject.name = data.name as String;
myObject.childIdList = data.childIdList.split(“,”);
}
第二種寫法:
function buildObjectByXML(data:XML):void {
var myObject:myClass = new myClass;
var nodeList:XMLList = data.children();
for each (var node:XML in nodeList) {
var valueName:String = node.localName();
if(!myObject.hasOwnProperty(valueName)) continue;
if (valueName == "childIdList") {
myObject[valueName] = node.toString().split(",");
} else {
myObject[valueName] = node.toString();
}
}
}
其中第一種寫法就是人肉所有屬性然後具體區別對待如何轉換,第二種則是遍曆XML中的元素然後用if條件來篩選後再進行具體區別和轉換。兩者所有的轉換過程和演算法
都集中在buildObjectByXML函數中,其缺點就是
萬一需要設定的XML中屬性複雜變數繁多的話閱讀性就直線下降,比如我們在寫XML配置的UI組件
的時候就經常會碰到這樣的情況。碰到這樣的狀況如果後期變數比較固定少做修改還好,如果要頻繁修改的話我們就不得不經常面對一個非常長的而且複雜難讀的buildObjectByXML函數。
那麼如何使用命名空間來最佳化這一結構呢?首先,
XML本身也擁有命名空間
(詳細請閱讀AS3協助)。第二命名空間不同的情況下可以使用同名函數或者變數
。集合以上兩個特點我們可以把上面的XML以及myClass改造成如下形式:
首先是XML:
<object xmlns:xmlSet=”http://www.aslii.com/xmlSet”>
<id>1000</id>
<name>test</name>
<xmlSet:childIdList>23,23,523,5,235,23,52,35,235,235,4646</ xmlSet:childIdList>
</ object >
然後是myClass類:
package{
public class myClass{
public namespace xmlSet = http://www.aslii.com/xmlSet;
public var id:int;
public var name:String;
public var childIdList:Array = new Array;
public function myClass(){
}
xmlSet function set childIdList(dataString:String):void{
this.childIdList = dataString.split(“,”);
}
}
}
最後是我們的buildObjectByXML函數:
function buildObjectByXML(data:XML):void {
var myObject:myClass = new myClass;
var nodeList:XMLList = data.children();
for each (var node:XML in nodeList) {
var valueName:String = node.localName();
var ns:Namespace = node.namespace();
if(myObject.hasOwnProperty(valueName)) {
myObject.ns::[valueName] = node.toString();
}
}
}
從中我們可以看到,具體轉換類型的代碼被移到了具體的類中以一個固定的命名空間以及和屬性相同的名字存在。而且這麼寫如果後期有添加刪除屬性只需要在具體類中添加對應的方法和變數即可,
buildObjectByXML函數就無須再做任何改動
了。如果轉換的時候演算法有所改變我們也可以很輕鬆的很有針對性的去對象類中找到對應函數名的set函數。
二、用命名空間+XML來組建自己的組件設定檔
。
這部分寫UI的朋友應該會有興趣,其實內容也基本是仿造MXML的做法。細心的朋友可能早已發現FLEX的MXML的結構其實非常頻繁
的使用了XML的命名空間系統,但是其MXML只能用在編寫階段,最後被編譯成了SWF。在被編譯成SWF之後我們就無法再使用MXML了。其利用XML
命名空間來轉換成執行個體的過程被固化在FLEX編輯器中而不是SWF動態編譯,所以那部分轉碼我們無法看到他是咋寫的。
其實其原理和上面利用命名空間來指定特定命名空間的set函數一樣,我們只需要在解析XML的時候把命名空間指定的函數內演算法和建立元件關聯起來即可。
而具體寫法其實就是寫一套頂級的命名空間函數。
比如,我要寫一套lii組件,需要通過XML來配置介面。那麼可以如下簡單實現:
首先是XML:
<root xmlns:lii="http://www.aslii.com/liiUI">
<lii:Button id="xx" x="0" y="0" width="232" height="333"/>
</root>
然後是一個預設預設包的頂級類:
package{
public class LiiUIManager{
public static const core:LiiUIManager = new LiiUIManager();
public namespace lii = "http://www.aslii.com/liiUI";
public var uiList:Array = new Array;
public var length:int;
public function LiiUIManager(){
}
lii static function set Button(data:XML):void{
trace("[ new lii::Button ]");
core.uiList[length] = new myButton();
core.length += 1;
//以下用XML解析轉換屬性代碼並且進行詳細構造,這裡就不寫了。
}
public static function buildUI(data:XML):void{
var nodeList:XMLList = data.children();
for each (var node:XML in nodeList) {
var valueName:String = node.localName();
var ns:Namespace = node.namespace();
LiiUIManager.ns::[valueName] = node;
}
}
}
}
最後是執行解析:
LiiUIManager.buildUI(xml);
而且我們可以把它們寫成可以動態編譯的即時解析與構造而不像FLEX那樣必須經過編輯器編譯構造。這隻是個小小的例子,具體的大家可以盡情發揮自己的想像力與創造力。FLEX的MXML並不神秘就是如此簡單,我們也可以擁有。