0

Sudsを使用してWebサービスと通信しようとしていますが、サービスからの読み取りは正常に機能しますが、書き込みはエラーをスローします。

suds.WebFault:サーバーで障害が発生しました:'メッセージの逆シリアル化の試行中にフォーマッタが例外をスローしました:パラメータhttp://tempuri.org/:tagValuesの逆シリアル化の試行中にエラーが発生しました。InnerExceptionメッセージは次のとおりです。'名前空間からの要素値 http://schemas.datacontract.org/2004/07/NOV.Api.Messagesには、オブジェクトとして逆シリアル化する子コンテンツを含めることはできません。XmlNode []を使用して、このXMLパターンを逆シリアル化します。詳細については、InnerExceptionを参照してください。

XMLが生成するものは、必要なxsi:type = "xsd:int"を追加していないようです。

生産:

<ns1:TagValue>
   <ns1:Quality>
      <ns1:Id>1</ns1:Id>
      <ns1:QualityData>Quality</ns1:QualityData>
   </ns1:Quality>
   <ns1:TagID>
      <ns1:Id>0</ns1:Id>
      <ns1:TagID>BitDepth</ns1:TagID>
   </ns1:TagID>
   <ns1:Value>23</ns1:Value>
</ns1:TagValue>

期待される:

<ns1:TagValue>
   <ns1:Quality>
      <ns1:Id>1</ns1:Id>
      <ns1:QualityData>Quality</ns1:QualityData>
   </ns1:Quality>
   <ns1:TagID>
      <ns1:Id>0</ns1:Id>
      <ns1:TagID>BitDepth</ns1:TagID>
   </ns1:TagID>
   <ns1:Value xsi:type="xsd:int">23</ns1:Value>
</ns1:TagValue>

周りを検索した後、私はImportDoctorを試して、xsi:typeに入ることができるかどうかを確認することにしました。

追加した

schema_url = 'http://schemas.xmlsoap.org/soap/encoding/'
schema_import = Import(schema_url)
schema_doctor = ImportDoctor(schema_import)

クライアントctorのdoctor=schema_doctor

これにより、追加のプレフィックスとタイプのはるかに拡張されたリストが得られました

Prefixes (4)
   ns0 = "http://schemas.datacontract.org/2004/07/NOV.Api.Messages"
   ns1 = "http://schemas.microsoft.com/2003/10/Serialization/"
   ns2 = "http://schemas.xmlsoap.org/soap/encoding/"
   ns3 = "http://tempuri.org/"

私は今ns2:intを持っています

ファクトリを使用して、ns2:int型のオブジェクトを作成し、その値を23に設定しました。

これを送信すると、次のXMLが表示されます。

<ns1:TagValue>
   <ns1:Quality>
      <ns1:Id>1</ns1:Id>
      <ns1:QualityData>Quality</ns1:QualityData>
   </ns1:Quality>
   <ns1:TagID>
      <ns1:Id>0</ns1:Id>
      <ns1:TagID>BitDepth</ns1:TagID>
   </ns1:TagID>
   <ns1:Value xsi:type="ns2:int">23</ns1:Value>
</ns1:TagValue>

送信しようとすると、次の例外が発生します。

suds.WebFault:サーバーで障害が発生しました:'メッセージの逆シリアル化の試行中にフォーマッタが例外をスローしました:パラメータhttp://tempuri.org/:tagValuesの逆シリアル化の試行中にエラーが発生しました。InnerExceptionメッセージは「1行目の位置651のエラー」でした。要素「http://schemas.datacontract.org/2004/07/NOV.Api.Messages:Value」には、名前「http:/」にマップされるタイプのデータが含まれています。 /schemas.xmlsoap.org/soap/encoding/:int'。デシリアライザーは、この名前にマップされるタイプを認識していません。DataContractResolverの使用を検討するか、「int」に対応する型を既知の型のリストに追加します。たとえば、KnownTypeAttribute属性を使用するか、DataContractSerializerに渡される既知の型のリストに追加します。

少し近いように見えますが、名前空間に混乱があるようです。

生成された完全なXML:

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns3="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns0="http://tempuri.org/" xmlns:ns1="http://schemas.datacontract.org/2004/07/NOV.Api.Messages" xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
   <SOAP-ENV:Header/>
   <ns3:Body>
      <ns0:WriteRealtimeValues>
         <ns0:tagValues>
            <ns1:TagValue>
               <ns1:Quality>
                  <ns1:Id>1</ns1:Id>
                  <ns1:QualityData>Quality</ns1:QualityData>
               </ns1:Quality>
               <ns1:TagID>
                  <ns1:Id>0</ns1:Id>
                  <ns1:TagID>BitDepth</ns1:TagID>
               </ns1:TagID>
               <ns1:Value xsi:type="ns2:int">23</ns1:Value>
            </ns1:TagValue>
         </ns0:tagValues>
      </ns0:WriteRealtimeValues>
   </ns3:Body>
</SOAP-ENV:Envelope>

参考までに、次のコードを使用してクライアントを作成します

credentials = dict(username='%s' % (username), password='%s' % password)
url=   "http://%s:%s/TagValueWriteService?wsdl" % (ip,port)
self.transport  = HttpAuthenticated(**credentials)
suds.client.Client.__init__(self,url, transport=self.transport, cache=None,doctor=schema_doctor)

ここスタックオーバーフローにはいくつかの同様の問題があるようですが、それらのほとんどは私が試したのと同じようにImportDoctorに言及しています。私はSOAPの基本的な理解の一部が不足していると思います...

4

2 に答える 2

2

SUDSを使用するときにxsi:typeとenvelope名前空間を追加するhttps://stackoverflow.com/a/10977734/696768)の回答を使用して、なんとか解決しました。

これが唯一の可能な解決策であるかどうかはわかりません。私には、これは他の何よりもハックのように見えますが、現在のシナリオでは問題なく機能します。

私が使用した解決策は、クライアント用のプラグインを作成し、xsi:type = "xsd:int"である必要がある特定の要素を探し、これらの属性をそれらの要素に追加することです。

私が参照用に使用することになったコード(前述のわずかな調整を加えたstackoverflowの質問から):

from suds.plugin import MessagePlugin
from suds.sax.attribute import Attribute

class SoapFixer(MessagePlugin):
    def marshalled(self, context):
        # Alter the envelope so that the xsd namespace is allowed
        context.envelope.nsprefixes['xsd'] = 'http://www.w3.org/2001/XMLSchema'
        # Go through every node in the document and apply the fix function to patch up incompatible XML. 
        context.envelope.walk(self.fix_any_type_string)
    def fix_any_type_string(self, element):
        """Used as a filter function with walk in order to fix errors.
        If the element has a certain name, give it a xsi:type=xsd:int. Note that the nsprefix xsd must also
         be added in to make this work."""

        # Fix elements which have these names
        fix_names = ['Value', 'anotherelementname']
        if element.name in fix_names:
            element.attributes.append(Attribute('xsi:type', 'xsd:int'))


plugin=SoapFixer()

次に、plugins=[plugin]をクライアントctorに追加しました。

例:

client = suds.client.Client("http://127.0.0.1:8099/TagValueWriteService?wsdl",plugins=[plugin])
于 2012-11-28T20:05:41.810 に答える
1

この質問はクライアント側であるため、これは「回答」ではありません。しかし、私は今のところ検索エンジンのためにこれをここに置いています。

問題は、要求メッセージが複合型であるということです。

私の解決策はサーバー側でした。私のサービスは、リクエスト内の型指定されていない要素を受け入れるようになりました。リクエスト本文のサーバー側の解析では、リクエストスキーマについて知っている必要があります。これが発生すると、サーバーは、クライアントが要素を入力しなくても、リクエストをタイプチェックして解析できます。

具体的には、私のエラーはPythonZSIモジュールとZopeで実装されたサービスから発生しました。

型指定されていない要素を解析することはできません

ここで、複雑なリクエストオブジェクトに関するヒントを入手しました:http:
//pypi.python.org/pypi/z3c.soap/ (ValidateEmailRequestを参照)

ここで、ZSIのクラッシュコースを受講しました。ZoleraSOAP インフラストラクチャ(ZSI)の実用的な例はありますか?

そしてここにまともなZSIドキュメント:http://pywebsvcs.sourceforge.net/zsi.html#SECTION0071100000000000000000

ZSIを満足させるには、Requestメッセージを表すクラスを作成し、それにタイプコードを追加するだけです。これが、「operation foo」、「fooRequest」、「fooResponse」に対する多くのサービスが表示される理由です。これらのサービスは、リクエストオブジェクトとレスポンスオブジェクトをxml複合型として入力できます。

上記の例では、soapリクエストの本文が解析されている名前空間にこのようなものをインポートします。あなたははるかに複雑になる可能性がありますが、これは本当に必要なすべてです:

import ZSI

class WriteRealTimeValuesRequest(object):
   tagValues = array() #of TagValue


WriteRealTimeValuesRequest.typecode = ZSI.TC.Struct(WriteRealTimeValuesRequest,
                                                    (ZSI.TC.Array("TagValue",
                                                                 TagValue.typecode,
                                                                 "tagValues"
                                                                ),
                                                     ),
                                                    "WriteRealTimeValuesRequest")

「タグの値は何ですか?」

class TagValue(object):
   Quality = Quality
   TagId = TagId
   Value = Value

TagValue.typecode = ZSI.TC.Struct(TagValue,
                                  (Quality.typecode,
                                   TagId.typecode,
                                   Value.typecode),
                                  "TagValue")

品質とは何ですか?

class Quality(object):
   Id = 0
   QualityData = "I'm a string"

Quality.typecode = ZSI.TC.Struct(Quality,
                                 (ZSI.TC.Integer("Id"),  #this is the secret sauce 
                                  ZSI.TC.String("QualityData")  #and here
                                 ),
                                 "Quality")

など、すべてのプリミティブ型にドリルダウンするまで続きます。

于 2012-12-06T02:57:49.780 に答える