【问题标题】:Lost in XML and Python迷失在 XML 和 Python 中
【发布时间】:2012-01-30 10:24:42
【问题描述】:

您好,我已经开始学习 python 并想用它来对 XML 文件做一些事情。

我一直在寻找有关最佳路线的信息,但坦率地说,我有点迷路了。有很多方法可以操作 XML 文件,如 ElementTree、lxml、minidom 等。有人能指出我正确的方向吗?或者给我一些我可以理解的代码。我已经开始尝试使用 lxml,但还没有进一步打印所有元素。

这是我想要做的:

  1. 从 csv 文件中读取一行。加载 Label 和 FullPath。
  2. 使用数学 FullPath 在 XML 文件中查找 ITEM
  3. 将该项目的 FLAG1 更改为 TRUE
  4. 将该项目的 FLAG2 和 FLAG3 更改为 FALSE
  5. 将该项目的标签更改为 CSV 文件中的标签。
  6. 写出new.xml

下面是我的 xml 结构。下面的两条记录在文件中重复了 10000 次。

<ThisIsMyData>
  <ITEM>
    <Number>0</Number>
    <Flag1>TRUE</Flag1>
    <Flag2>FALSE</Flag2>  
    <Flag3>FALSE</Flag3>
    <Label>RED</Label> <<-2- After finding 1 I need to change THIS(only this)
    <Path>C:\\test\\</Path> <-1- I need to find this 
    <file>test.png</file>
  </ITEM>
  <ITEM>
    <Number>1</Number>
    <Flag1>TRUE</Flag1>
    <Flag2>FALSE</Flag2>
    <Flag3>FALSE</Flag3>
    <Label>Blue</Label>
    <Path>c:\\test\\test2\\</Path>
    <file>blue.png</file>
  </ITEM>
 </ThisIsMyData>

所以我有一个 ROOT : 然后很多元素:。 它们每个都有 7 个子元素。

这是我的 CSV 文件的样子,也是我需要输出的样子: CSV 文件:

  Label;FullPath
  YELLOW;C:\\test\\test.png
  YELLOW;c:\\test\\test2\\blue.png

 <ThisIsMyData>
  <ITEM>
    <Number>0</Number>
    <Flag1>FALSE</Flag1>
    <Flag2>FALSE</Flag2>
    <Flag3>TRUE</Flag3>
    <Label>YELLOW</Label>
    <Path>C:\\test\\</Path>
    <file>test.png</file>
  </ITEM>
  <ITEM>
    <Number>1</Number>
    <Flag1>FALSE</Flag1>
    <Flag2>FALSE</Flag2>
    <Flag3>TRUE</Flag3>
    <Label>YELLOW</Label>
    <Path>c:\\test\\test2\\</Path>
    <file>blue.png</file>
  </ITEM>
 </ThisIsMyData>

Pastebin 链接以防布局混乱:

http://pastebin.com/embed_js.php?i=QEx2ZGuY

我现在正在使用以下示例尝试 ElementTree: http://pymotw.com/2/xml/etree/ElementTree/parse.html。我设法在 xml 中搜索某个元素名称并打印内容。但是我仍然看不到在同一级别上找到匹配元素的方法。

from xml.etree import ElementTree
with open('mydata.xml', 'rt') as f:
    tree = ElementTree.parse(f)
#    filelist = ElementTree.ElementTree.find()
for node in tree.findall('.//file'):
    FileName = node.tag, node.text
    print FileName      

输出:

('file', 'test.png')
('file', 'blue.png')

【问题讨论】:

  • 你可以用你提到的任何解析器做你想做的事。您能否更具体地说明您无法解决的问题?

标签: python xml csv lxml


【解决方案1】:

这是一个简单的示例,说明如何使用 lxml.etreexpath 执行我认为您想要的操作。

from cStringIO import StringIO
from lxml import etree

xmlfile = StringIO("""
<ThisIsMyData>
  <ITEM>
    <Number>0</Number>
    <Flag1>TRUE</Flag1>
    <Flag2>FALSE</Flag2>  
    <Flag3>FALSE</Flag3>
    <Label>RED</Label>
    <Path>C:\\test\\</Path>
    <file>test.png</file>
  </ITEM>
  <ITEM>
    <Number>1</Number>
    <Flag1>TRUE</Flag1>
    <Flag2>FALSE</Flag2>
    <Flag3>FALSE</Flag3>
    <Label>Blue</Label>
    <Path>c:\\test\\test2\\</Path>
    <file>blue.png</file>
  </ITEM>
 </ThisIsMyData>
""".strip())

datafile = StringIO("""
Label;FullPath
YELLOW;C:\\test\\test.png
YELLOW;c:\\test\\test2\\blue.png
""".strip())

# Read "csv". Simple, no error checking, skip first line.
filenameToLabel = {}
for l,f in (x.strip().split(';') for x in datafile.readlines()[1:]):
  filenameToLabel[f] = l

def first(seq,default=None):
  """xpath helper function"""
  for item in seq:
    return item
  return None

doc = etree.XML(xmlfile.read())

for item in doc.xpath('//ITEM'):
  item_filename = first(item.xpath('./Path/text()'),'').strip() + first(item.xpath('./file/text()'),'').strip()
  label = filenameToLabel.get(item_filename)
  if label is not None:
    first(item.xpath('./Flag1')).text = 'TRUE'
    first(item.xpath('./Flag2')).text = 'FALSE'
    first(item.xpath('./Flag3')).text = 'FALSE'
    first(item.xpath('./Label')).text = label

print etree.tostring(doc)

产量

<ThisIsMyData>
  <ITEM>
    <Number>0</Number>
    <Flag1>TRUE</Flag1>
    <Flag2>FALSE</Flag2>
    <Flag3>FALSE</Flag3>
    <Label>YELLOW</Label>
    <Path>C:\test\</Path>
    <file>test.png</file>
  </ITEM>
  <ITEM>
    <Number>1</Number>
    <Flag1>TRUE</Flag1>
    <Flag2>FALSE</Flag2>
    <Flag3>FALSE</Flag3>
    <Label>YELLOW</Label>
    <Path>c:\test\test2\</Path>
    <file>blue.png</file>
  </ITEM>
</ThisIsMyData>

【讨论】:

  • 哦,非常感谢您的示例(工作文件)答案在这一行: item_filename = first(item.xpath('./Path/text()'),'').strip () + first(item.xpath('./file/text()'),'').strip() .
【解决方案2】:

首先使用python csv 模块从csv 文件中获取数据。如果数据不大,字符串拆分就可以正常工作。

比使用etree.XML 创建你的xml。

示例:

>>>from lxml import etree
>>> csv_value = 'C:\\test\\'
>>> st = '<document>'+'<Flag1>FALSE</Flag1>' + '<Flag2>FALSE</Flag2>'+'<Path>' + csv_value + '</Path>' + '</document>'
>>> tree = etree.XML(st)
>>> etree.tostring(tree)
'<document><Flag1>FALSE</Flag1><Flag2>FALSE</Flag2><Path>C:\\test\\</Path></document>'

获取csv_value 留给您作为练习。

还有take a look at this question

【讨论】:

  • 感谢您的回答,但我认为我在描述我正在尝试做的事情时过于含糊(可能是因为我使用了错误的术语)。这只是打印出一个构造的 XML。我需要做的是: 在第一个 XML 文件中查找 ITEM 的子元素,其中包含 csv 文件中的第二个字符串。然后将名为 :
【解决方案3】:

我发现 Beautiful Soup 和它的姐妹 Beautiful Stone Soup 有非常好的、简洁的、基于示例的文档,这些文档非常适合深入研究和尝试真实世界的示例。

但是,我也听说ElementTree 被某些人认为是 python 中的黄金标准。

【讨论】:

  • 根据 Droogans 的建议更新了有关 ElementTree 的更多信息和进展的问题
猜你喜欢
  • 2021-06-25
  • 2016-01-31
  • 1970-01-01
  • 2011-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多