2010-11-23 14 views
47

ich eine XML-doc, dass ich mit Etree.lxmllxml etree XMLParser unerwünschte Namespace entfernen

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

Mein Code zu analysieren versuche ist:

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

Wenn ich versuche, dom.getroot zu bekommen() ich bekomme:

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

jedoch nur ich will:

<Element Envelope at 28adacac> 

Wenn ich tun

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

ich nichts zurückgegeben. Wenn ich jedoch

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

bin, bekomme ich ein Ergebnis.

Ich dachte, dass die Übergabe von ns_clean = True an den Parser dies verhindern würde.

Irgendwelche Ideen?

Antwort

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

Sie Namespace-aware Knoten mit der xpath Methode finden :

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>] 

Wenn Sie Namespaces wirklich entfernen möchten, Sie eine XSL-Transformation verwenden könnte:

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

Hier sehen wir den Namensraum entfernt wurde:

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

So können Sie nun den Datenknoten auf diese Weise finden:

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

body = dom.xpath ('// ns: Körper', namespaces = {'ns': 'http: //www.xxx.com/zzz/yyy'}) PERFEKT! – Mark

+9

XSLT, um alle Namespaces zu entfernen. Genau das, wonach ich gesucht habe, Genie. –

+0

FYI wenn Sie Python3 benutzen, müssen Sie den xslt String zuerst kodieren. dh xslt_doc = ET.parse (io.BytesIO (str.encode (xslt))) – AZhao

-1

Sie zeigen das Ergebnis des Aufrufs repr() an. Wenn Sie sich programmgesteuert durch die Struktur bewegen, können Sie den Namespace einfach ignorieren.

+4

nein, wenn ich es tue - dom.getroot(). Find ("Body") - Ich bekomme überhaupt kein Ergebnis. Die einzige Möglichkeit, das Element zu erhalten, ist - dom.getroot() .find ('{http://www.xxx.com/zzz/yyy} Body') – Mark

24

Versuchen XPath:

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

genommen (und vereinfacht) von this page unter "XPath() Methode" Abschnitt

+0

Dies ist die beste Lösung. Bis abstimmen! – vangheem

3

Die letzte Lösung von https://bitbucket.org/olauzanne/pyquery/issue/17 kann Ihnen helfen, Namespaces mit wenig Aufwand zu vermeiden

xml.replace(' xmlns:', ' xmlnamespace:') auf Ihre xml anwenden, bevor pyquery mit so lxml Namespaces In Ihrem Fall

ignorieren, versuchen xml.replace(' xmlns="', ' xmlnamespace="'). Möglicherweise benötigen Sie jedoch etwas Komplexeres, wenn die Zeichenfolge auch in den Körpern erwartet wird.

+2

Das ist erstaunlich. Du hast mein Leben verändert, danke. (ps, wer auch immer XML namespaces, wtf?) –

+11

String Munging ist immer der Weg zum Wahnsinn. Im allgemeinen Fall ist diese Antwort absolut falsch. Angenommen, Sie formatieren einen RSS-Feed dieser genauen Frage - das Ergebnis würde den Leuten sagen: 'xml.replace (' xmlnamespace = '', 'xmlnamespace =' ') '... – bukzor

Verwandte Themen