2016-07-21 2 views
1

Я пытаюсь проанализировать XML-файл, используя lxml.lxml - По умолчанию пространства имен

my_tree = etree.parse(file) 
my_root = my_tree.getroot() 

for child in my_root: 
    print(child.tag) 

# {some default namespace}Prop 
# {some default namespace}Prop 
# {some default namespace}Stuff 
# ... 

В идеале, я просто хочу, чтобы все элементы, которые я хочу что-то вроде

my_root.findall('Prop', my_root.nsmap) 

, но это возвращает пустой список. Я заметил, что словарь my_root.nsmap содержит элемент None с пространством имен по умолчанию.

nsmap = {None: 'default namespace', ...} 

Я нашел быстрый обходной путь копирования nsmap и добавление элемента «по умолчанию» с тем же значением, как None пункт, а затем я

my_root.findall('default:Prop', new_map) 

Это чувствует себя очень хак. Почему None даже на карте пространства имен? Есть ли простой метод в lxml, который автоматически использует пространство имен по умолчанию?

Изменить: XML Я смотрю на это по линии

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<ScenarioProps xmlns="http://filler.com/default.xsd" xmlns:ns2="http://filler.com/ns.xsd" id="Test"> 
    <Prop id="Wi-Fi"> 
     <ns2:Position x="0.0" y="0.0" z="0.0"/> 
     <ns2:Orientation roll="0.0" pitch="0.0" yaw="0.0"/> 
    </Prop> 
</ScenarioProps> 
+0

Пожалуйста, покажите нам источник XML (preferab насколько это возможно, достаточно, чтобы воспроизвести проблему). – mzjn

+0

@mzjn редактируется. Надеюсь, этого достаточно, чтобы быть полезным. – Shatnerz

ответ

1

Hackish или нет, вы должны указать префикс. XPath 1.0, который поддерживает lxml, не имеет понятия пространства имен по умолчанию (он работает по-разному в XPath 2.0, но это не применимо здесь).

Другой вариант - не беспокоить префиксы вообще. Используйте полное имя элемента в «Clark нотации» вместо:

my_root.findall('{http://filler.com/default.xsd}Prop'). 

http://lxml.de/FAQ.html#how-can-i-specify-a-default-namespace-for-xpath-expressions Смотрите также.

+0

Спасибо, я смотрел на пространства имен по адресу http://lxml.de/tutorial.html. Я находился под впечатлением, ключ «Нет» был для пространства имен по умолчанию. Спасибо, что разобрался – Shatnerz

1

Я просто использовать вспомогательный класс. context - это документ, my - это пространство имен, а key - это имя тега.

found = self.context.find('.//{%s}%s' % (self.my, key)) 
1

вы можете «автоматически» переопределить пространство имен по умолчанию что-то вроде:

{k if k is not None else 'default':v for k,v in my_root.nsmap.items()} 

который получает словарь пространства имен с ключом None заменен «по умолчанию» и оставляет все остальные ключи нетронутыми:

{'default': 'http://filler.com/default.xsd', 'ns2': 'http://filler.com/ns.xsd'} 

ваш пример будет выглядеть следующим образом:

from lxml import etree 
import StringIO 
f = StringIO.StringIO(''' 
<ScenarioProps xmlns="http://filler.com/default.xsd" xmlns:ns2="http://filler.com/ns.xsd" id="Test"> 
    <Prop id="Wi-Fi"> 
     <ns2:Position x="0.0" y="0.0" z="0.0"/> 
     <ns2:Orientation roll="0.0" pitch="0.0" yaw="0.0"/> 
    </Prop> 
</ScenarioProps> 
''') 
parser = etree.XMLParser() 
my_tree = etree.parse(f, parser) 
my_root = my_tree.getroot() 
my_tree.getroot().nsmap 
nsmap = {k if k is not None else 'default':v for k,v in my_root.nsmap.items()} 
my_root.findall('default:Prop', nsmap) 
Смежные вопросы