我正在进行的一个项目将从网络服务器中提取 XML 并从中构建数据存储。数据将具有某些核心字段,但需要可扩展......例如,我有一个,以后可能想要添加额外的字段。
在 Flex 应用程序中,我不希望中央数据存储处理 XML 对象或只是将属性放入对象中。我想要有强类型,例如 Person 类,它是从 XML 创建/填充的。
如何以灵活的方式做到这一点?如果属性名称匹配,Flex 是否能够从 XML 自动构建 Person,或者我是否需要为 、 等编写转换功能?
我正在进行的一个项目将从网络服务器中提取 XML 并从中构建数据存储。数据将具有某些核心字段,但需要可扩展......例如,我有一个,以后可能想要添加额外的字段。
在 Flex 应用程序中,我不希望中央数据存储处理 XML 对象或只是将属性放入对象中。我想要有强类型,例如 Person 类,它是从 XML 创建/填充的。
如何以灵活的方式做到这一点?如果属性名称匹配,Flex 是否能够从 XML 自动构建 Person,或者我是否需要为 、 等编写转换功能?
我不认为这可以自动完成。我通常创建一个类来镜像我拥有的 XML 结构,然后创建一个静态类方法来创建给定 XML 节点的对象的实例。例如:
package {
public class Foo{
public function Foo(barparam1:String, barparam2:uint, barparam3:String, barparam4:Number){
this._bar1 = barparam1;
this._bar2 = barparam2;
this._bar3 = barparam3;
this._bar4 = barparam4;
}
protected var _bar1:String;
protected var _bar2:uint;
protected var _bar3:String;
protected var _bar4:Number;
public function get bar1():String{ return this._bar1; }
public function get bar2():uint { return this._bar2; }
public function get bar3():String { return this._bar3; }
public function get bar4():Number { return this._bar4; }
public function toString():String{
return "[Foo bar1:\"" + this.bar1 + "\", bar3:\"" + this.bar3 + "\", bar2:" + this.bar2 + ", bar4:" + this.bar4 + "]";
}
public static function createFromXml(xmlParam:XML):Foo{
/* XML Format:
<foo bar1="bar1value" bar2="5">
<bar3>bar3 data</bar3>
<bar4>10</bar4>
</foo>
*/
return new Foo(xmlParam.@bar1, xmlParam.@bar2, xmlParam.bar3[0], xmlParam.bar4[0]);
}
}
}
如果您不依赖于 XML(例如,您有一个应用服务器而不是文件服务器),您可以考虑使用 AMF(动作消息格式)来传输数据。有一些项目将 AMF 暴露给服务器,包括 Adobe 自己的Blaze DS和社区开源变体,如OpenAMF、AMFPHP、PyAMF等。这将使您能够将自定义对象从服务器传输到 Flex,自动解析数据类型和类型安全。看看这个数据传输选项的比较,以了解相对优点。
话虽如此,XML 对于应用程序配置数据之类的东西非常有用,并且在这些情况下,您没有运行应用程序服务器。我同意另一张海报,我将立即手动将 xml 解析为适当的结构。我通常将这些与修复后的 VO(用于值对象)一起存储,并将成员保留为公开。我经常分层地做这件事。
package model.vo
{
public class ConfigVO
{
public var foo:String;
public var bar:int;
public var baz:Boolean;
public var sections:Array;
public function ConfigVO(xml:XML)
{
parseXML(xml);
}
private function parseXML(xml:XML):void
{
foo = xml.foo;
bar = xml.bar;
baz = (xml.baz == "true");
sections = [];
for each(var sectionXML:XML in xml.section)
{
sections.push(new SectionVO(sectionXML));
}
}
}
}
package model.vo
{
public class SectionVO
{
public var title:String;
public function SectionVO(xml:XML)
{
parseXML(xml);
}
private function parseXML(xml:XML):void
{
title = xml.@title;
}
}
}
过去我见过将 XML 元素名称绑定到类定义的系统。这些通常对类使用某种自省来确定要从 xml 中读取哪些属性,或者它们将具有一些静态类属性,这些属性将实例属性映射到 xml 标记或属性。根据我的经验,它们带来的麻烦比它们的价值要大得多。添加一个新的公共属性和从属性或子标签读取数据的一行需要全部 2 秒。我的建议是避免使用这种复杂的方案,但为了完整起见,我将举一个简单的例子。
package model
{
public class XMLReader
{
// maps <tagname> to a class
private static var elementClassMap:Object =
{
"section": SectionVO,
"person": PersonVO
};
public var parsedElements:Array;
public function XMLReader(xml:XML)
{
parsedElements = [];
parseXML(xml);
}
private function parseXML(xml:XML):void
{
var voClass:Class;
for each(var element:XML in xml.children())
{
voClass = elementClassMap[element.name().localname];
if(voClass)
{
parsedElements.push(new voClass(element));
}
}
}
}
}
使用 flex simplexmldecoder 类@flexExamples将 xml 转换为对象
不久前,我开始研究一个 Flex 库,该库将帮助序列化和反序列化动作脚本对象与 XML 之间的关系。您所要做的就是创建模型对象,在字段上添加一些注释,让序列化程序知道您希望如何序列化字段(元素、属性、名称等)并调用(反)序列化过程。
我认为它适合您的需求。
如果您愿意,可以在http://code.google.com/p/flexxb/上查看。
希望这将被证明是有帮助的。
创建强数据类型有几个优点,代码完成和编译时语法检查是最重要的。可以完成手动映射,但应该生成(因此毕竟不再是真正的手动映射)以避免迟早不同步。
基于自省的通用转换库是通用的、易于使用的,并且应该足以满足大多数用例。
JAXB 是 Java 的标准。ASXB为 Actionscript 世界提供了这个想法的轻量级实现。它使用带有注释的显式 AS 对象来(取消)编组对象和 XML。
如果您被迫在线上使用 XML,我建议您仔细看看 ASXB。如果您可以自由选择格式并拥有支持的服务器端,那么 Adobe 自己的 AMF 格式应该是您的选择,因为它在语言中直接受支持,并且在传输过程中的开销要低得多。
在我们当前的项目中,我们编写了小型代码生成器,它采用 Java 端的外部 API(源自省,也复制 Javadoc)并在我们的构建过程中从中生成 AS 类。因此,当外部需求迫使我们这样做时,从 AMF 切换到 XML 很容易。
PS:记得将编译器参数添加到您的 flex 配置文件中以保留注释
AsBeanGen可以做到这一点。它为 DTD 驱动的 XML 文件生成值对象。