2012-03-08 75 views
0

解析空白XML标记时,格式为XML文档解析:与LXML和Python

<Car> 
    <Color>Blue</Color> 
    <Make>Chevy</Make> 
    <Model>Camaro</Model> 
</Car> 

我使用下面的代码:

carData = element.xpath('//Root/Foo/Bar/Car/node()[text()]') 
parsedCarData = [{field.tag: field.text for field in carData} for action in carData] 
print parsedCarData[0]['Color'] #Blue 

此代码不会,如果一个标签是空的工作如:

<Car> 
    <Color>Blue</Color> 
    <Make>Chevy</Make> 
    <Model/> 
</Car> 

使用相同的代码如上:

carData = element.xpath('//Root/Foo/Bar/Car/node()[text()]') 
parsedCarData = [{field.tag: field.text for field in carData} for action in carData] 
print parsedCarData[0]['Model'] #Key Error 

我该如何解析这个空白标记。

回答

3

你在[text()]过滤器仅其中明确要求对于具有文本节点元素把他们...然后你不高兴时,它不给你没有文字节点的元素?

离开过滤掉,你会得到你的模型元素:

>>> s=''' 
... <root> 
... <Car> 
...  <Color>Blue</Color> 
...  <Make>Chevy</Make> 
...  <Model/> 
... </Car> 
... </root>''' 
>>> e = lxml.etree.fromstring(s) 
>>> carData = e.xpath('Car/node()') 
>>> carData 
[<Element Color at 0x23a5460>, <Element Make at 0x23a54b0>, <Element Model at 0x23a5500>] 
>>> dict(((e.tag, e.text) for e in carData)) 
{'Color': 'Blue', 'Make': 'Chevy', 'Model': None} 

那说 - 如果你的近期目标是遍历树的节点,可以考虑使用lxml.etree.iterparse()相反,这将避免尝试在内存中构建完整的DOM树,否则将比构建树并使用XPath迭代它更有效。 (想想SAX,但没有疯狂和痛苦的API)。

iterparse实施看起来是这样的:

def get_cars(infile): 
    in_car = False 
    current_car = {} 
    for (event, element) in lxml.etree.iterparse(infile, events=('start', 'end')): 
     if event == 'start': 
      if element.tag == 'Car': 
       in_car = True 
       current_car = {} 
      continue 
     if not in_car: continue 
     if element.tag == 'Car': 
      yield current_car 
      continue 
     current_car[element.tag] = element.text 

for car in get_cars(infile = cStringIO.StringIO('''<root><Car><Color>Blue</Color><Make>Chevy</Make><Model/></Car></root>''')): 
    print car 

...这是更多的代码,但(如果我们不使用StringIO的的例子),它可以处理除了可以适应更大的文件记忆。

+0

现在我正在做一个'element = etree.parse(xmlfile)'。 iterparse如何改变我现有的代码库? – lodkkx 2012-03-08 15:39:50

+1

@lodkkx使用iterparse如下所示:lxml.etree.iterparse(xmlfile):...中的for(event_type,element):决定每个元素依次执行什么操作(通常是通过检查其标记)。 – 2012-03-08 15:46:52

1

我不知道里面有LXML建立了一个更好的解决方案,但你可以只使用.get()

print parsedCarData[0].get('Model', '') 
-1

解决方案:使用try/except块来捕捉关键错误。

+0

错误只发生在第一位,因为他没有文字过滤掉元素。为什么要避开它,在过程中缩短代码? – 2012-03-08 15:58:17

+0

@CharlesDuffy我认为OP有这样做的一些理由,也许他正在使用其他地方创建的数据结构。 – Marcin 2012-03-08 16:00:35

+0

是的,但结构很好 - 这是他用来检索部分结构的过滤器,而这部分显然是他的代码。 – 2012-03-08 16:48:52

0

我捕捉到了异常:

try: 
    print parsedCarData[0]['Model'] 
except KeyError: 
    print 'No model specified' 

异常在Python是不是在同一意义非凡在其他语言中,在那里它们被更严格地链接到错误条件。相反,它们通常是设计中正常使用模块的一部分。例如,一个迭代器引发StopIteration来表示它已经达到迭代的结束。

编辑:如果你确定只有这个项目可以是空的@CharlesDuffy有它的权利,因为使用get()可能更好。但总的来说,我会考虑使用异常来轻松处理各种异常输出。

+0

使用'parsedCarModel [0] .get('Model')'来避免异常(在未找到的情况下返回'None')比提升和处理异常更短更快......尽管我认为这是当从XPath查询中移除不必要的限制时,很愚蠢的做法首先会导致这个问题。 – 2012-03-08 15:59:47

+0

@CharlesDuffy:没错,但我认为这种方法有很多优点。我通常使用try/except块来包装行,我在其中几个关于输入的几个假设。在这种情况下,使用异常似乎比改变每一行更自然。另外,通常你必须用无论如何处理None。 – 2012-03-08 16:08:13