2012-03-01 1 views
12

Этот файл XML с именем example.xml:Python: ElementTree, получить строку пространства имен элемента

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

Если я загружаю example.xml и разобрать его с ElementTree я могу видеть его пространство имен 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> 

Я не нашел способ, чтобы позвонить, чтобы получить только пространство имен из Element, не прибегая к разбору str(an_element) элемента. Похоже, что должен быть лучший способ.

+0

Вы знаете, как использовать метод find в этом случае? он не работал здесь ... – caarlos0

ответ

10

Я не уверен, если это возможно с xml.etree, но вот как вы могли бы сделать это с lxml.etree:

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

Я получаю 'unresolved import: etree', используя Python 2.7.2 в Windows. 'xpath' не был доступен как метод при использовании' xml.etree', и если я использую 'find()' (который поддерживает выражения xpath), оператор '' namespace-uri (.) ''все еще не работает. – Deleted

+0

это именно то, что я искал, [см. Pr на gh] (https://github.com/samatjain/gpxsplitter/pull/3) –

+0

Это было лучшее решение, которое я видел. Обычно я использую xmlstarlet, но теперь могу переключиться. –

1

Я думаю, что это будет легче взглянуть на атрибуты:

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

Конечно, проще, чем синтаксический анализ 'str (the_element)'. Но я думаю, что разбор 'the_element.tag' даже немного проще. Поскольку меня интересует только пространство имен. Как вы думаете? – Deleted

+1

Я думаю, что ответ @ RikPoggi кажется лучшим (на самом деле, я его поддержал). Фактически, получение пространства имен должно быть таким же простым, как 're.search ('\ {(. *) \}', The_element.tag) .группа (1)'. С моим ответом вы можете использовать 'the_element.attrib.values ​​() [0] .split() [0]', но, действительно, это выглядит не так просто, и не гарантируется, что вы выиграли ' t получить любые другие атрибуты в будущем. – jcollado

17

Пространство имен должно быть в Element.tag непосредственно перед "реальной" метки:

>>> root = tree.getroot() 
>>> root.tag 
'{http://maven.apache.org/POM/4.0.0}project' 

Чтобы узнать больше об пространствах имен, взгляните на ElementTree: Working with Namespaces and Qualified Names.

12

Это идеальная задача для regular expression.

import re 

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

После долгого боя с этим вопросом это лучшее решение, которое я нашел. Я не могу поверить, что API не дает вам способ спросить пространство имен и в то же время не возвращает атрибут «xmlns» при выполнении «rootElement.keys()». Конечно, для этого есть веская причина, но я не могу найти ее в этот момент. – Robert

5

без использования регулярных выражений:

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

аналогичный ответ 'root.tag [1: root.tag.index ('}')]' – watashiSHUN

0

Элемента lxml.xtree библиотеки есть словарь под названием nsmap, который показывает все пространство имен, которые используются в текущей области тегов.

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

Короткий ответ:

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

, но только если вы звонили

ElementTree.register_namespace(prefix,uri) 

в ответ на каждый события == "старт-нс" получил в то время как итерация в результате

ET.iterparse(...) 

и вы зарегистрировались на «старт-нс»

ответить на вопрос «что такое пространство имен по умолчанию?», То необходимо уточнить два момента:

(1) спецификации XML говорят, что пространство имен по умолчанию не обязательно является глобальным по всему дереву, а пространство имен по умолчанию может быть повторно объявлено любым элементом под root и наследуется вниз, пока не будет повторено повторное объявление другого пространства имен по умолчанию.

(2) Модуль ElementTree может (де-факто) обрабатывать XML-подобные документы, которые не имеют корневого пространства имен по умолчанию, -если они не используют пространство имен в любом месте документа. (* могут быть менее строгие условия, например., то есть «если» и не обязательно «iff»).

Возможно, стоит также подумать о том, для чего вы хотите? Учтите, что XML-файлы могут быть семантически эквивалентными, но синтаксически очень разными. Например, следующие три файла семантически эквивалентны, но у A.xml есть одно объявление пространства имен по умолчанию, B.xml имеет три, а C.xml - нет.

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> 

Файл C.xml - это каноническое расширенное синтаксическое представление, представленное в функции поиска ElementTree.

Если вы уверены, априори, что не будет пространства имен столкновений, вы можете изменять тег элементов при разборе, как описано здесь: Python ElementTree module: How to ignore the namespace of XML files to locate matching element when using the method "find", "findall"

0

объединения некоторых из вышеперечисленных ответов, я думаю, что самый короткий код

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