2012-03-01 11 views
12

Ten plik XML o nazwie example.xml:Python: ElementTree, uzyskać ciąg przestrzeni nazw elementu

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

Gdybym załadować example.xml i analizować je z ElementTree widzę jego nazw jest 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> 

nie znalazłem sposobu, aby zadzwonić, aby uzyskać tylko nazw z Element bez uciekania się do parsowania str(an_element) elementu. Wygląda na to, że musi być lepszy sposób.

+0

Czy wiesz, jak użyć metody wyszukiwania w tym przypadku? to nie działało tutaj ... – caarlos0

Odpowiedz

10

Nie jestem pewien, czy jest to możliwe z xml.etree, ale tutaj jest to, jak można to zrobić z lxml.etree:

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

Otrzymuję 'nierozstrzygnięty import: etree' używając Python 2.7.2 w Windows. 'xpath' nie było dostępne jako metoda przy używaniu' xml.etree' i jeśli używam 'find()' (który obsługuje wyrażenia xpath) '' nazwa-przestrzeni-uri (.) '' instrukcja nadal nie działa. – Deleted

+0

to jest dokładnie to, czego szukałem, [patrz pr na gh] (https://github.com/samatjain/gpxsplitter/pull/3) –

+0

To było najlepsze rozwiązanie, jakie widziałem. Zwykle używam xmlstarlet, ale mogę teraz zmienić. –

1

Myślę, że łatwiej będzie spojrzeć na atrybutach:

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

Z pewnością łatwiejsze niż parsowanie 'str (the_element)'. Ale myślę, że parsowanie 'the_element.tag' jest jeszcze łatwiejsze. Ponieważ interesuje mnie tylko przestrzeń nazw. Co myślisz? – Deleted

+1

Myślę, że odpowiedź @ RikPoggi wydaje się najlepsza (właściwie to ja ją przegłosowałem). W rzeczywistości uzyskanie przestrzeni nazw powinno być tak proste, jak 're.search ('\ {(. *) \}', The_element.tag) .group (1)'. Z moją odpowiedzią wygląda na to, że można użyć 'the_element.attrib.values ​​() [0] .split() [0]', ale w rzeczywistości nie wygląda to tak prosto i nie ma gwarancji, że wygrałeś ' t uzyskać wszelkie inne atrybuty w przyszłości. – jcollado

12

To jest idealne zadanie dla regular expression.

import re 

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

Po krótkiej walce z tym problemem jest to najlepsze rozwiązanie, jakie znalazłem. Nie mogę uwierzyć, że interfejs API nie pozwala ci pytać o przestrzeń nazw, a jednocześnie nie zwraca atrybutu "xmlns" podczas wykonywania "rootElement.keys()". Pewnie, że jest ku temu dobry powód, ale nie mogę go znaleźć w tej chwili. – Robert

5

Bez użycia wyrażeń regularnych:

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

podobna odpowiedź 'root.tag [1: root.tag.index ('}')]' – watashiSHUN

0

element lxml.xtree biblioteki ma słownika nazwie nsmap, który pokazuje wszystkie nazw, które są używane w bieżącym zakresie znacznika.

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

Odpowiedź jest krótka:

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

ale tylko jeśli zostały nazywając

ElementTree.register_namespace(prefix,uri) 

w odpowiedzi na każdy przypadku == "start-NS" otrzymał podczas iteracji przez wynik:

ET.iterparse(...) 

i zarejestrowany „start-ns”

odpowiedź na pytanie: „Jaki jest domyślny obszar nazw?”, Konieczne jest, aby wyjaśnić dwie kwestie:

(1) specyfikacji XML powiedzieć, że domyślny obszar nazw niekoniecznie jest globalny w całym drzewie, a domyślna przestrzeń nazw może zostać ponownie zadeklarowana w dowolnym elemencie w katalogu głównym, i dziedziczy w dół, aż do spełnienia innej domyślnej replikacji obszaru nazw.

(2) Moduł ElementTree może (de facto) obsługiwać dokumenty podobne do XML, które nie mają domyślnej przestrzeni głównej roota, -jeśli w dokumencie nie ma obszaru nazw. (* mogą istnieć mniej surowe warunki, np., to jest "jeśli", a niekoniecznie "iff").

Prawdopodobnie warto również zastanowić się "do czego chcesz?" Rozważmy, że pliki XML mogą być semantycznie równoważne, ale składniowo bardzo różne. Np. Następujące trzy pliki są semantycznie równoważne, ale A.xml ma jedną domyślną deklarację przestrzeni nazw, B.xml ma trzy, a C.xml nie ma.

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> 

Plik C.xml to kanoniczna rozszerzona reprezentacja składniowa prezentowana funkcjom wyszukiwania ElementTree.

Jeżeli jesteś pewien a priori, że nie będzie żadnych kolizji przestrzeni nazw, można zmodyfikować znaczniki elementów podczas parsowania jak omówiono tutaj: Python ElementTree module: How to ignore the namespace of XML files to locate matching element when using the method "find", "findall"

0

łącząc niektóre z powyższych odpowiedzi, myślę najkrótszy kod jest

theroot = tree.getroot() 
theroot.attrib[theroot.keys()[0]] 
Powiązane problemy