lxml eTree xmlparser remove namespace indesiderati
-
27-09-2019 - |
Domanda
Ho un documento XML che sto cercando di analizzare utilizzando Etree.lxml
<Envelope xmlns="http://www.example.com/zzz/yyy">
<Header>
<Version>1</Version>
</Header>
<Body>
some stuff
<Body>
<Envelope>
Il mio codice è:
path = "path to xml file"
from lxml import etree as ET
parser = ET.XMLParser(ns_clean=True)
dom = ET.parse(path, parser)
dom.getroot()
Quando provo ad ottenere dom.getroot () ottengo:
<Element {http://www.example.com/zzz/yyy}Envelope at 28adacac>
Comunque io voglio solo:
<Element Envelope at 28adacac>
Quando faccio
dom.getroot().find("Body")
non ottengo niente restituito. Tuttavia, quando ho
dom.getroot().find("{http://www.example.com/zzz/yyy}Body")
ho un risultato.
Ho pensato che passa ns_clean = True al parser impedirebbe questo.
Tutte le idee?
Soluzione
import io
import lxml.etree as ET
content='''\
<Envelope xmlns="http://www.example.com/zzz/yyy">
<Header>
<Version>1</Version>
</Header>
<Body>
some stuff
</Body>
</Envelope>
'''
dom = ET.parse(io.BytesIO(content))
Si possono trovare i nodi namespace-aware usando il metodo xpath
:
body=dom.xpath('//ns:Body',namespaces={'ns':'http://www.example.com/zzz/yyy'})
print(body)
# [<Element {http://www.example.com/zzz/yyy}Body at 90b2d4c>]
Se si vuole veramente rimuovere gli spazi dei nomi, è possibile utilizzare una trasformazione XSL:
# http://wiki.tei-c.org/index.php/Remove-Namespaces.xsl
xslt='''<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="no"/>
<xsl:template match="/|comment()|processing-instruction()">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
'''
xslt_doc=ET.parse(io.BytesIO(xslt))
transform=ET.XSLT(xslt_doc)
dom=transform(dom)
Qui vediamo lo spazio dei nomi è stata rimossa:
print(ET.tostring(dom))
# <Envelope>
# <Header>
# <Version>1</Version>
# </Header>
# <Body>
# some stuff
# </Body>
# </Envelope>
Così ora è possibile trovare il corpo del nodo in questo modo:
print(dom.find("Body"))
# <Element Body at 8506cd4>
Altri suggerimenti
Prova a usare XPath:
dom.xpath("//*[local-name() = 'Body']")
Taken (e semplificato) da questa pagina , in "The XPath () il metodo" sezione
L'ultima soluzione da https://bitbucket.org/olauzanne/pyquery/issue/17 può aiutare a evitare gli spazi dei nomi con poco sforzo
invia candidatura
xml.replace(' xmlns:', ' xmlnamespace:')
al tuo xml prima di utilizzare in modo pyquery lxml ignorerà gli spazi dei nomi
Nel tuo caso, prova a xml.replace(' xmlns="', ' xmlnamespace="')
. Tuttavia, potrebbe essere necessario qualcosa di più complesso se la stringa è previsto nei corpi come bene.
si sta mostrando il risultato della chiamata repr (). Quando si sposta di programmazione tramite l'albero, si può semplicemente scegliere di ignorare lo spazio dei nomi.