我正在尝试将(几个)复杂的数据结构从python序列化成一个非常显式的XML字符串。
在C#中,这就像创建数据结构一样简单,用XmlElement或XmlAttribute之类的属性标记字段,并在本质上调用“序列化”。
但是,我在python中找不到类似的功能。我可以看到大量手动解析结构的示例,但这并不适合我的需要。
是否有任何模拟这个C#功能;
public enum eType {
[XmlEnum("multi")]
Multiple,
[XmlEnum("mutex1")]
Single,
[XmlEnum("product")]
Product,
[XmlEnum("alias")]
Alias
}
[Serializable]
[XmlRoot("root")]
public class RootClass{
public RootClass() {
Metadata = new Metadata ();
FeatureDictionary = new FeatureDictionary ();
}
[XmlElement("metadata")]
public Metadata Metadata { get; set; }
[XmlElement("feature-dictionary")]
public FeatureDictionary FeatureDictionary { get; set; }
}
[Serializable]
public class Metadata {
public Metadata() {
Meta = new List<Meta> ();
}
[XmlAttribute("status")]
public string Status { get; set; }
[XmlAttribute("url")]
public string URL { get; set; }
[XmlAttribute("view")]
public string View { get; set; }
[XmlElement("meta")]
public List<Meta> Meta { get; set; }
}
在蟒蛇里?
请记住,上面的片段大约是定义C#中XML的代码的1/20左右。
发布于 2013-08-16 17:36:44
一种合理的方法是使用python描述符在知道如何序列化和反序列化自身的对象上创建属性。描述符是python用于创建@property装饰器的机制:包含getter和setter方法,并且可以具有本地状态,因此它们在数据和xml之间提供了一个良好的暂存地。再加上一个类或修饰器,该类或修饰器可以自动对附加到对象的描述符进行批量序列化/反序列化,您就拥有了C# XML序列化系统的核心。
一般来说,您希望代码看起来像这样(使用臭名昭著的XML ISBN示例:
@xmlobject("Book")
class Book( object ):
author = XElement( 'AuthorsText' )
title = XElement( 'Title' )
bookId = XAttrib( 'book_id' )
isbn = IntAttrib( 'isbn' )
publisher = XInstance( 'PublisherText', Publisher )
这里的辅助语法是为实例中的所有字段(作者、标题等)创建类级描述符。与其他python代码相比,每个描述符看起来都是一个常规字段,因此您可以执行以下操作:
book.author = 'Joyce, James'
诸若此类。在内部,每个描述符存储和xml节点或属性,当被调用序列化时,它将返回适当的XML:
from xml.etree.cElementTree import ElementTree, Element
class XElement( object ):
'''
Simple XML serializable field
'''
def __init__( self, path):
self.path = path
self._xml = Element(path) # using an ElementTree or lxml element as internal storage
def get_xml( self, inst ):
return inst._xml
def _get_element( self ):
return self.path
def _get_attribute( self ):
return None
# the getter and setter push values into the underlying xml and return them from there
def __get__( self, instance, owner=None ):
myxml = self.get_xml( instance )
underlying = myxml.find( self.path )
return underlying.text
def __set__( self, instance, value, owner=None ):
myxml= self._get_xml( instance )
underlying = myxml.find( self.path )
underlying.text = value
对应的XAttrib类执行相同的操作,除了在属性中而不是在元素中。
class XAttrib( XElement):
'''
Wraps a property in an attribute on the containing xml tag specified by 'path'
'''
def __get__( self, instance, owner=None ):
return self._get_xml( instance ).attrib[self.path]
# again, using ElementTree under the hood
def __set__( self, instance, value, owner=None ):
myxml = self._get_xml( instance )
has_element = myxml.get( self.path, 'NOT_FOUND' )
if has_element == 'NOT_FOUND':
raise Exception, "instance has no element path"
myxml.set( self.path, value )
def _get_element( self ):
return None #so outside code knows we are an attrib
def _get_attribute( self ):
return self.path
为了将它们连接在一起,拥有类需要在初始化时设置描述符,以便每个实例级描述符都指向拥有实例的XML元素中的一个XML节点。这样,实例道具的更改就会自动反映在所有者的XML中。
def create_defaults( target_cls):
# where target class is the serializable class, eg 'Book'
# here _et_xml() would return the class level Element, just
# as in the XElement and XAttribute. Good use for a decorator!
myxml = target_cls.get_xml()
default_attribs = [item for item in target_cls.__class__.__dict__.values()
if issubclass( item.__class__, XElement) ]
#default attribs will be all the descriptors in the target class
for item in default_attribs:
element_name = item._get_element()
#update the xml for the owning class with
# all the XElements
if element_name:
new_element = Element( element_name )
new_element.text = str( item.DEFAULT_VAL )
myxml.append( new_element )
# then update the owning XML with the attributes
for item in default_attribs:
attribpath = item._get_attribute()
if attrib:
myxml.set( attribpath, str( item.DEFAULT_VAL ) )
很抱歉,如果这段代码不能正常运行的话--我从一个工作示例中删除了它,但我可能引入了but,同时试图使其可读性并删除特定于我的应用程序的细节。
https://stackoverflow.com/questions/18277053
复制相似问题