使用 zeep / python 创建 XML 序列
Creating XML sequences with zeep / python
我正在使用 zeep (Python 3.6) 与 SOAP API 交互,并使用包含此部分的 WSDL 架构:
<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 看起来像这样:
<book:passengers>
<book:passenger>
...redacted...
</book:passenger>
</book:passengers>
我第一次使用 Zeep 实现此目的的尝试如下所示:
passengers = [factories.PassengerType()]
但是,当将其发送到我的 SOAP API 时,会产生以下错误:
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
来实现这一点,但还没有成功。
如有任何建议,我们将不胜感激。
回答我自己的问题,因为我现在已经解决了,没有收到任何其他答案。
此问题的根源在于我试图创建 XML 元素,而我的 SOAP API 的 WSDL 并未将其明确定义为类型。但这没关系,因为 Zeep 仍会为其生成类型对象,它只是不会将这些类型分配给特定名称,因此我们必须跳过一些额外的环节才能获得这些类型。这是我花了一点时间才弄明白的。
您可以通过任何父类型访问它们来获取这些对象。它们作为 2 元组列表存储在名为 elements
的属性中。在这种情况下,我的 PassengerType
对象应该包含在属性名称为 'passengers' 的序列容器中。例如,如果我的父类型被命名为 ParentType
,我可以像这样使用这个 'passengers' 序列:
passengers = dict(ParentType.elements)['passengers'](
PassengerType(),
...
PassengerType()
)
在这里,我们将元素对象转换为字典(利用它是一个二元组列表,其中第一项是属性名称的字符串),然后按名称拉出元素。
结果对象可以直接传递给ParentType
,如:
ParentType(passengers=passengers)
简单。
我发现的另一种选择是使用 zeep 的 xsd
对象显式构建类型。示例如下。
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")
)
我认为这不是很好,但可能对登陆这里的人有用。
我正在使用 zeep (Python 3.6) 与 SOAP API 交互,并使用包含此部分的 WSDL 架构:
<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 看起来像这样:
<book:passengers>
<book:passenger>
...redacted...
</book:passenger>
</book:passengers>
我第一次使用 Zeep 实现此目的的尝试如下所示:
passengers = [factories.PassengerType()]
但是,当将其发送到我的 SOAP API 时,会产生以下错误:
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
来实现这一点,但还没有成功。
如有任何建议,我们将不胜感激。
回答我自己的问题,因为我现在已经解决了,没有收到任何其他答案。
此问题的根源在于我试图创建 XML 元素,而我的 SOAP API 的 WSDL 并未将其明确定义为类型。但这没关系,因为 Zeep 仍会为其生成类型对象,它只是不会将这些类型分配给特定名称,因此我们必须跳过一些额外的环节才能获得这些类型。这是我花了一点时间才弄明白的。
您可以通过任何父类型访问它们来获取这些对象。它们作为 2 元组列表存储在名为 elements
的属性中。在这种情况下,我的 PassengerType
对象应该包含在属性名称为 'passengers' 的序列容器中。例如,如果我的父类型被命名为 ParentType
,我可以像这样使用这个 'passengers' 序列:
passengers = dict(ParentType.elements)['passengers'](
PassengerType(),
...
PassengerType()
)
在这里,我们将元素对象转换为字典(利用它是一个二元组列表,其中第一项是属性名称的字符串),然后按名称拉出元素。
结果对象可以直接传递给ParentType
,如:
ParentType(passengers=passengers)
简单。
我发现的另一种选择是使用 zeep 的 xsd
对象显式构建类型。示例如下。
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")
)
我认为这不是很好,但可能对登陆这里的人有用。