2012-03-01 8 views
12

Questo file XML è denominato example.xml:Python: elementtree, ottiene la stringa spazio dei nomi di un elemento

<?xml version="1.0"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 

    <modelVersion>14.0.0</modelVersion> 
    <groupId>.com.foobar.flubber</groupId> 
    <artifactId>uberportalconf</artifactId> 
    <version>13-SNAPSHOT</version> 
    <packaging>pom</packaging> 
    <name>Environment for UberPortalConf</name> 
    <description>This is the description</description>  
    <properties> 
     <birduberportal.version>11</birduberportal.version> 
     <promotiondevice.version>9</promotiondevice.version> 
     <foobarportal.version>6</foobarportal.version> 
     <eventuberdevice.version>2</eventuberdevice.version> 
    </properties> 
    <!-- A lot more here, but as it is irrelevant for the problem I have removed it --> 
</project> 

Se carico example.xml e analizzare con ElementTree posso vedere il suo spazio dei nomi è http://maven.apache.org/POM/4.0.0.

>>> from xml.etree import ElementTree 
>>> tree = ElementTree.parse('example.xml') 
>>> print tree.getroot() 
<Element '{http://maven.apache.org/POM/4.0.0}project' at 0x26ee0f0> 

non ho trovato un metodo da chiamare per ottenere solo lo spazio dei nomi da un Element senza ricorrere alla analisi del str(an_element) di un elemento. Sembra che ci debba essere un modo migliore.

+0

sai come utilizzare il metodo di ricerca in questo caso? non ha funzionato qui ... – caarlos0

risposta

10

io non sono sicuro se questo è possibile con xml.etree, ma ecco come si potrebbe fare con lxml.etree:

>>> from lxml import etree 
>>> tree = etree.parse('example.xml') 
>>> tree.xpath('namespace-uri(.)') 
'http://maven.apache.org/POM/4.0.0' 
+1

Ottengo "importazione non risolta: etree" utilizzando Python 2.7.2 in Windows. 'xpath' non era disponibile come metodo quando si utilizza' xml.etree' e se si usa 'find()' (che supporta espressioni xpath) l'istruzione '' namespace-uri (.) ''non funziona ancora. – Deleted

+0

questo è esattamente quello che stavo cercando, [vedi pr on gh] (https://github.com/samatjain/gpxsplitter/pull/3) –

+0

Questa è stata la soluzione migliore che ho visto. Di solito uso xmlstarlet ma potrei passare ora. –

1

penso che sarà più facile dare un'occhiata agli attributi:

>>> root.attrib 
{'{http://www.w3.org/2001/XMLSchema-instance}schemaLocation': 
    'http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd'} 
+0

Certamente più semplice dell'analisi di 'str (the_element)'. Ma credo che l'analisi di "the_element.tag" sia anche un po 'più semplice. Dato che sono interessato solo al namespace. Cosa ne pensi? – Deleted

+1

Penso che la risposta di @RikPoggi sia la migliore (in realtà, l'ho svalutata). In effetti, ottenere lo spazio dei nomi dovrebbe essere facile come 're.search ('\ {(. *) \}', The_element.tag) .group (1)'. Con la mia risposta sembra che tu possa usare 'the_element.attrib.values ​​() [0] .split() [0]', ma, in effetti, non sembra così semplice e non è garantito che tu abbia vinto ' t ottenere altri attributi in futuro. – jcollado

12

Questo è un compito perfetto per un regular expression.

import re 

def namespace(element): 
    m = re.match('\{.*\}', element.tag) 
    return m.group(0) if m else '' 
+7

Dopo aver combattuto per un po 'con questo problema, questa è la soluzione migliore che ho trovato. Non posso credere che l'API non ti dia il modo di chiedere lo spazio dei nomi e, allo stesso tempo, non restituisca l'attributo 'xmlns' quando si esegue 'rootElement.keys()'. Certo, c'è una buona ragione per questo, ma non riesco a trovarlo in questo momento. – Robert

5

Senza usare le espressioni regolari:

>>> root 
<Element '{http://www.google.com/schemas/sitemap/0.84}urlset' at 0x2f7cc10> 

>>> root.tag.split('}')[0].strip('{') 
'http://www.google.com/schemas/sitemap/0.84' 
+0

una risposta simile 'root.tag [1: root.tag.index ('}')]' – watashiSHUN

0

elemento della biblioteca lxml.xtree ha un dizionario chiamato nsmap, che mostra tutto lo spazio dei nomi che sono in uso in ambito tag corrente.

>>> item = tree.getroot().iter().next() 
>>> item.nsmap 
{'md': 'urn:oasis:names:tc:SAML:2.0:metadata'} 
0

La risposta breve è:

ElementTree._namspace_map[ElementTree._namspace_map.values().index('')] 

ma solo se v'è stato chiamando

ElementTree.register_namespace(prefix,uri) 

in risposta ad ogni evento == "start-ns" ricevuti mentre l'iterazione attraverso il risultato di

ET.iterparse(...) 

e ti sei registrato per "start-ns"

La rispondere alla domanda "qual è il namespace di default?", È necessario chiarire due punti:

(1) specifiche XML dicono che lo spazio dei nomi predefinito non è necessariamente globale in tutto l'albero, piuttosto lo spazio dei nomi predefinito può essere dichiarato nuovamente in qualsiasi elemento della directory principale e viene ereditato verso il basso fino a incontrare un'altra nuova dichiarazione dello spazio dei nomi predefinita.

(2) Il modulo ElementTree può (di fatto) gestire documenti di tipo XML che non hanno uno spazio dei nomi predefinito di root, -se non hanno alcun spazio dei nomi utilizzato in nessuna parte del documento. (* potrebbero esserci condizioni meno rigide, ad es., che è "se" e non necessariamente "iff").

Probabilmente vale anche la pena considerare "per cosa lo vuoi?" Considera che i file XML possono essere equivalenti semanticamente, ma sintatticamente molto diversi. Ad esempio, i tre file seguenti sono equivalenti semanticamente, ma A.xml ha una dichiarazione dello spazio dei nomi predefinita, B.xml ne ha tre e C.xml non ne ha.

A.xml: 
<a xlmns="http://A" xlmns:nsB0="http://B0" xlmns:nsB1="http://B1"> 
    <nsB0:b/> 
    <nsB1:b/> 
</a> 

B.xml: 
<a xlmns="http://A"> 
    <b xlmns="http://B0"/> 
    <b xlmns="http://B1"/> 
</a> 

C.xml: 
<{http://A}a> 
    <{http://B0}b/> 
    <{http://B1}b/> 
</a> 

Il file C.xml è la rappresentazione sintattica espansa canonica presentata alle funzioni di ricerca ElementTree.

Se si è certi a priori che non ci saranno collisioni namespace, è possibile modificare i tag degli elementi durante l'analisi come discusso qui: Python ElementTree module: How to ignore the namespace of XML files to locate matching element when using the method "find", "findall"

0

che unisce alcune delle risposte di cui sopra, credo che il codice più breve è

theroot = tree.getroot() 
theroot.attrib[theroot.keys()[0]] 
Problemi correlati