Background
要做一个表单,其中自然少不了ComboBox,数据源不是从后台动态获取的,竟然是一个Excel表格文件!这个数据量很大,而且还有可能会修改,所以只能采用外部加载的方式。写一个解析Excel数据的库自然是不现实的,所以决定把Excel转换成XML格式,然后再加载。
Excel转换成XML
一般直接将Excel是不能导出成XML的,因为“不包含任何XML映射”,所以首先需要建立一个XML映射,其实就是设计一个XML结构,然后将Excel数据映射到对应的节点上。这一步其实很简单,但是颇具技巧性。
“开发工具”选项卡
导出XML需要“开发工具”功能,一般Excel不会显示这个选项卡,需要打开“文件”-“选项”-“自定义功能区”对话框,勾选“开发工具”。
设计XML结构
XML结构根据自己要求设计,多个相同子节点表示可以重复。比如这个:
<?xml version="1.0" encoding="UTF-8"?> <root> <province name=""> <city name=""> <dealer name="" address=""/> </city> </province> <province name=""> <city name=""> <dealer name="" address=""/> </city> </province> </root>
导入XML文件
回到Excel里,新建一个空白Excel文档,点击“开发工具”里的“源”按钮,在右侧弹出的面板里点击“XML映射”,然后添加之前的XML文件。如果成功右侧面板里会显示XML的树形结构。
映射数据
这步更简单,把那个树状结构根节点拖到工作表上,工作表上会显示行以XML节点属性为名称的表头。把数据对应地粘贴到这个表里。
导出文件
点击“源”按钮右边的“导出”,就可以导出XML了。导出后检查下数据映射对不对,如果没问题就算完成了。
加载XML数据
加载直接用URLLoader就可以。
var url:String = xmlUrl; var vars:URLVariables = new URLVariables(); var request:URLRequest = new URLRequest(url); var loader:URLLoader = new URLLoader(); loader.addEventListener(Event.COMPLETE, dealerInfoLoadHandler); loader.addEventListener(IOErrorEvent.IO_ERROR, loadErrorHandler); loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, loadErrorHandler); loader.load(request);
级联ComboBox
由于ActionScript E4X 的处理能力很强,所以利用XML作为数据源是完全可行的。经过几个简单的处理步骤就可以作为数据源提供给ComboBox。代码如下:
/** * 加载XML数据 * @param event * */ public function dealerInfoLoadHandler(event:Event):void { var loader:URLLoader = event.target as URLLoader; var xml:XML = new XML(loader.data); if(xml) { dealerXML = xml; var arrProv:Array = []; var seen:Object={}; var prov:XMLList = xml.province.@name.(!seen[valueOf()]&&(seen[valueOf()]=true)); prov. ( arrProv.push(toString()) ); this.provinces = arrProv; } cbxProv.dataProvider = new DataProvider(this.provinces); } /** * 省份ComboBox变化处理函数 * @param event * */ private function cbxProvChangeHandler(event:Event):void { cbxCity.dataProvider.removeAll(); //清空City DP var seen:Object={}; var provStr:String = cbxProv.selectedItem.data; var prov:XMLList = this.dealerXML.province.(@name==provStr); //根据省份名称从XML检索所有符合条件的城市子节点 var city:XMLList = prov.city.@name.(!seen[valueOf()]&&(seen[valueOf()]=true)); //过滤重复的城市节点 var arrCity:Array = []; city. ( arrCity.push(toString()) //把City数据灌到Array里 ); cbxCity.dataProvider = new DataProvider(arrCity); cbxCity.selectedIndex = 0; this.cbxCityChangeHandler(event); //联动一次cbxCity } /** * 城市ComboBox变化处理函数 * @param event * */ private function cbxCityChangeHandler(event:Event):void { cbxDealer.dataProvider.removeAll(); var cityStr:String = cbxCity.selectedItem.data; var city:XMLList = this.dealerXML..city.(@name==cityStr); var dealer:XMLList = city.dealer.@name; //末节点经销商数据不会重复,不需要过滤重复的 var arrDealer:Array = []; dealer. ( arrDealer.push(toString()) ); cbxDealer.dataProvider = new DataProvider(arrDealer); cbxDealer.selectedIndex = 0; }
示例
demo如下:
总结
单纯验证了XML作为级联ComboBox数据源的可行性。如果考虑重用性和稳定性,还有一些工作要做的。不过作为临时想出来的解决方案,也完全满足要求了,还挺有趣味性的。