swaRefの仕様書を眺めていたところ、
<?xml version='1.0' ?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <claim:insurance_claim_auto id="insurance_claim_document_id" xmlns:claim="http://schemas.risky-stuff.com/Auto-Claim"> <theSignedForm href="cid:claim061400a.tiff@claiming-it.com"/> <theCrashPhoto href="cid:claim061400a.jpeg@claiming-it.com"/> <!-- ... more claim details go here... --> </claim:insurance_claim_auto> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
となっていました。
気になったのは
<theSignedForm href="cid:claim061400a.tiff@claiming-it.com"/>
のように、 element theSignedForm
に、attribute href
があったことです。
elementにattributeのあるWSDLを書いたことがないため、今回
- WSDLで element に attribute を追加する方法
- Zeepで、 attributeに値を設定する方法
をそれぞれ調べてみました。
目次
環境
- Python 3.7.1
- Zeep 3.2.0
WSDLのelementにattributeを追加する方法
WSDLはXMLなので、XMLでの追加方法を調べてみました。
属性を追加する場合は、xsd:attribute要素を使用します。
とのことなので、WSDL内の型定義を
<xsd:element name="RequestInterface"> <xsd:complexType> <xsd:sequence> <xsd:element minOccurs="0" name="image"/> </xsd:sequence> <!-- 追加 --> <xsd:attribute name="href" type="xsd:string" /> </xsd:complexType> </xsd:element>
として、 image
elementに href
を追加できないか試してみました。
結果は、
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> <soap-env:Body> <ns0:RequestInterface xmlns:ns0="http://example.com/HelloWorld" href="ham_spam"/> </soap-env:Body> </soap-env:Envelope>
と、その親 RequestInterface
elementに付きました。
RequestInterfaceの子の image
element に追加できないかを調べたところ、同じページに
ref属性を記述した場合、要素の構造については別の場所で宣言します。そして、ref属性の値に記されている要素を参照します。
とありました。
そのため、WSDLを
<!-- 名前空間 my (任意の名前で可)を追加 --> <wsdl:definitions ... xmlns:my="http://example.com/HelloWorld" targetNamespace="http://example.com/HelloWorld"> <wsdl:types> <!-- ここのtargetNamespaceも適当に設定(先ほどのと同じでもOK) --> <xsd:schema elementFormDefault="qualified" targetNamespace="http://example.com/HelloWorld"> <xsd:element name="RequestInterface"> <xsd:complexType> <xsd:sequence> <!-- このelementにattributeを設定するため、refで別の型を参照させる --> <!-- SOAP UIで動作させるため、名前空間(my)を付与して、参照先を明確にする --> <xsd:element minOccurs="0" ref="my:image"/> </xsd:sequence> </xsd:complexType> </xsd:element> <!-- attributeを付けたい型の定義--> <xsd:element name="image"> <xsd:complexType> <xsd:attribute name="href" type="xsd:string" /> </xsd:complexType> </xsd:element>
として試してみます。
なお、WSDL中のコメントにも記載しましたが、 ref
属性を使うときは、
を行います。名前空間がない場合、SOAP UIでWSDLをimportする際、エラーとなってしまいます。
参考:xml - What does the ref attribute on an element in an XSD do? - Stack Overflow
実行結果は
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> <soap-env:Body> <ns0:RequestInterface xmlns:ns0="http://example.com/HelloWorld"> <ns0:image href="foo_bar"/> </ns0:RequestInterface> </soap-env:Body> </soap-env:Envelope>
と、image elementに href attribute が追加されました。
ちなみに、
<xsd:element name="RequestInterface"> <xsd:complexType> <xsd:sequence> <xsd:element minOccurs="0" name="image"/> <!-- sequenceの中にattributeを追加 --> <xsd:attribute name="href" type="xsd:string" /> </xsd:sequence> </xsd:complexType> </xsd:element>
と、 <xsd:sequence>
の中に <xsd:attribute>
を入れると、以下のエラーになります。
zeep.exceptions.XMLParseError: Unexpected element {http://www.w3.org/2001/XMLSchema}attribute in xsd:sequence
WSDLのattributeに、Zeepから値を設定する
WSDLでelementにattributeを付けられたものの、どうすればZeepから値を与えられるのかが分かりませんでした。
調べてみたところ、Stack Overflowに回答があったため、それを参考に実装してみます。
Python Zeep - how to set attributes for element - Stack Overflow
親要素のattributeを設定する
client.service.requestMessage(href='ham_spam')
と、attribute名の引数に対し、設定したい値を渡します。
history_plugin = HistoryPlugin() child_wsdl = BASE_PATH.joinpath('root_attribute.wsdl') client = Client(str(child_wsdl), plugins=[history_plugin]) # Zeepと同様、requests_mockを使って、POSTをMockする # https://github.com/mvantellingen/python-zeep/blob/3.2.0/tests/integration/test_http_post.py#L15 with requests_mock.mock() as m: m.post('http://localhost:9500/attributeBindingSoap11', text='<root>mocked!</root>') # requestMessage()の結果がWSDLの内容と異なるため、常にXMLSyntaxErrorが出る # 今回は送信したSOAPエンベロープの値を見たいので、例外は無視する try: response = client.service.requestMessage(href='ham_spam') except XMLSyntaxError: pass print(etree.tostring(history_plugin.last_sent['envelope'], pretty_print=True, encoding='unicode'))
実行すると、親要素の RequestInterface
の href
に値が設定されました。
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> <soap-env:Body> <ns0:RequestInterface xmlns:ns0="http://example.com/HelloWorld" href="ham_spam"/> </soap-env:Body> </soap-env:Envelope>
子要素のattributeを設定する
親要素との変更点は、 client.service.requestMessage(image={'href': 'foo_bar'})
と、element名の引数に対し、属性名のdictを渡すことだけです。
history_plugin = HistoryPlugin() child_wsdl = BASE_PATH.joinpath('child_attribute.wsdl') client = Client(str(child_wsdl), plugins=[history_plugin]) with requests_mock.mock() as m: m.post('http://localhost:9501/attributeBindingSoap11', text='<root>mocked!</root>') try: # image elementの要素をdictで渡す response = client.service.requestMessage(image={'href': 'foo_bar'}) except XMLSyntaxError: pass print(etree.tostring(history_plugin.last_sent['envelope'], pretty_print=True, encoding='unicode'))
実行すると、子要素の image
の href
に値が設定されました。
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"> <soap-env:Body> <ns0:RequestInterface xmlns:ns0="http://example.com/HelloWorld"> <ns0:image href="foo_bar"/> </ns0:RequestInterface> </soap-env:Body> </soap-env:Envelope>
ソースコード
GitHubに上げました。 wsdl_attribute/
ディレクトリの中が今回のファイルです。
https://github.com/thinkAmi-sandbox/python_zeep-sample