2010-11-23 15 views
47

Tengo un documento XML que estoy tratando de analizar el uso de Etree.lxmllxml etree XMLParser quitar espacio de nombres no deseada

<Envelope xmlns="http://www.example.com/zzz/yyy"> 
    <Header> 
    <Version>1</Version> 
    </Header> 
    <Body> 
    some stuff 
    <Body> 
<Envelope> 

Mi código es:

path = "path to xml file" 
from lxml import etree as ET 
parser = ET.XMLParser(ns_clean=True) 
dom = ET.parse(path, parser) 
dom.getroot() 

cuando trato de conseguir dom.getroot() me sale:

<Element {http://www.example.com/zzz/yyy}Envelope at 28adacac> 

Sin embargo sólo quiero:

<Element Envelope at 28adacac> 

cuando lo haga

dom.getroot().find("Body") 

me sale nada volvió. Sin embargo, cuando yo

dom.getroot().find("{http://www.example.com/zzz/yyy}Body") 

obtengo un resultado.

Pensé que pasar ns_clean = Verdadero para el analizador evitaría esto.

¿Alguna idea?

Respuesta

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

puede encontrar nodos espacio de nombres consciente utilizando el método 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>] 

Si realmente desea eliminar espacios de nombres, podría usar una transformación 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) 

Aquí vemos el espacio de nombres se ha eliminado:

print(ET.tostring(dom)) 
# <Envelope> 
# <Header> 
#  <Version>1</Version> 
# </Header> 
# <Body> 
#  some stuff 
# </Body> 
# </Envelope> 

Así que ahora se puede encontrar el nodo cuerpo de esta manera:

print(dom.find("Body")) 
# <Element Body at 8506cd4> 
+0

body = dom.xpath ('// ns: Body', namespaces = {'ns': 'http: //www.xxx.com/zzz/yyy'}) ¡PERFECTO! – Mark

+9

XSLT para eliminar todos los espacios de nombres. Justo lo que estaba buscando, genio. –

+0

FYI si usa Python3 primero tendrá que codificar la cadena xslt. es decir, xslt_doc = ET.parse (io.BytesIO (str.encode (xslt))) – AZhao

-1

Está mostrando el resultado de la llamada a repr(). Cuando se mueve programáticamente a través del árbol, simplemente puede optar por ignorar el espacio de nombres.

+4

no, Cuando lo hago - dom.getroot(). Find ("Cuerpo") - No obtengo ningún resultado. La única forma en que puedo obtener el elemento es - dom.getroot() .find ('{http://www.xxx.com/zzz/yyy} Body') – Mark

24

Trate de usar Xpath:

dom.xpath("//*[local-name() = 'Body']") 

Tomado (y simplificado) de this page, en "El XPath() método de" sección

+0

Esta es la mejor solución. ¡Vota arriba! – vangheem

3

La última solución desde https://bitbucket.org/olauzanne/pyquery/issue/17 puede ayudarle a evitar espacios de nombres con poco esfuerzo

se aplican a su xml.replace(' xmlns:', ' xmlnamespace:') XML antes de usar por lo pyquery lxml ignorará espacios de nombres

En su caso, tratar xml.replace(' xmlns="', ' xmlnamespace="'). Sin embargo, es posible que necesite algo más complejo si también se espera la secuencia en los cuerpos.

+2

Esto es increíble. Has cambiado mi vida, gracias. (ps, quien diseñó espacios de nombres XML, wtf?) –

+11

String munging es siempre el camino a la locura. En el caso general, esta respuesta está completamente equivocada. Supongamos que está formateando un feed rss de esta pregunta exacta: el resultado indicaría a la gente 'xml.replace ('xmlnamespace ="', 'xmlnamespace = "')' ... – bukzor

Cuestiones relacionadas