Eu tenho o seguinte XML que eu quero analisar usando Python ElementTree
:
<rdf:RDF xml:base="http://dbpedia.org/ontology/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:owl="http://www.w3.org/2002/07/owl#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns="http://dbpedia.org/ontology/">
<owl:Class rdf:about="http://dbpedia.org/ontology/BasketballLeague">
<rdfs:label xml:lang="en">basketball league</rdfs:label>
<rdfs:comment xml:lang="en">
a group of sports teams that compete against each other
in Basketball
</rdfs:comment>
</owl:Class>
</rdf:RDF>
Quero encontrar todas as owl:Class
tags e extrair o valor de todas as rdfs:label
instâncias dentro delas. Estou usando o seguinte código:
tree = ET.parse("filename")
root = tree.getroot()
root.findall('owl:Class')
Por causa do espaço para nome, estou recebendo o seguinte erro.
SyntaxError: prefix 'owl' not found in prefix map
Tentei ler o documento em http://effbot.org/zone/element-namespaces.htm, mas ainda não consigo fazer isso funcionar, pois o XML acima tem vários namespaces aninhados.
Por favor, deixe-me saber como alterar o código para encontrar todas as owl:Class
tags.
xmlns
atributos; como indicado na resposta,lxml
faz isso por você, oxml.etree.ElementTree
módulo não. Mas se você está tentando corresponder a um elemento específico (já codificado), também está tentando corresponder a um elemento específico em um espaço para nome específico. Esse espaço para nome não será alterado entre os documentos mais do que o nome do elemento. Você também pode codificar isso com o nome do elemento.register_namespace
apenas influencia a serialização, não a pesquisa.cElementTree
vez deElementTree
,findall
não usará espaços para nome como argumento de palavra-chave, mas simplesmente como argumento normal, ou seja, usectree.findall('owl:Class', namespaces)
.findall
sem e depois com onamespace
argumento, mas o argumento não é mencionado como um dos argumentos para o método method na seção Objeto Elemento .Veja como fazer isso com o lxml sem precisar codificar os namespaces ou digitalizar o texto para eles (como Martijn Pieters menciona):
ATUALIZAÇÃO :
Cinco anos depois, ainda estou enfrentando variações desse problema. O lxml ajuda como mostrei acima, mas não em todos os casos. Os comentaristas podem ter um ponto válido em relação a essa técnica quando se trata de mesclar documentos, mas acho que a maioria das pessoas está tendo dificuldade em simplesmente pesquisar documentos.
Aqui está outro caso e como eu lidei com isso:
xmlns sem prefixo significa que tags não prefixadas obtêm esse espaço de nome padrão. Isso significa que, ao procurar o Tag2, é necessário incluir o espaço para nome para encontrá-lo. No entanto, o lxml cria uma entrada nsmap com None como chave e não consegui encontrar uma maneira de procurá-la. Então, eu criei um novo dicionário de namespace como este
fonte
owl
) pode mudar de arquivo para arquivo. Portanto, fazer o que essa resposta sugere é uma péssima idéia.Nota : Esta é uma resposta útil para a biblioteca padrão ElementTree do Python sem usar espaços para nome codificados.
Para extrair prefixos e URI do espaço para nome dos dados XML, você pode usar a
ElementTree.iterparse
função, analisando apenas os eventos start do espaço para nome ( start-ns ):Em seguida, o dicionário pode ser passado como argumento para as funções de pesquisa:
fonte
ValueError: write to closed
para esta linhafilemy_namespaces = dict([node for _, node in ET.iterparse(StringIO(my_schema), events=['start-ns'])])
. Alguma idéia quer errado?dict([...])
você também pode usar a compreensão do ditado.StringIO(my_schema)
você também pode colocar o nome do arquivo XML.Eu tenho usado um código semelhante a este e descobri que sempre vale a pena ler a documentação ... como sempre!
findall () encontrará apenas elementos que são filhos diretos da tag atual . Então, não é realmente tudo.
Pode valer a pena tentar fazer com que seu código funcione com o seguinte, especialmente se você estiver lidando com arquivos xml grandes e complexos, para que os subelementos (etc.) também sejam incluídos. Se você se conhece onde estão os elementos no seu xml, acho que tudo ficará bem! Apenas pensei que valia a pena lembrar.
ref: https://docs.python.org/3/library/xml.etree.elementtree.html#finding-interesting-elements "Element.findall () encontra apenas elementos com uma tag que são filhos diretos do elemento atual. Element.find () localiza o primeiro filho com uma tag específica e Element.text acessa o conteúdo de texto do elemento. Element.get () acessa os atributos do elemento: "
fonte
Para obter o espaço para nome em seu formato, por exemplo
{myNameSpace}
, você pode fazer o seguinte:Dessa forma, você pode usá-lo posteriormente em seu código para encontrar nós, por exemplo, usando interpolação de strings (Python 3).
fonte
Minha solução é baseada no comentário de @Martijn Pieters:
Portanto, o truque aqui é usar dicionários diferentes para serialização e pesquisa.
Agora, registre todos os namespaces para análise e gravação:
Para pesquisar (
find()
,findall()
,iterfind()
) precisamos de um prefixo não vazio. Passe essas funções para um dicionário modificado (aqui modifico o dicionário original, mas isso só deve ser feito após o registro dos namespaces).Agora, as funções da
find()
família podem ser usadas com odefault
prefixo:mas
não usa nenhum prefixo para elementos no espaço para nome padrão.
fonte