python lxml使用iterparse来编辑和输出xml

时间:2014-03-19 00:11:55

标签: python xml xpath lxml

我一直在搞乱lxml库一段时间,也许我没有正确理解它或者我错过了一些东西但我似乎无法弄清楚如何在我抓到之后编辑文件某个xpath,然后能够在我逐个元素地解析时将其写回xml。

假设我们将此xml作为示例:

<xml>
   <items>
      <pie>cherry</pie>
      <pie>apple</pie>
      <pie>chocolate</pie>
  </items>
</xml>

我在解析时想要做的是当我点击“/ xml / items / pie”的xpath时是在馅饼之前添加一个元素,所以它会像这样:

<xml>
   <items>
      <item id="1"><pie>cherry</pie></item>
      <item id="2"><pie>apple</pie></item>
      <item id="3"><pie>chocolate</pie></item>
  </items>
</xml>

当我点击每个标签并在某些xpath处编辑xml时,需要通过逐行写入文件来完成输出。我的意思是我可以让它打印起始标签,文本,属性(如果它存在),然后通过硬编码某些部分来结束标签,但这将是非常混乱的,如果有办法避免如果可能的。

这是我的猜测代码:

from lxml import etree

path=[]
count=0

context=etree.iterparse(file,events=('start','end'))
for event, element in context:
    if event=='start':
       path.append(element.tag)
       if /'+'/'.join(path)=='/xml/items/pie':
          itemnode=etree.Element('item',id=str(count))
          itemnode.text=""
          element.addprevious(itemnode)#Not the right way to do it of course
          #write/print out xml here.
    else:
        element.clear()
        path.pop()

编辑:另外,我需要运行相当大的文件,所以我必须使用iterparse。

3 个答案:

答案 0 :(得分:1)

有一种更简洁的方法可以进行所需的修改:

  • 迭代pie元素
  • 制作item元素
  • 使用replace()pie元素替换为item
  

replace(self,old_element,new_element)

     

用子句替换子元素   元素作为第二个参数传递。


from lxml import etree
from lxml.etree import XMLParser, Element

data = """<xml>
   <items>
      <pie>cherry</pie>
      <pie>apple</pie>
      <pie>chocolate</pie>
  </items>
</xml>"""


tree = etree.fromstring(data, parser=XMLParser())
items = tree.find('.//items')
for index, pie in enumerate(items.xpath('.//pie'), start=1):
    item = Element('item', {'id': str(index)})
    items.replace(pie, item)
    item.append(pie)

print etree.tostring(tree, pretty_print=True)

打印:

<xml>
   <items>
      <item id="1"><pie>cherry</pie></item>
      <item id="2"><pie>apple</pie></item>
      <item id="3"><pie>chocolate</pie></item>
   </items>
</xml>

答案 1 :(得分:1)

这是使用iterparse()的解决方案。我们的想法是抓住所有标签&#34; start&#34;事件,记住父(items)标记,然后为每个pie标记创建一个item标记并将其放入其中:

from StringIO import StringIO
from lxml import etree
from lxml.etree import Element

data = """<xml>
   <items>
      <pie>cherry</pie>
      <pie>apple</pie>
      <pie>chocolate</pie>
  </items>
</xml>"""

stream = StringIO(data)
context = etree.iterparse(stream, events=("start", ))

for action, elem in context:
    if elem.tag == 'items':
        items = elem
        index = 1
    elif elem.tag == 'pie':
        item = Element('item', {'id': str(index)})
        items.replace(elem, item)
        item.append(elem)
        index += 1

print etree.tostring(context.root)

打印:

<xml>
   <items>
      <item id="1"><pie>cherry</pie></item>
      <item id="2"><pie>apple</pie></item>
      <item id="3"><pie>chocolate</pie></item>
   </items>
</xml>

答案 2 :(得分:0)

我建议您使用XSLT模板,因为它似乎更适合此任务。最初XSLT有点棘手,直到你习惯它,如果你想要的只是从XML生成一些输出,那么XSLT是一个很好的工具。