ElementTree XPath - Selecionar Elemento baseado em atributo
-
03-07-2019 - |
Pergunta
Estou tendo problemas usando o atributo Selector XPath em ElementTree, que eu deveria ser capaz de fazer de acordo com o Documentação
Aqui está um código de exemplo
XML
<root>
<target name="1">
<a></a>
<b></b>
</target>
<target name="2">
<a></a>
<b></b>
</target>
</root>
Python
def parse(document):
root = et.parse(document)
for target in root.findall("//target[@name='a']"):
print target._children
Estou recebendo a seguinte exceção:
expected path separator ([)
Solução
A sintaxe que você está tentando usar é novo no ElementTree 1,3 .
Tal versão é fornecido com o Python 2.7 ou superior. Se você tiver Python 2.6 ou menos você ainda tem ElementTree 1.2.6 ou menos.
Outras dicas
Existem vários problemas neste código.
-
O Python buildin ElementTree (ET para o short) não tem qualquer apoio real XPATH; apenas um subconjunto limitado por exemplo, ele não suporta encontrar-da-raiz expressões como
//target
.Aviso: documentação menciona " // ", mas apenas para as crianças: Então uma expressão como
.//target
é válido;//...
não é!Há uma implementação alternativa: lxml que é mais rica. É costuras que a documentação é usada, para o build-in de código. Que não corresponde / trabalho.
-
O
@name
notação selecciona em XMLatributos ; a expressãokey=value
dentro de um xml-tag.Assim que o nome de valor tem de ser 1 ou 2 para selecionar algo no documento dado. Ou, pode-se procurar alvos com uma criança elemento 'a' :.
target[a]
(sem @)
Para o documento dado, analisado com o build-in ElementTree (v1.3) para a raiz, o seguinte código está correto e funcionando:
-
root.findall(".//target")
Localizar ambas as metas -
root.findall(".//target/a")
encontrar dois um elemento -
root.findall(".//target[a]")
isto encontra tanto elemento alvo novamente, já que ambos têm um um-elemento -
root.findall(".//target[@name='1']")
Encontrar apenas o início alvo. Note as aspas em torno de 1 são necessários; então um SyntaxError é levantada -
root.findall(".//target[a][@name='1']")
também válido; para encontrar esse alvo -
root.findall(".//target[@name='1']/a")
Encontra apenas um elemento-; ...