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?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top