2012-04-18 26 views
5

Tôi sử dụng python/suds để thực hiện một máy khách và tôi nhận được tiền tố không gian tên sai trong tiêu đề SOAP đã gửi cho một kiểu tham số spefic được xác định bởi element ref= trong wsdl.python sai số tiền tố không gian tên trong yêu cầu SOAP

.wsdl đang tham chiếu tệp dữ liệu .xsd, xem bên dưới. Vấn đề là với hàm GetRecordAttributes và đối số đầu tiên của loại gbt:recordReferences.

File: browse2.wsdl

<xsd:schema targetNamespace="http://www.grantadesign.com/10/10/Browse" xmlns="http://www.grantadesign.com/10/10/Browse" xmlns:gbt="http://www.grantadesign.com/10/10/GrantaBaseTypes" elementFormDefault="qualified" attributeFormDefault="qualified"> 
<xsd:import schemaLocation="grantabasetypes2.xsd" namespace="http://www.grantadesign.com/10/10/GrantaBaseTypes"/> 
<xsd:element name="GetRecordAttributes"> 
     <xsd:complexType> 
      <xsd:sequence> 
       <xsd:element ref="gbt:recordReferences"> 
       </xsd:element> 

Tham chiếu tập tin: grantabasetypes2.xsd

<element name="recordReferences"> 
    <complexType> 
    <sequence> 
     <element name="record" minOccurs="0" maxOccurs="unbounded" type="gbt:MIRecordReference"/> 
    </sequence> 
    </complexType> 
</element> 

SOAP Request gửi bởi bọt:

<SOAP-ENV:Envelope xmlns:ns0="http://www.grantadesign.com/10/10/GrantaBaseTypes" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://www.grantadesign.com/10/10/Browse" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> 
    <SOAP-ENV:Header/> 
    <ns1:Body> 
     <ns2:GetRecordAttributes> 
     <ns2:recordReferences> 
      <ns0:record> 
      </ns0:record> 
     </ns2:recordReferences> 
     </ns2:GetRecordAttributes> 
    </ns1:Body> 
</SOAP-ENV:Envelope> 

Vấn đề: <ns2:recordReferences> có tiền tố sai, phải là <ns0:recordReferences> vì nó thuộc về không gian tên ...GrantaBaseTypes được xác định trong .xsd.

Điều này xảy ra cho tất cả các đối số được xác định bởi ref= trong wsdl. Làm thế nào điều này có thể được tự động cố định?

Lưu ý: Tôi đã kiểm tra xem tiền tố "tốt" có được dịch vụ chấp nhận hay không bằng cách gửi yêu cầu SOAP xml theo cách thủ công qua curl.

CẬP NHẬT

tôi meddled với mã bọt nguồn và sau lực lượng sửa chữa thực nghiệm tất cả các yếu tố với ref= thuộc tính để giả định không gian tên ref-ed (trước đây, họ đi trên namespace gốc schema hoặc bất cứ điều gì tns là) :

file: /suds/xsd/sxbase.py

class SchemaObject(object): 
.... 
    def namespace(self, prefix=None): 

     ns = self.schema.tns 

#FIX BEGIN 
     if self.ref and self.ref in self.schema.elements.keys(): 
      ns = self.ref 
#FIX END 

trình với dịch vụ của tôi, nhưng tôi không chắc chắn nếu nó sẽ phá vỡ điều khác S. Tôi thích một giải pháp thông minh hơn mà không thay đổi mã nguồn SUDS.

Cảm ơn,

Alex

+0

Đây rõ ràng là một lỗi trong ngăn xếp của bạn; ý bạn là gì "tự động"? Ví dụ: bạn có sẵn sàng làm việc với một XSD khác, nhưng tương đương sẽ làm việc với công cụ của bạn không? Từ những gì bạn nói, nếu bạn thay thế ref bằng một phần tử được xác định cục bộ, nó sẽ hoạt động; đối với tất cả các quan tâm của XSD, XML được tạo ra sẽ giống nhau. Nếu bạn nghĩ về việc thay đổi trên chuyến bay, như sử dụng một số loại XSLT thông qua một proxy, đó sẽ là một cách tiếp cận khác. Tôi có thể đề xuất một giải pháp sẽ tự động refactor XSD của bạn để thay thế refs với các yếu tố địa phương. –

+0

Tôi thực sự đã thử di chuyển và thay đổi định nghĩa, nhưng vì tôi không phải là một chuyên gia có lẽ tôi không thể xác định đúng cú pháp, SUDS tiếp tục đặt không gian tên sai ở đó. Tôi cũng không thích đùa giỡn với những thứ này, vì chúng được cung cấp bởi một nhà cung cấp bên ngoài và có thể thay đổi. Xem UPDATE cho một giải pháp không tối ưu tôi đã tìm thấy cho đến nay. –

Trả lời

8

Viết Suds plugin để thay đổi XML trước khi nó được gửi đi.

from suds.client import Client 
from suds.plugin import MessagePlugin 

class MyPlugin(MessagePlugin): 
    def marshalled(self, context): 
     #modify this line to reliably find the "recordReferences" element 
     context.envelope[1][0][0].setPrefix('ns0') 

client = Client(WSDL_URL, plugins=[MyPlugin()]) 

Trích dẫn tài liệu bọt:

marshalled()
Cung cấp các plugin có cơ hội để kiểm tra/sửa đổi các tài liệu phong bì trước khi nó được gửi đi.

+1

Điều này sẽ hoạt động tốt cho trường hợp cụ thể này. Tuy nhiên vì có rất nhiều thông số như vậy ở các vị trí cây khác nhau, việc sửa chúng bằng tay không phải là tối ưu. Tôi muốn một cái gì đó như _prefix ns0 cho tất cả các yếu tố với ref = _, và trong khi người ta có thể cho là phân tích cú pháp toàn bộ cây xml, tôi tin rằng context.envelope không giữ lại thông tin 'ref ='. –

+0

Một tùy chọn khác là mở rộng 'DocumentPlugin' để sửa đổi đối tượng WSDL/XSD, phương thức' parsed() '(xem tài liệu) sẽ được gọi hai lần (một cho WSDL, một cho XSD). – dusan

+0

Rực rỡ, cảm ơn !! Điều thú vị là tôi phải sửa phong bì ở cùng một nơi (cấu trúc) giống như ví dụ ban đầu. Có mô hình ở đây không? – Gesias

1

Bạn có thể xây dựng thông điệp xà phòng mình và sử dụng SoapClient để gửi tin nhắn:

sc = SoapClient(cli.service.XXXMethod.client,cli.service.XXXMethod.method) 
sc.send(some_soap_doc) 
2

tôi đã có vấn đề chính xác tương tự khi sử dụng bọt để truy cập một dịch vụ SOAP/IIS BizTalk. Từ những gì tôi có thể nói từ WSDL nó xảy ra khi có một "complexType" không phải là một phần của "targetNamespace" (nó có nó), có một con cũng là một complexType, nhưng không có không gian tên được đặt. Trong BizTalk, điều này có nghĩa là đứa trẻ phải thuộc về cùng một không gian tên như cha mẹ, nhưng Suds dường như nghĩ rằng nó nên là một phần của targetNamespace ....

Việc sửa mã nguồn đã giải quyết được vấn đề " chính xác ", nhưng vì tôi muốn có thể nâng cấp mà không áp dụng sửa chữa mỗi lần tôi đi giải pháp khác ....

Giải pháp của tôi là bỏ qua Sud và chỉ sao chép XML thô, sử dụng làm mẫu và sao chép các giá trị vào nó ... Không đẹp, nhưng ít nhất là đơn giản. Các giải pháp để thêm một plugin là theo ý kiến ​​của tôi bằng nhau hardcoded và thậm chí có thể khó khăn hơn để duy trì.

0

Tôi thích biểu thức thông thường :)

import re 

class EnvelopeFixer(MessagePlugin): 
    def sending(self, context): 
     # rimuovi i prefissi 
     context.envelope = re.sub('ns[0-9]:', '', context.envelope) 
     return context.envelope 
+0

Phương thức của bạn không hoạt động tốt: WebFault: Lỗi máy chủ: 'Phần tử gốc cho yêu cầu không thể xác định được. – Allen

+0

mmhhh ... vì vậy chiến lược plugin là cách ... –

Các vấn đề liên quan