[Major Edit основанные на опыте, так как 1-й пост два дня назад.]Suds генерирует пустые элементы; как их удалить?
Я строю 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>[email protected]?clientVersion=7.3</ns3:OriginHost>
</ns3:ShUpdate>
</ns2:Body>
</SOAP-ENV:Envelope>
Но это все еще не удается. Проблема в том, что Suds генерирует пустые элементы для дополнительных элементов (помеченных как Mandatory = No
в WSDL). Но сервер требует, чтобы дополнительный элемент либо присутствует с разумной стоимостью или отсутствуют, и я получаю следующее сообщение об ошибке (потому что <CallFeatureServerControlStatus/>
элемент не является одним из допустимых значений.
The user data provided did not validate against the MetaSwitch XML Schema for user data.
Details: cvc-enumeration-valid: Value '' is not facet-valid with respect to enumeration '[Controlling, Abandoned, Cautiously controlling]'. It must be a value from the enumeration.
Если взять сгенерированный SOAP/XML в SoapUI и удалить пустые элементы, запрос работает просто отлично.
есть ли способ, чтобы получить Suds либо не создают пустые элементы для дополнительных полей, или для меня, чтобы удалить их в коде после этого?
Главное обновление
Я решил эту проблему (что я видел в другом месте), но довольно неэлегантно. Поэтому я отправляю свое текущее решение в надежде, что: а) он помогает другим и/или б) кто-то может предложить лучшую работу.
Оказалось, что проблема заключается не в том, что Suds генерирует пустые элементы для необязательных элементов (помеченных как Mandatory = No
в WSDL). Но скорее, что Suds генерирует пустые элементы для необязательного комплекса элементов. Например, следующие элементы 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()])
вы можете посмотреть по следующим ссылкам: 1> http://stackoverflow.com/questions/2469988/how-to-pass-soap-headers-into-python-suds-that-are-not -defined-in-wsdl-file 2> http://stackoverflow.com/questions/2964867/add-header-section-to-soap-request-using-soappy. – avasal
Я их видел. Они связаны с добавлением заголовков (если я неправильно понимаю/неправильно читаю), а не заставлять Suds включать префиксы для пространств имен, о которых он знает). – Torid
надеясь, что кто-то может добавить более чистый ответ! – trinth