我有一个包含对象层次结构的xml片段:
doc = """
<RootObj val1="ValueOne" stat1="Stat1" stat2="Stat2">
<internalarray type="array">
<InternalObject val1="12" val2="12" />
<InternalObject val1="13" val2="13" />
<InternalObject val1="14" val2="14" />
<InternalObject val1="15" val2="15" />
</internalarray>
</RootObj>"""
我使用ElementTree xml表示来解析xml:
from xml.etree import ElementTree as ET
...
xml_doc = ET.XML(doc)
我递归地遍历xml_doc元素,边使用"namedtuple"边构建类定义:
from collections import namedtuple
...
def buildClass(name, node):
symbol_table = {}
args = []
varnames = ""
for subnode in node:
args.append(buildClass(subnode.tag, subnode))
if (subnode.tag not in symbol_table):
symbol_table[subnode.tag] = 1
varnames += subnode.tag + " "
print 'Building class for:', name
for (key, value) in node.items():
args.append(value)
varnames += key + " "
varnames = varnames.strip()
if (not name[0] == name[0].upper()):
#this is an array, do not create a class, just return an array
#pop the last element, "array"
args.pop()
return args
globals()[name] = namedtuple(name, varnames)
obj = globals()[name](*args)
return obj
这样调用:
rootObj = build_class(xml_doc.tag, xml_doc)
使用dump,一个在StackOverflow中可以找到的函数:
def dump(obj):
'''return a printable representation of an object for debugging'''
newobj=obj
if '__dict__' in dir(obj):
newobj=obj.__dict__
if ' object at ' in str(obj) and not newobj.has_key('__type__'):
newobj['__type__']=str(obj)
for attr in newobj:
newobj[attr]=dump(newobj[attr])
return newobj
您可以调用:
print dump(rootObj)
和看到(我手动格式化空格):
RootObj(
internalarray=[
InternalObject(val2='12', val1='12'),
InternalObject(val2='13', val1='13'),
InternalObject(val2='14', val1='14'),
InternalObject(val2='15', val1='15')
],
val1='ValueOne', stat2='Stat2', stat1='Stat1')
所以我们知道代码实际上在生成一个类。现在,如果您使用快速DynamicClassMapper和代码生成器:
import amfast
from amfast import class_def
from amfast.class_def.code_generator import CodeGenerator
...
class_mapper = class_def.ClassDefMapper()
mapped_class = class_def.DynamicClassDef(RootObj, 'RootObj', ())
#OR
#mapped_class = class_def.DynamicClassDef(globals()[xml_doc.tag],xml_doc.tag, ())
#I tried both and received the same output
coder = CodeGenerator()
coder.generateFilesFromMapper(class_mapper, use_accessors=False,
packaged=True, constructor=True, bindable=True, extends='Object')
得到一个文件RootObj.as:
package
{
[Bindable]
[RemoteClass(alias='RootObj')]
public dynamic class RootObj extends Object
{
public function RootObj():void
{
super();
}
}
}
显然缺少所有的属性之类的东西。是否有一种方法利用这种编码方法来输出ActionScript文件,实际上包含正确的类定义?
好的,显然,这是没有人知道如何做的事情,所以我想出了一个解决方案。
我修改buildClass()函数如下:
def buildClass(name, node):
global _classes
symbol_table = {}
args = []
varnames = ""
varnameswithtypes = ""
for subnode in node:
args.append(buildClass(subnode.tag, subnode))
if (subnode.tag not in symbol_table):
symbol_table[subnode.tag] = 1
varnames += subnode.tag + " "
if (not subnode.tag[0] == subnode.tag[0].upper()):
varnameswithtypes += subnode.tag + ":array "
else:
varnameswithtypes += subnode.tag + ":object "
print 'Building class for:', name
for (key, value) in node.items():
args.append(value)
varnames += key + " "
if (key == "variable_name"):
varnameswithtypes+= key + ":" + value + " "
elif (is_numeric(value)):
varnameswithtypes+= key + ":numeric" + " "
else:
varnameswithtypes+= key + ":text" + " "
varnames = varnames.strip()
varnameswithtypes = varnameswithtypes.strip()
if (_classes.has_key(name)):
if (len(_classes[name]) < len(varnameswithtypes)):
_classes[name] = varnameswithtypes
else:
_classes[name] = varnameswithtypes
if (not name[0] == name[0].upper()):
#this is an array, do not create a class, just return an array
return args
#print varnames, args
globals()[name] = namedtuple(name, varnames)
obj = globals()[name](*args)
#print dump(obj)
return obj
然后补充说:
_classdefs = {}
def getClassDef(name):
global _classdefs, _classes
_classdefs[name] = "class " + name + "(object):n def __init__(self):n"
classvars = _classes[name].split(" ")
for x in classvars:
vals = x.split(":")
if (vals[1] == "array"):
c = _classes[vals[0]].split(":")[0]
if (not _classdefs.has_key(c)):
getClassDef(c)
_classdefs[name] += " self." + vals[0] + " = []n"
elif (vals[1] == "text"):
_classdefs[name] += " self." + vals[0] + " = ""n"
elif (vals[1] == "numeric"):
_classdefs[name] += " self." + vals[0] + " = 0n"
elif (vals[1] == "object"):
if (not _classdefs.has_key(vals[0])):
getClassDef(vals[0])
subclassvars = _classes[vals[0]].split(" ")
for z in subclassvars:
if (z.split(":")[0] == "variable_name"):
_classdefs[name] += " self." + z.split(":")[1] + " = " + vals[0] + "()n"
可以这样调用:
getClassDef("RootObj")
for x in _classdefs.keys():
print _classdefs[x]
使用xml: <RootObj val1="ValueOne" stat1="Stat1" stat2="Stat2">
<internalarray>
<InternalObject val1="12" val2="12" />
<InternalObject val1="13" val2="13" />
<InternalObject val1="14" val2="14" />
<InternalObject val1="15" val2="15" />
</internalarray>
<InternalObject2 val1="12" val2="13" variable_name="intObj2" />
</RootObj>
代码将输出:
class RootObj(object):
def __init__(self):
self.internalarray = []
self.intObj2 = InternalObject2()
self.val1 = ""
self.stat2 = ""
self.stat1 = ""
class InternalObject2(object):
def __init__(self):
self.val2 = 0
self.val1 = 0
class InternalObject(object):
def __init__(self):
self.val2 = 0
self.val1 = 0
你可以把它保存到一个.py文件中,然后像平常一样导入到amfast ActionScript代码生成中。去我。