Como analiso e escrevo XML usando o ElementTree do Python sem mover espaços de nome?
Nosso projeto obtém do XML upstream deste formulário:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="7.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<appSettings>
<add key="foo" value="default">
...
</appSettings>
</configuration>
Em seguida, ele lê / analisa esse XML usando o ElementTree e, para cada configuração de aplicativo que corresponde a uma determinada chave ("foo"), grava um novo valor queisto sabe que o processo upstream não funciona (nesse caso, a chave "foo" deve ter o valor "bar").
oRio abaixo processo consumindo o XML filtrado é, aaahhhh ...frágil. Ele espera receber o XML emexatamente o formulário acima.
Se eu analisar esse XML sem registrar um espaço para nome, o ElementTree manipulará minha árvore como esta na entrada:
<configuration xmlns:ns0="urn:schemas-microsoft-com:asm.v1">
<runtime>
<ns0:assemblyBinding>
<ns0:dependentAssembly>
<ns0:assemblyIdentity culture="neutral" name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" />
<ns0:bindingRedirect newVersion="7.0.0.0" oldVersion="0.0.0.0-6.0.0.0" />
</ns0:dependentAssembly>
</ns0:assemblyBinding>
</runtime>
<appSettings>
<add key="foo" value="default">
...
</appSettings>
</configuration>
O processo a jusante não pode lidar com isso, porque não é inteligente o suficiente para perceber que, semanticamente, isso é a mesma coisa. Então, decido registrar o espaço para nome que sei que o processo upstream fornecerá como espaço para nome padrão para evitar que os prefixos apareçam em todos os lugares e agora entendi:
<configuration xmlns="urn:schemas-microsoft-com:asm.v1">
<runtime>
<assemblyBinding>
<dependentAssembly>
<assemblyIdentity culture="neutral" name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" />
<bindingRedirect newVersion="7.0.0.0" oldVersion="0.0.0.0-6.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<appSettings>
<add key="foo" value="default">
...
</appSettings>
</configuration>
Eu não sei muito sobre XML, mas esse também o componente downstream chora, e parece-me que agora não significa esse padrãoxmlns
agora aplique atudo elementos incluídos dentro<configuration>
, enquanto que antessó aplicado ao<assemblyBinding>
elemento?
Existe alguma maneira,usando ElementTree, para manipular esse espaço de nome para que eu possa absorver o XML do upstream, definafoo
é o valor e, em seguida, passa-o a jusante, sem mover o espaço para nome e deixá-lo exatamente como o encontrei?
Eu poderia usar uma solução baseada em lxml, que parece lidar com isso,Contudo, lxml depende de C, que o componente downstream realmente gostaria de não ter suporte: é preferível uma solução Python pura.
Eu poderia ler o documento como HTML, o que ignoraria o atributo de espaço para nome, deixe-me manipular o valor desejado e depois passar o documento;Contudo, Ainda não encontrei um analisador Python que não faça o downcase de todos os nomes de elementos, e meu componente downstream exige que a cobertura de todos os nomes de elementos seja preservada.
Eu poderia recorrer à análise de strings e a expressões regulares. Prefiro não escrever meu próprio analisador.
O único conselho que pude encontrar até agora sobre o tratamento de namespace no ElementTree sugere a abordagem "registrar um namespace padrão para evitar prefixos", que eu supunha que seria adequado, mas o ElementTree insiste em mover oxmlns
declaração até o nó raiz após o dumping.
Eu também poderia ser inteligente construindo uma corda que despeja a árvore em estágios e na ordem exata para colocar oxmlns
declaração de volta no "nó direito", mas isso me parece também muito frágil.
Alguém conseguiu superar um problema como este?