跳转到主要内容

将Zope 3对象描述转换为XML,反之亦然

项目描述

Schema To XML

简介

此包可以将由Zope 3模式描述的对象转换为简单的XML结构。它还可以将此XML转换回对象。导出和导入过程完全由模式驱动;任何在模式中未描述的属性都不会被此系统看到。

此系统可用于创建Zope 3应用程序的导出和导入系统。它也可以用于为其他目的提供对象的XML表示,例如XSLT转换,或者只是为了索引目的获得全文表示。

该包基于lxml进行XML序列化。

序列化

首先定义一个简单的Zope 3模式

>>> from zope import interface, schema
>>> class IName(interface.Interface):
...     first_name = schema.TextLine(title=u'First name')
...     last_name = schema.TextLine(title=u'Last name')

现在创建一个实现此模式的类

>>> from zope.interface import implements
>>> class Name(object):
...     implements(IName)
...     def __init__(self, first_name, last_name):
...         self.first_name = first_name
...         self.last_name = last_name

创建类的实例

>>> name = Name('Karel', 'Titulaer')

现在将其序列化为XML

>>> from z3c.schema2xml import serialize
>>> print serialize('container', IName, name)
<container>
  <first_name>Karel</first_name>
  <last_name>Titulaer</last_name>
</container>

这也可以用于其他类型的字段

>>> from zope import interface, schema
>>> class IAddress(interface.Interface):
...     street_name = schema.TextLine(title=u'Street name')
...     number = schema.Int(title=u'House number')
>>> class Address(object):
...     implements(IAddress)
...     def __init__(self, street_name, number):
...         self.street_name = street_name
...         self.number = number
>>> address = Address('Hofplein', 42)
>>> print serialize('container', IAddress, address)
<container>
  <street_name>Hofplein</street_name>
  <number>42</number>
</container>

如果字段未填写,序列化将生成一个空元素

>>> address2 = Address(None, None)
>>> print serialize('container', IAddress, address2)
<container>
  <street_name/>
  <number/>
</container>

如果模式定义了一个具有其自己模式的对象字段,序列化也可以处理这种情况

>>> class IPerson(interface.Interface):
...     name = schema.Object(title=u"Name", schema=IName)
...     address = schema.Object(title=u"Address", schema=IAddress)

>>> class Person(object):
...     implements(IPerson)
...     def __init__(self, name, address):
...         self.name = name
...         self.address = address

>>> person = Person(name, address)
>>> print serialize('person', IPerson, person)
<person>
  <name>
    <first_name>Karel</first_name>
    <last_name>Titulaer</last_name>
  </name>
  <address>
    <street_name>Hofplein</street_name>
    <number>42</number>
  </address>
</person>

模式还可以定义一个具有其自己模式的元素列表字段。让我们创建一个对象并将其序列化

>>> class ICommission(interface.Interface):
...     members = schema.List(
...         title=u"Commission",
...         value_type=schema.Object(__name__='person',
...         schema=IPerson))

请注意,我们必须明确指定用于value_type的此字段的__name__,否则我们无法将其名称序列化为XML。

>>> class Commission(object):
...     implements(ICommission)
...     def __init__(self, members):
...         self.members = members
>>> commission = Commission(
...     [person, Person(Name('Chriet', 'Titulaer'), Address('Ruimteweg', 3))])
>>> print serialize('commission', ICommission, commission)
<commission>
  <members>
    <person>
      <name>
        <first_name>Karel</first_name>
        <last_name>Titulaer</last_name>
      </name>
      <address>
        <street_name>Hofplein</street_name>
        <number>42</number>
      </address>
    </person>
    <person>
      <name>
        <first_name>Chriet</first_name>
        <last_name>Titulaer</last_name>
      </name>
      <address>
        <street_name>Ruimteweg</street_name>
        <number>3</number>
      </address>
    </person>
  </members>
</commission>

每次尝试序列化没有序列化器的字段类型时,都会得到一个适配器查找失败

>>> class IWithNonSerializableField(interface.Interface):
...     field = schema.Field(title=u"Commission")
>>> class NotSerializable(object):
...     implements(IWithNonSerializableField)
...     def __init__(self, value):
...         self.field = value
>>> not_serializable = NotSerializable(None)
>>> serialize('noway', IWithNonSerializableField, not_serializable)
Traceback (most recent call last):
 ...
TypeError: ('Could not adapt', <zope.schema._bootstrapfields.Field object at ...>, <InterfaceClass z3c.schema2xml._schema2xml.IXMLGenerator>)

反序列化

现在我们想要根据模式将XML反序列化为提供此模式的对象。

>>> from z3c.schema2xml import deserialize
>>> xml = '''
...  <container>
...    <first_name>Karel</first_name>
...    <last_name>Titulaer</last_name>
...  </container>
...  '''
>>> name = Name('', '')
>>> deserialize(xml, IName, name)
>>> name.first_name
u'Karel'
>>> name.last_name
u'Titulaer'

XML中字段的顺序无关紧要

>>> xml = '''
...  <container>
...    <last_name>Titulaer</last_name>
...    <first_name>Karel</first_name>
...  </container>
...  '''
>>> name = Name('', '')
>>> deserialize(xml, IName, name)
>>> name.first_name
u'Karel'
>>> name.last_name
u'Titulaer'

反序列化后,对象还提供了模式接口

>>> IName.providedBy(name)
True

这也可以用于其他类型的字段

>>> xml = '''
...  <container>
...    <street_name>Hofplein</street_name>
...    <number>42</number>
...  </container>
...  '''
>>> address = Address('', 0)
>>> deserialize(xml, IAddress, address)
>>> address.street_name
u'Hofplein'
>>> address.number
42

如果模式定义了一个具有其自己模式的对象字段,序列化也可以处理这种情况

>>> xml = '''
...  <person>
...    <name>
...      <first_name>Karel</first_name>
...      <last_name>Titulaer</last_name>
...    </name>
...    <address>
...      <street_name>Hofplein</street_name>
...      <number>42</number>
...    </address>
...  </person>
...  '''
>>> person = Person(Name('', ''), Address('', 0))
>>> deserialize(xml, IPerson, person)
>>> person.name.first_name
u'Karel'
>>> person.name.last_name
u'Titulaer'
>>> person.address.street_name
u'Hofplein'
>>> person.address.number
42
>>> IPerson.providedBy(person)
True
>>> IName.providedBy(person.name)
True
>>> IAddress.providedBy(person.address)
True

再次,XML中字段的顺序不应该重要

>>> xml = '''
...  <person>
...    <address>
...      <number>42</number>
...      <street_name>Hofplein</street_name>
...    </address>
...    <name>
...      <last_name>Titulaer</last_name>
...      <first_name>Karel</first_name>
...    </name>
...  </person>
...  '''
>>> person = Person(Name('', ''), Address('', 0))
>>> deserialize(xml, IPerson, person)
>>> person.name.first_name
u'Karel'
>>> person.name.last_name
u'Titulaer'
>>> person.address.street_name
u'Hofplein'
>>> person.address.number
42
>>> IPerson.providedBy(person)
True
>>> IName.providedBy(person.name)
True
>>> IAddress.providedBy(person.address)
True

>>> xml = '''
... <commission>
...  <members>
...    <person>
...      <name>
...        <first_name>Karel</first_name>
...        <last_name>Titulaer</last_name>
...      </name>
...      <address>
...        <street_name>Hofplein</street_name>
...        <number>42</number>
...      </address>
...    </person>
...    <person>
...      <name>
...        <first_name>Chriet</first_name>
...        <last_name>Titulaer</last_name>
...     </name>
...      <address>
...        <street_name>Ruimteweg</street_name>
...        <number>3</number>
...      </address>
...    </person>
...  </members>
... </commission>
... '''

>>> commission = Commission([])
>>> deserialize(xml, ICommission, commission)
>>> len(commission.members)
2
>>> member = commission.members[0]
>>> member.name.first_name
u'Karel'
>>> member.address.street_name
u'Hofplein'
>>> member = commission.members[1]
>>> member.name.first_name
u'Chriet'
>>> member.address.street_name
u'Ruimteweg'

每当XML元素为空时,生成的值应为None

>>> from z3c.schema2xml import deserialize
>>> xml = '''
...  <container>
...    <first_name></first_name>
...    <last_name/>
...  </container>
...  '''
>>> name = Name('', '')
>>> deserialize(xml, IName, name)
>>> name.first_name is None
True
>>> name.last_name is None
True

对于所有类型的字段,如字符串和整数...

>>> xml = '''
...  <container>
...    <street_name/>
...    <number/>
...  </container>
...  '''
>>> address = Address('', 0)
>>> deserialize(xml, IAddress, address)
>>> address.street_name is None
True
>>> address.number is None
True

…以及子对象的字段(但不包括子对象本身!)

>>> xml = '''
...  <person>
...    <name>
...      <first_name/>
...      <last_name/>
...    </name>
...    <address>
...      <street_name/>
...      <number/>
...    </address>
...  </person>
...  '''
>>> person = Person(Name('', ''), Address('', 0))
>>> deserialize(xml, IPerson, person)
>>> person.name.first_name is None
True
>>> person.name.last_name is None
True
>>> IPerson.providedBy(person)
True
>>> IName.providedBy(person.name)
True
>>> person.address is None
False
>>> person.address.street_name is None
True
>>> person.address.number is None
True
>>> IAddress.providedBy(person.address)
True

同样,当期望一个序列时,值应该是一个空序列

>>> xml = '''
... <commission>
...   <members/>
... </commission>
... '''
>>> commission = Commission([])
>>> deserialize(xml, ICommission, commission)
>>> len(commission.members)
0

TextLine、Int、Object 和 List 已经过测试。现在对具有序列化器的其他字段类型进行测试。

日期时间

日期时间对象

>>> from datetime import datetime
>>> class IWithDatetime(interface.Interface):
...     datetime = schema.Datetime(title=u'Date and time')
>>> class WithDatetime(object):
...     implements(IWithDatetime)
...     def __init__(self, datetime):
...         self.datetime = datetime
>>> with_datetime = WithDatetime(datetime(2006, 12, 31))
>>> xml = serialize('container', IWithDatetime, with_datetime)
>>> print xml
<container>
  <datetime>2006-12-31T00:00:00</datetime>
</container>
>>> new_datetime = WithDatetime(None)
>>> deserialize(xml, IWithDatetime, new_datetime)
>>> new_datetime.datetime.year
2006
>>> new_datetime.datetime.month
12
>>> new_datetime.datetime.day
31

让我们尝试不填写字段的情况

>>> with_datetime = WithDatetime(None)
>>> xml = serialize('container', IWithDatetime, with_datetime)
>>> print xml
<container>
  <datetime/>
</container>
>>> new_datetime= WithDatetime(None)
>>> deserialize(xml, IWithDatetime, new_datetime)
>>> new_datetime.datetime is None
True

选择

选择字段。目前,我们只处理具有文本值的选择字段

>>> from zc.sourcefactory.basic import BasicSourceFactory
>>> class ChoiceSource(BasicSourceFactory):
...     def getValues(self):
...         return [u'alpha', u'beta']
>>> class IWithChoice(interface.Interface):
...     choice = schema.Choice(title=u'Choice', required=False,
...                            source=ChoiceSource())
>>> class WithChoice(object):
...     implements(IWithChoice)
...     def __init__(self, choice):
...         self.choice = choice
>>> with_choice = WithChoice('alpha')
>>> xml = serialize('container', IWithChoice, with_choice)
>>> print xml
<container>
  <choice>alpha</choice>
</container>
>>> new_choice = WithChoice(None)
>>> deserialize(xml, IWithChoice, new_choice)
>>> new_choice.choice
'alpha'
>>> with_choice = WithChoice(None)
>>> xml = serialize('container', IWithChoice, with_choice)
>>> print xml
<container>
  <choice/>
</container>
>>> deserialize(xml, IWithChoice, new_choice)
>>> new_choice.choice is None
True

集合

集合字段与列表字段非常相似

>>> class IWithSet(interface.Interface):
...     set = schema.Set(title=u'Set', required=False,
...                      value_type=schema.Choice(__name__='choice',
...                                               source=ChoiceSource()))
>>> class WithSet(object):
...     implements(IWithSet)
...     def __init__(self, set):
...         self.set = set
>>> with_set = WithSet(set(['alpha']))
>>> xml = serialize('container', IWithSet, with_set)
>>> print xml
<container>
  <set>
    <choice>alpha</choice>
  </set>
</container>
>>> with_set = WithSet(set(['alpha', 'beta']))
>>> xml = serialize('container', IWithSet, with_set)
>>> print xml
<container>
  <set>
    <choice>alpha</choice>
    <choice>beta</choice>
  </set>
</container>
>>> new_set = WithSet(None)
>>> deserialize(xml, IWithSet, new_set)
>>> new_set.set
set(['alpha', 'beta'])

变更

1.0 (2008-12-05)

  • grokcore.component 的依赖性已更改,因此这也可以在 Zope 3 应用程序中直接使用。

  • 针对 lxml 2.0.9 运行测试。

0.10 (2008-03-10)

  • 在 svn.zope.org 的首次提交。

下载

项目详情


下载文件

下载适用于您的平台的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分发

z3c.schema2xml-1.0.tar.gz (12.5 kB 查看散列)

上传时间

由…支持