我有以下内容:
from spyne.service import ServiceBase
from spyne.util import xml
from spyne.model import complex, primitive
class ComplexModel(complex.ComplexModelBase):
__namespace__ = 'http://xml.candyshop.com/ns/candies/'
__metaclass__ = complex.ComplexModelMeta
class CandyModel(ComplexModel):
__type_name__ = 'candy'
flavor = complex.XmlAttribute(primitive.Unicode)
class BagModel(ComplexModel):
__type_name__ = 'bag'
candies = complex.Array(CandyModel)
class CandyShop(ServiceBase):
__tns__ = 'http://xml.candyshop.com/ns/shop/'
@rpc(_returns=primitive.AnyXml)
def get_my_bag(ctx):
bag = BagModel()
bag.candies = [CandyModel(flavor='choco')]
return xml.get_object_as_xml(
bag,
cls=BagModel,
root_tag_name='bag',
)
@classmethod
def dispatch(cls):
from django.views.decorators.csrf import csrf_exempt
from spyne.application import Application
from spyne.server.django import DjangoApplication
application = Application([cls],
tns=cls.__tns__,
in_protocol=Soap11(validator='lxml'),
out_protocol=Soap11(cleanup_namespaces=True)
)
return csrf_exempt(DjangoApplication(application))
shop_service = CandyShop.dispatch()
get_my_bag
的结果如下:
<tns:get_my_bagResult xmlns:tns="http://xml.candyshop.com/ns/shop/">
<ns0:bag xmlns:ns0="http://xml.candyshop.com/ns/candies/">
<ns0:candies>
<ns1:candy xmlns:ns1="None" flavor="choco"/>
</ns0:candies>
</ns0:bag>
</tns:get_my_bagResult>
但我想跟随:
<tns:get_my_bagResult xmlns:tns="http://xml.candyshop.com/ns/shop/">
<ns0:bag xmlns:ns0="http://xml.candyshop.com/ns/candies/">
<ns0:candies>
<ns0:specialCandy flavor="choco"/>
</ns0:candies>
</ns0:bag>
</tns:get_my_bagResult>
那么,如何在不定义新子类的情况下自定义数组内容的类型名称?我试过了
complex.Array(CandyModel.customize(type_name='specialCandy'))
但这不起作用。使用静态alias
方法会得到一个空的<ns0:candies/>
,也许是因为我仍然将CandyModel
个实例放到candies
列表中,但这是我的目标。
其次,为什么有xmlns:ns1="None"
以及如何为ns0
修复它?
顺便说一句。有没有办法自定义名称空间前缀?
class Candies(complex.Array):
__namespace__ = 'http://xml.candyshop.com/ns/candies/'
和
candies = Candies(CandyModel)
解决了命名空间的问题,但它是一种解决方法而不是解决方案。我更喜欢内联自定义或一些mixin与我的命名空间ComplexModel
。
答案 0 :(得分:1)
为什么要返回AnyXml而不是返回正确的对象?
这是您重构的代码,用于返回您想要的XML文档:
import logging
logging.basicConfig(level=logging.DEBUG)
logging.getLogger('spyne.protocol.xml').setLevel(logging.DEBUG)
from spyne.decorator import rpc
from spyne.service import ServiceBase
from spyne.util import xml
from spyne.model import complex, primitive
from spyne.application import Application
from spyne.protocol.soap import Soap11
from spyne.server.wsgi import WsgiApplication
from lxml import etree
class ComplexModel(complex.ComplexModelBase):
__namespace__ = 'http://xml.candyshop.com/ns/candies/'
__metaclass__ = complex.ComplexModelMeta
class CandyModel(ComplexModel):
__type_name__ = 'candy'
flavor = complex.XmlAttribute(primitive.Unicode)
class BagModel(ComplexModel):
__type_name__ = 'bag'
candies = complex.Array(CandyModel)
class Bag(ComplexModel):
bag = BagModel
class CandyShop(ServiceBase):
__tns__ = 'http://xml.candyshop.com/ns/shop/'
@rpc(_returns=Bag)
def get_my_bag(ctx):
bag = BagModel()
bag.candies = [CandyModel(flavor='choco')]
return Bag(bag=bag)
@classmethod
def dispatch(cls):
application = Application([cls],
tns=cls.__tns__,
in_protocol=Soap11(validator='lxml'),
out_protocol=Soap11(cleanup_namespaces=True)
)
return application
# In case you need to extract parts of your response, you can use hooks:
def _on_method_return_document(ctx):
ns = ctx.app.interface.nsmap
elt = ctx.out_document.xpath('//s0:bag',namespaces=ns)[0]
output = etree.tostring(elt, pretty_print=True)
print output # do what you want with it.
CandyShop.event_manager.add_listener('method_return_document',
_on_method_return_document)
if __name__ == '__main__':
from wsgiref.simple_server import make_server
service_app = CandyShop.dispatch()
application = WsgiApplication(service_app)
server = make_server('0.0.0.0', 8080, application)
server.serve_forever()
这是输出:
<?xml version='1.0' encoding='ASCII'?>
<senv:Envelope xmlns:tns="http://xml.candyshop.com/ns/shop/"
xmlns:s0="http://xml.candyshop.com/ns/candies/"
xmlns:senv="http://schemas.xmlsoap.org/soap/envelope/">
<senv:Body>
<tns:get_my_bagResponse>
<tns:get_my_bagResult>
<s0:bag>
<s0:candies>
<s0:candy flavor="choco"/>
</s0:candies>
</s0:bag>
</tns:get_my_bagResult>
</tns:get_my_bagResponse>
</senv:Body>
</senv:Envelope>
修改强>
如果您需要提取部分答案,可以使用挂钩。我已经更新了代码。此处还有许多事件示例:https://github.com/arskom/spyne/blob/master/examples/events.py