Вопрос по soap, python – Python suds неправильный префикс пространства имен в запросе SOAP

5

Я использую python / suds для реализации клиента и получаю неправильные префиксы пространства имен в отправляемом заголовке SOAP для специфического типа параметров, определенныхelement ref= в WSDL.

.Wsdl ссылается на файл .xsd типов данных, см. Ниже. Проблема с функциейGetRecordAttributes и его первый аргумент типа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>

Referenced File : grantabasetypes2.xsd

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

SOAP Request sent by suds:

<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>

Problem : <ns2:recordReferences> имеет неправильный префикс, должен быть<ns0:recordReferences> так как он принадлежит пространству имен...GrantaBaseTypes  определено в .xsd.

Это происходит для всех аргументов, определенныхref= в WSDL. Как это можно исправить автоматически?

Примечание. Я проверил, что это "хорошо" Служба принимает префикс, отправляя запрос xml SOAP через curl.

UPDATE

Я вмешался в исходный код SUDS, и следующее эмпирическое исправление заставляет все элементыref= атрибут для использования пространства имен ref-ed (ранее они брали пространство имен корней схемы или что-то ещеtns является):

Файл: /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

Работает с моим сервисом, но я не уверен, что он сломает другие вещи. Я бы предпочел более разумное решение, которое не меняет исходный код SUDS.

Спасибо,

Alex

Я действительно пытался перемещать и изменять определения, но, поскольку я не эксперт, возможно, я не могу точно определить правильный синтаксис, SUDS продолжал помещать туда неправильное пространство имен. Я также предпочел бы не играть с ними, поскольку они предоставляются внешним поставщиком и могут быть изменены. Смотрите ОБНОВЛЕНИЕ для неоптимального решения, которое я нашел до сих пор. al_miro
Это явно ошибка в вашем стеке; что вы подразумеваете под "автоматически"? Например, готовы ли вы работать с другим, но эквивалентным XSD, который будет работать с вашими инструментами? Исходя из того, что вы говорите, если вы замените ссылку локально определенным элементом, это сработает; для всех забот XSD сгенерированный XML будет таким же. Если вы думаете об изменениях в полете, как, например, использование какого-либо XSLT через прокси-сервер, это был бы другой подход. Я мог бы порекомендовать решение, которое будет автоматически реорганизовывать ваш XSD для замены ссылок на локальные элементы. Petru Gardea

Ваш Ответ

4   ответа
2

к сервису BizTalk / IIS SOAP. Из того, что я могу сказать из WSDL, это происходит, когда есть «complexType» это не является частью "targetNamespace" (он имеет его собственный), у которого есть дочерний элемент, который также является complexType, но без установленного пространства имен. В BizTalk это означает, что дочерний элемент должен принадлежать тому же пространству имен, что и родительский, но Suds, кажется, считает, что он должен быть частью targetNamespace ....

Исправление в исходном коде решило проблему «правильно», но так как я хочу иметь возможность обновляться без применения исправления каждый раз, когда я выбирал другое решение ...

Моим решением было пропустить Suds и просто скопировать необработанный XML, использовать его в качестве шаблона и копировать в него значения ... Не красиво, но, по крайней мере, просто. Решение добавить плагин, на мой взгляд, одинаково жестко запрограммировано и, возможно, еще сложнее в обслуживании.

8

Плагин Suds изменить XML перед отправкой.

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()])

Цитирование Suds документации:

marshalled()
Provides the plugin with the opportunity to inspect/modify the envelope Document before it is sent.

Это будет работать нормально для этого конкретного случая. Однако, поскольку таких параметров в разных позициях дерева много, их исправление вручную не является оптимальным. Я хотел бы что-то вродеprefix ns0 to all elements with ref= и хотя можно, вероятно, проанализировать все дерево XML, я считаю, что context.envelope не сохраняетref= Информация. al_miro
Еще один вариант расширенияDocumentPlugin чтобы изменить объект WSDL / XSD,parsed() метод (см. документацию) будет вызываться дважды (один для WSDL, другой для XSD).
Как я вижу, порядок именования ns (ns {x} и отображение uri) является случайным и меняется для каждого экземпляра клиента. Итак, я добавил это:array_ns = {v: k for k, v in context.envelope.nsprefixes.items()}['http://mylonguri']  И да, это сработало. И в большинстве случаев вторым ребенком тела будет определение метода. Так что вы можете проверитьcontext.envelope.getChild('Body').getChild('MyMethod') возражать, если этот запрос действительно относится к вашему методу, который вы хотите исправить или нет, и вы можете получить доступ к другим полям условно таким образом.
Отлично, спасибо !! Интересно, что мне пришлось исправить конверт в том же месте (структурно), что и в первоначальном примере. Здесь есть образец?
1

SoapClient отправить сообщение:

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

import re

class EnvelopeFixer(MessagePlugin):
    def sending(self, context):
        # rimuovi i prefissi
        context.envelope = re.sub( 'ns[0-9]:', '', context.envelope )
        return context.envelope
Ваш метод работает не очень хорошо: WebFault: Сервер вызвал ошибку: "Корневой элемент для запроса не может быть определен.
ммхххх ... так плагин стратегия это путь ...

Похожие вопросы