Suds gera elementos vazios; como removê-los?

[Edição principal com base na experiência desde o 1º post, há dois dias.]

Estou construindo um script SOAP / XML Python usando Suds, mas estou tendo dificuldades para obter o código para gerar SOAP / XML aceitável para o servidor. Eu pensava que o problema era que o Suds não estava gerando prefixos para elementos internos, mas subseqüentemente acontece que a falta de prefixos (consulteSh-Data e elementos internos) não é um problema, pois oSh-Data eMetaSwitchDatas elementos @ declaram os namespaces apropriados (veja abaixo

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

Mas isso ainda falha. A questão é que o Suds gera elementos vazios para elementos opcionais (marcados comoMandatory = No no WSDL). Mas o servidor exige que um elemento opcional esteja presente com um valor sensível ou ausente e recebo o seguinte erro (porque o<CallFeatureServerControlStatus/> elemento @ não é um dos valores permitido

Os dados do usuário fornecidos não foram validados no esquema XML do MetaSwitch para dados do usuári
Details: cvc-enumeration-valid: Value '' não é válido para facetas com relação à enumeração '[Controlando, Abandonado, Cautelosamente Controlando]'. Deve ser um valor da enumeração.

Se eu pegar o SOAP / XML gerado no SOAPUI e excluir os elementos vazios, a solicitação funcionará perfeitament

Existe uma maneira de fazer o Suds não gerar elementos vazios para campos opcionais ou removê-los no código posteriorment

Major Update

Resolvi esse problema (que já vi em outros lugares), mas de uma maneira bastante deselegante. Portanto, estou postando minha solução atual na esperança de que a) ajude outras pessoas e / ou b) alguém possa sugerir uma solução alternativa melho

Acontece que o problema não era que Suds gera elementos vazios para elementos opcionais (marcados comoMandatory = No no WSDL). Mas sim que Suds gera elementos vazios para @ opcioncomplex elementos. Por exemplo, os seguintes elementos Meta_SubG_BaseInformation são elementos simples e o Suds não gera nada para eles no SOAP / XM

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

Em contraste, o seguinte elemento Meta_SubG_BaseInformation é um elemento complexo e, mesmo quando opcional e meu código não atribui um valor a ele, ele acaba no SOAP / XML gerado.

<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 gera o seguinte para ProviderStatus que (como mencionado acima) perturba meu servido

<ProviderStatus/>

A solução alternativa é definir todos osMeta_SubG_BaseInformation elementos paraNone depois de criar o elemento pai e antes de atribuir valores, como a seguir. Isso é supérfluo para os elementos simples, mas garante que elementos complexos não atribuídos não resultem em SOAP / XML gerad

subGatewayBaseInformation = client.factory.create('ns1:Meta_SubG_BaseInformation')
for (el) in subGatewayBaseInformation:
  subGatewayBaseInformation.__setitem__(el[0], None)
subGatewayBaseInformation._Action            = 'apply'
subGatewayBaseInformation.NetworkElementName = 'Meribel'
etc...

Isso resulta no Suds gerando SOAP / XML sem elementos vazios, o que é aceitável para o meu servido

Mas alguém conhece uma maneira mais limpa de obter o mesmo efeit

solução abaixo é baseada em respostas / comentários de dusan e Roland Smith abaix

Esta solução usa um Suds MessagePlugin para remover XML "vazio" do formulário<SubscriberType/> antes de Suds colocar a solicitação no arame. Precisamos apenas remover ShUpdates (onde estamos atualizando dados no servidor), e a lógica (especialmente a indexação nos filhos para obter a lista de elementos de indicação de serviço) é muito específica para o WSDL. Não funcionaria para WSDL diferente.

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)

E só precisamos fazer referência ao plug-in quando criamos o client

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