使用属性的pythonxml序列化

2024-04-18 19:04:31 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图将python中的(几个)复杂数据结构序列化为一个非常显式的XML字符串。在

在C#中,这就像创建数据结构一样简单,用一些属性(如[xmleelement]或[xmltribute]标记字段)和调用“serialise”一样简单。在

但是,我在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; }

}

在python中?在

请记住,上面的代码片段大约占C#中定义XML的代码的1/20。在


Tags: 功能数据结构newgetstringxmlpublicmeta
1条回答
网友
1楼 · 发布于 2024-04-18 19:04:31

一种合理的方法是使用python descriptors在对象上创建属性,这些属性知道如何对自身进行序列化和反序列化。描述符是python用来创建@property decorators的机制:contain 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 )

这里的赋值语法是为实例中的所有字段(author、title等)创建类级别的描述符。对于其他python代码,每个描述符看起来都像一个常规字段,因此可以执行以下操作:

^{pr2}$

等等。在内部,每个描述符存储和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 ) )

很抱歉,如果这段代码没有立即运行-我把它从一个工作示例中剥离出来,但是我可能在试图使它可读并删除我的应用程序特定的细节时引入了错误。在

相关问题 更多 >