[Major Edit, основанный на опыте с 1-го поста два дня назад.]
Я создаю сценарий Python SOAP / XML с использованием Suds, но изо всех сил пытаюсь получить код для генерации SOAP / XML, который является приемлемымна сервер.Я думал, что проблема заключается в том, что Suds не генерирует префиксы для внутренних элементов, но впоследствии выясняется, что отсутствие префиксов (см. Sh-Data
и внутренние элементы) не является проблемой, так как Sh-Data
и MetaSwitchData
элементы объявляют соответствующие пространства имен (см. ниже).
<SOAP-ENV:Envelope xmlns:ns3="http://www.metaswitch.com/ems/soap/sh" xmlns:ns0="http://www.metaswitch.com/ems/soap/sh/userdata" xmlns:ns1="http://www.metaswitch.com/ems/soap/sh/servicedata" xmlns:ns2="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<ns2:Body>
<ns3:ShUpdate>
<ns3:UserIdentity>Meribel/TD Test Sub Gateway 3</ns3:UserIdentity>
<ns3:DataReference>0</ns3:DataReference>
<ns3:UserData>
<Sh-Data xmlns="http://www.metaswitch.com/ems/soap/sh/userdata">
<RepositoryData>
<ServiceIndication>Meta_SubG_BaseInformation</ServiceIndication>
<SequenceNumber>0</SequenceNumber>
<ServiceData>
<MetaSwitchData xmlns="http://www.metaswitch.com/ems/soap/sh/servicedata" IgnoreSequenceNumber="False" MetaSwitchVersion="?">
<Meta_SubG_BaseInformation Action="apply">
<NetworkElementName>Meribel</NetworkElementName>
<Description>TD Test Sub Gateway 3</Description>
<DomainName>test.datcon.co.uk</DomainName>
<MediaGatewayModel>Cisco ATA</MediaGatewayModel>
<CallFeatureServerControlStatus/>
<CallAgentControlStatus/>
<UseStaticNATMapping/>
<AuthenticationRequired/>
<ProviderStatus/>
<DeactivationMode/>
</Meta_SubG_BaseInformation>
</MetaSwitchData>
</ServiceData>
</RepositoryData>
</Sh-Data>
</ns3:UserData>
<ns3:OriginHost>user@domain.com?clientVersion=7.3</ns3:OriginHost>
</ns3:ShUpdate>
</ns2:Body>
</SOAP-ENV:Envelope>
Но это все равно не удается.Проблема в том, что Suds генерирует пустые элементы для необязательных элементов (помеченных как Mandatory = No
в WSDL).Но сервер требует, чтобы дополнительный элемент либо присутствовал с разумным значением, либо отсутствовал, и я получаю следующую ошибку (поскольку элемент <CallFeatureServerControlStatus/>
не является одним из допустимых значений.
Пользовательпредоставленные данные не были проверены в соответствии с XML-схемой MetaSwitch для пользовательских данных.
Подробности: cvc-enumeration-valid: значение '' не является корректным по отношению к перечислению '[Controlling, Abandoned, Осторожно контролирующий]'.быть значением из перечисления.
Если я возьму сгенерированный SOAP / XML в SOAPUI и удалю пустые элементы, запрос будет работать нормально.
Есть ли способ получитьНужно или не генерировать пустые элементы для необязательных полей, или для меня, чтобы потом удалить их в коде?
Major Update
Я решил эту проблему (которую я 'видел в другом месте), но довольно не элегантно. Так что я публикую свое текущее решение в надежде, что а) оно поможет другим и / или б) кто-то может посоветоватьr обходной путь.
Оказывается, проблема не в том, что Suds генерирует пустые элементы для необязательных элементов (помеченных как Mandatory = No
в WSDL).Но вместо этого тот Sud генерирует пустые элементы для необязательных сложных элементов.Например, следующие элементы Meta_SubG_BaseInformation являются простыми элементами, и Suds не генерирует для них ничего в SOAP / XML.
<xs:element name="CMTS" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>
<d:DisplayName firstVersion="5.0" lastVersion="7.4">CMTS</d:DisplayName>
<d:ValidFrom>5.0</d:ValidFrom>
<d:ValidTo>7.4</d:ValidTo>
<d:Type firstVersion="5.0" lastVersion="7.4">String</d:Type>
<d:BaseAccess firstVersion="5.0" lastVersion="7.4">RWRWRW</d:BaseAccess>
<d:Mandatory firstVersion="5.0" lastVersion="7.4">No</d:Mandatory>
<d:MaxLength firstVersion="5.0" lastVersion="7.4">1024</d:MaxLength>
</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="TAGLocation" type="xs:string" minOccurs="0">
<xs:annotation>
<xs:documentation>
<d:DisplayName>Preferred location of Trunk Gateway</d:DisplayName>
<d:Type>String</d:Type>
<d:BaseAccess>RWRWRW</d:BaseAccess>
<d:Mandatory>No</d:Mandatory>
<d:DefaultValue>None</d:DefaultValue>
<d:MaxLength>1024</d:MaxLength>
</xs:documentation>
</xs:annotation>
</xs:element>
В противоположность этому следующий элемент Meta_SubG_BaseInformation является сложным элементом, и даже если он является необязательным иМой код не присваивает ему значение, он заканчивается в сгенерированном SOAP / XML.
<xs:element name="ProviderStatus" type="tMeta_SubG_BaseInformation_ProviderStatus" minOccurs="0">
<xs:annotation>
<xs:documentation>
<d:DisplayName>Provider status</d:DisplayName>
<d:Type>Choice of values</d:Type>
<d:BaseAccess>R-R-R-</d:BaseAccess>
<d:Mandatory>No</d:Mandatory>
<d:Values>
<d:Value>Unavailable</d:Value>
<d:Value>Available</d:Value>
<d:Value>Inactive</d:Value>
<d:Value>Active</d:Value>
<d:Value>Out of service</d:Value>
<d:Value>Quiescing</d:Value>
<d:Value>Unconfigured</d:Value>
<d:Value>Pending available</d:Value>
</d:Values>
</xs:documentation>
</xs:annotation>
</xs:element>
Suds генерирует следующее для ProviderStatus, который (как указано выше) расстраивает мой сервер.
<ProviderStatus/>
Обходное решение - установить для всех элементов Meta_SubG_BaseInformation
значение None
после создания родительского элемента и перед присвоением значений, как показано ниже.Это является излишним для простых элементов, но гарантирует, что неназначенные сложные элементы не приведут к генерации SOAP / XML.
subGatewayBaseInformation = client.factory.create('ns1:Meta_SubG_BaseInformation')
for (el) in subGatewayBaseInformation:
subGatewayBaseInformation.__setitem__(el[0], None)
subGatewayBaseInformation._Action = 'apply'
subGatewayBaseInformation.NetworkElementName = 'Meribel'
etc...
В результате Suds генерирует SOAP / XML без пустых элементов, что приемлемона мой сервер.
Но кто-нибудь знает более чистый способ достижения того же эффекта?
Решение, приведенное ниже, основано на ответах / комментариях от Душана и Ролана Смита ниже.
В этом решении используется SudS MessagePlugin для обрезки «пустого» XML вида <SubscriberType/>
до того, как Suds отправит запрос в проводное соединение.Нам нужно только сократить ShUpdates (где мы обновляем данные на сервере), и логика (особенно индексация дочерних элементов для получения списка элементов индикации обслуживания) очень специфична для WSDL.Это не будет работать для разных WSDL.
class MyPlugin(MessagePlugin):
def marshalled(self, context):
pruned = []
req = context.envelope.children[1].children[0]
if (req.name == 'ShUpdate'):
si = req.children[2].children[0].children[0].children[2].children[0].children[0]
for el in si.children:
if re.match('<[a-zA-Z0-9]*/>', Element.plain(el)):
pruned.append(el)
for p in pruned:
si.children.remove(p)
И тогда нам просто нужно сослаться на плагин при создании клиента.
client = Client(url, plugins=[MyPlugin()])