56 votes

problème d'espace de noms lxml etree xmlparser

J'ai un document xml que je suis en train de les analyser à l'aide du programme etree.lxml

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

Mon code est:

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

Lorsque j'essaie d'obtenir des dom.getroot() j'obtiens:

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

Cependant je ne le veux:

<Element Envelope at 28adacac>

Quand je fais

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

Je ne reçois rien retourné. Cependant, quand je

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

Je obtenir un résultat.

Je pensais passer ns_clean=True à l'analyseur permettrait d'éviter cela.

Des idées?

59voto

unutbu Points 222216
 import io
import lxml.etree as ET

content='''\
<Envelope xmlns="http://www.xxx.com/zzz/yyy">
  <Header>
    <Version>1</Version>
  </Header>
  <Body>
    some stuff
  </Body>
</Envelope>
'''    
dom = ET.parse(io.BytesIO(content))
 

Vous pouvez rechercher des nœuds prenant en compte les espaces de noms à l'aide de la méthode xpath :

 body=dom.xpath('//ns:Body',namespaces={'ns':'http://www.xxx.com/zzz/yyy'})
print(body)
# [<Element {http://www.xxx.com/zzz/yyy}Body at 90b2d4c>]
 

Si vous voulez vraiment supprimer les espaces de noms, vous pouvez utiliser une transformation 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)
 

Nous voyons ici que l'espace de noms a été supprimé:

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

Donc, vous pouvez maintenant trouver le nœud Body de cette façon:

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

34voto

dusan Points 3778

Essayez d'utiliser Xpath:

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

Extrait (et simplifié) de cette page , dans la section "La méthode xpath ()"

5voto

Andrei Points 3689

La dernière solution de https://bitbucket.org/olauzanne/pyquery/issue/17 peut vous aider à éviter les espaces de noms facilement.

applique xml.replace(' xmlns:', ' xmlnamespace:') à votre xml avant d'utiliser pyquery afin que lxml ignore les espaces de noms

Dans votre cas, essayez xml.replace(' xmlns="', ' xmlnamespace="') . Cependant, vous aurez peut-être besoin de quelque chose de plus complexe si la chaîne est également attendue dans les corps.

-4voto

robert Points 10493

Vous affichez le résultat de l'appel repr (). Lorsque vous vous déplacez par programme dans l'arborescence, vous pouvez simplement choisir d'ignorer l'espace de noms.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X