问题描述
我正在使用zeep(Python 3.6)与SOAP API进行接口,并使用包含本节的WSDL模式:
I am using zeep (Python 3.6) to interface with a SOAP API, and working with a WSDL schema which contains this section:
<xs:element name="passengers">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="passenger" type="com:PassengerType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
所以我希望我的zeep生成的XML看起来像这样:
So I'd like my zeep-generated XML to look like this:
<book:passengers>
<book:passenger>
...redacted...
</book:passenger>
</book:passengers>
我首次尝试使用Zeep实现这一目标的过程是这样的:
My first attempt at achieving this with Zeep looked like this:
passengers = [factories.PassengerType()]
但是,将其发送到我的SOAP API时,会产生以下错误:
However, when sending this to my SOAP API, this generated the following error:
File "/usr/local/lib/python3.6/site-packages/zeep/xsd/elements/element.py", line 220, in validate
"Missing element %s" % (self.name), path=render_path)
zeep.exceptions.ValidationError: Missing element passenger (createBookingRecordRequest.passengers)
我相信这是因为我的'passengers'属性应包含一个标记名称为"passenger"的Zeep对象,其中将包含我的元素列表.我已经尝试过修改zeep.xsd.AnyType
来实现这一目标,但是还没有成功.
I believe this is because my 'passengers' attribute should contain a Zeep object with the tag name "passenger", which would contain my list of elements. I've tried tinkering with the zeep.xsd.AnyType
to achieve this, but haven't succeeded yet.
任何建议将不胜感激.
推荐答案
回答我自己的问题,因为现在已经解决了该问题,但未收到其他任何答案.
Answering my own question as I've now solved it, and not received any other answers.
此问题的根源是我试图创建XML元素,而该元素未由SOAP API的WSDL明确定义为类型.不过这没关系,因为Zeep仍将为其生成类型对象,因此它不会将这些类型分配给特定的名称,因此我们必须跳过一些额外的步骤才能获得这些类型.这是我花了一些时间才弄清楚的.
The root of this problem is that I am trying to create XML element that is not explicitly defined as a type by my SOAP API's WSDL. This is OK though, as Zeep will still be generating type objects for it, it just won't be assigning those types to a particular name, so we have to jump through a few extra hoops to get at those types. This is what it took me a little time to figure out.
您可以通过任何父类型访问它们来获取这些对象.它们以2元组的列表形式存储在名为elements
的属性中.在这种情况下,我的PassengerType
对象应该由属性名称为"passengers"的序列容器包含.例如,如果我的父类型名为ParentType
,则可以这样使用乘客"序列:
You can get at these objects by accessing them through any parent type. They are stored in an attribute named elements
as a list of 2-tuples. In this case, my PassengerType
objects are supposed to be contained by a sequence container with the attribute name 'passengers'. If, for example, my parent type is named ParentType
, I could use this 'passengers' sequence like so:
passengers = dict(ParentType.elements)['passengers'](
PassengerType(),
...
PassengerType()
)
在这里,我们将elements对象转换为dict(利用了一个由2个元组组成的列表的事实,其中第一项是属性名称的字符串),然后按名称将元素拉出.
Here, we are turning the elements object into a dict (exploiting the fact that it's a list of 2-tuples where the first item is a string of the attribute name), and then pulling the elements out by name.
结果对象可以直接传递到ParentType
中,例如:
The resultant object can be passed directly into ParentType
like:
ParentType(passengers=passengers)
简单.
我发现的另一种替代方法是使用zeep的xsd
对象显式构建类型.示例如下所示.
One other alternative I discovered is to explicitly build the type with zeep's xsd
objects. Example shown below.
from lxml import etree
from zeep import xsd
PassengersType = xsd.ComplexType(
xsd.Sequence([
xsd.Element('passengers', PassengerType, min_occurs=1, max_occurs='unbounded')
]), qname=etree.QName("{http://example.com/schema}passengers")
)
我认为这不太好,但是对登陆这里的人可能有用.
I think this isn't as nice, but might be useful to someone landing here.
这篇关于使用zeep/python创建XML序列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!