Python中将字典转换为XML以及相关的命名空间解析


Posted in Python onOctober 15, 2015

尽管 xml.etree.ElementTree 库通常用来做解析工作,其实它也可以创建XML文档。 例如,考虑如下这个函数:

from xml.etree.ElementTree import Element

def dict_to_xml(tag, d):
'''
Turn a simple dict of key/value pairs into XML
'''
elem = Element(tag)
for key, val in d.items():
  child = Element(key)
  child.text = str(val)
  elem.append(child)
return elem

下面是一个使用例子:

>>> s = { 'name': 'GOOG', 'shares': 100, 'price':490.1 }
>>> e = dict_to_xml('stock', s)
>>> e
<Element 'stock' at 0x1004b64c8>
>>>

转换结果是一个 Element 实例。对于I/O操作,使用 xml.etree.ElementTree 中的 tostring() 函数很容易就能将它转换成一个字节字符串。例如:

>>> from xml.etree.ElementTree import tostring
>>> tostring(e)
b'<stock><price>490.1</price><shares>100</shares><name>GOOG</name></stock>'
>>>

如果你想给某个元素添加属性值,可以使用 set() 方法:

>>> e.set('_id','1234')
>>> tostring(e)
b'<stock _id="1234"><price>490.1</price><shares>100</shares><name>GOOG</name>
</stock>'
>>>

如果你还想保持元素的顺序,可以考虑构造一个 OrderedDict 来代替一个普通的字典。当创建XML的时候,你被限制只能构造字符串类型的值。例如:

def dict_to_xml_str(tag, d):
  '''
  Turn a simple dict of key/value pairs into XML
  '''
  parts = ['<{}>'.format(tag)]
  for key, val in d.items():
    parts.append('<{0}>{1}</{0}>'.format(key,val))
  parts.append('</{}>'.format(tag))
  return ''.join(parts)

问题是如果你手动的去构造的时候可能会碰到一些麻烦。例如,当字典的值中包含一些特殊字符的时候会怎样呢?

>>> d = { 'name' : '<spam>' }

>>> # String creation
>>> dict_to_xml_str('item',d)
'<item><name><spam></name></item>'

>>> # Proper XML creation
>>> e = dict_to_xml('item',d)
>>> tostring(e)
b'<item><name><spam></name></item>'
>>>

注意到程序的后面那个例子中,字符 ‘<' 和 ‘>' 被替换成了 < 和 >

下面仅供参考,如果你需要手动去转换这些字符, 可以使用 xml.sax.saxutils 中的 escape() 和 unescape() 函数。例如:

>>> from xml.sax.saxutils import escape, unescape
>>> escape('<spam>')
'<spam>'
>>> unescape(_)
'<spam>'
>>>

除了能创建正确的输出外,还有另外一个原因推荐你创建 Element 实例而不是字符串, 那就是使用字符串组合构造一个更大的文档并不是那么容易。 而 Element 实例可以不用考虑解析XML文本的情况下通过多种方式被处理。 也就是说,你可以在一个高级数据结构上完成你所有的操作,并在最后以字符串的形式将其输出。

利用命名空间解析XML文档
如果你解析这个文档并执行普通的查询,你会发现这个并不是那么容易,因为所有步骤都变得相当的繁琐。

>>> # Some queries that work
>>> doc.findtext('author')
'David Beazley'
>>> doc.find('content')
<Element 'content' at 0x100776ec0>
>>> # A query involving a namespace (doesn't work)
>>> doc.find('content/html')
>>> # Works if fully qualified
>>> doc.find('content/{http://www.w3.org/1999/xhtml}html')
<Element '{http://www.w3.org/1999/xhtml}html' at 0x1007767e0>
>>> # Doesn't work
>>> doc.findtext('content/{http://www.w3.org/1999/xhtml}html/head/title')
>>> # Fully qualified
>>> doc.findtext('content/{http://www.w3.org/1999/xhtml}html/'
... '{http://www.w3.org/1999/xhtml}head/{http://www.w3.org/1999/xhtml}title')
'Hello World'
>>>

你可以通过将命名空间处理逻辑包装为一个工具类来简化这个过程:

class XMLNamespaces:
  def __init__(self, **kwargs):
    self.namespaces = {}
    for name, uri in kwargs.items():
      self.register(name, uri)
  def register(self, name, uri):
    self.namespaces[name] = '{'+uri+'}'
  def __call__(self, path):
    return path.format_map(self.namespaces)

通过下面的方式使用这个类:

>>> ns = XMLNamespaces(html='http://www.w3.org/1999/xhtml')
>>> doc.find(ns('content/{html}html'))
<Element '{http://www.w3.org/1999/xhtml}html' at 0x1007767e0>
>>> doc.findtext(ns('content/{html}html/{html}head/{html}title'))
'Hello World'
>>>

讨论
解析含有命名空间的XML文档会比较繁琐。 上面的 XMLNamespaces 仅仅是允许你使用缩略名代替完整的URI将其变得稍微简洁一点。

很不幸的是,在基本的 ElementTree 解析中没有任何途径获取命名空间的信息。 但是,如果你使用 iterparse() 函数的话就可以获取更多关于命名空间处理范围的信息。例如:

>>> from xml.etree.ElementTree import iterparse
>>> for evt, elem in iterparse('ns2.xml', ('end', 'start-ns', 'end-ns')):
... print(evt, elem)
...
end <Element 'author' at 0x10110de10>
start-ns ('', 'http://www.w3.org/1999/xhtml')
end <Element '{http://www.w3.org/1999/xhtml}title' at 0x1011131b0>
end <Element '{http://www.w3.org/1999/xhtml}head' at 0x1011130a8>
end <Element '{http://www.w3.org/1999/xhtml}h1' at 0x101113310>
end <Element '{http://www.w3.org/1999/xhtml}body' at 0x101113260>
end <Element '{http://www.w3.org/1999/xhtml}html' at 0x10110df70>
end-ns None
end <Element 'content' at 0x10110de68>
end <Element 'top' at 0x10110dd60>
>>> elem # This is the topmost element
<Element 'top' at 0x10110dd60>
>>>

最后一点,如果你要处理的XML文本除了要使用到其他高级XML特性外,还要使用到命名空间, 建议你最好是使用 lxml 函数库来代替 ElementTree 。 例如,lxml 对利用DTD验证文档、更好的XPath支持和一些其他高级XML特性等都提供了更好的支持。 这一小节其实只是教你如何让XML解析稍微简单一点。

Python 相关文章推荐
python通过pil模块将raw图片转换成png图片的方法
Mar 16 Python
在Django的模型中添加自定义方法的示例
Jul 21 Python
python使用正则表达式替换匹配成功的组并输出替换的次数
Nov 22 Python
Python实现多进程共享数据的方法分析
Dec 04 Python
Python实现的质因式分解算法示例
May 03 Python
widows下安装pycurl并利用pycurl请求https地址的方法
Oct 15 Python
Python中format()格式输出全解
Apr 12 Python
Python多线程正确用法实例解析
May 30 Python
python pip如何手动安装二进制包
Sep 30 Python
python关于倒排列的知识点总结
Oct 13 Python
Python word文本自动化操作实现方法解析
Nov 05 Python
Pycharm连接远程服务器并远程调试的全过程
Jun 24 Python
详细解读Python中解析XML数据的方法
Oct 15 #Python
深入解析Python编程中JSON模块的使用
Oct 15 #Python
使用Python解析JSON数据的基本方法
Oct 15 #Python
深入讲解Python编程中的字符串
Oct 14 #Python
Python编程中字符串和列表的基本知识讲解
Oct 14 #Python
Python循环语句之break与continue的用法
Oct 14 #Python
Python编程中的for循环语句学习教程
Oct 14 #Python
You might like
php 数学运算验证码实现代码
2009/10/11 PHP
PHP获取MSN好友列表类的实现代码
2013/06/23 PHP
php读取flash文件高宽帧数背景颜色的方法
2015/01/06 PHP
php简单实现多字节字符串翻转的方法
2015/03/31 PHP
thinkphp框架使用JWTtoken的方法详解
2019/10/10 PHP
一端时间轮换的广告
2006/06/26 Javascript
一个网马的tips实现分析
2010/11/28 Javascript
jQuery 联动日历实现代码
2012/05/31 Javascript
javascript中有趣的反柯里化深入分析
2012/12/05 Javascript
基于Javascript实现二级联动菜单效果
2016/03/04 Javascript
jQuery实现的鼠标经过时变宽的效果(附demo源码)
2016/04/28 Javascript
JS实现title标题栏文字不间断滚动显示效果
2016/09/07 Javascript
JavaScript随机生成颜色的方法
2016/10/15 Javascript
微信小程序 swiper制作tab切换实现附源码
2017/01/21 Javascript
JS实现图片预览的两种方式
2017/06/27 Javascript
jQuery 中msgTips 顶部弹窗效果实现代码
2017/08/14 jQuery
浅谈Webpack自动化构建实践指南
2017/12/18 Javascript
vue调试工具vue-devtools安装及使用方法
2018/11/07 Javascript
[03:39]这就是刀塔,我们是冠军!燃情短片讲述我们的DOTA故事
2019/07/02 DOTA
使用python搭建Django应用程序步骤及版本冲突问题解决
2013/11/19 Python
一个检测OpenSSL心脏出血漏洞的Python脚本分享
2014/04/10 Python
Python二分查找详解
2015/09/13 Python
Python编程实现蚁群算法详解
2017/11/13 Python
Sanic框架基于类的视图用法示例
2018/07/18 Python
Python操作json的方法实例分析
2018/12/06 Python
pyinstaller参数介绍以及总结详解
2019/07/12 Python
python代码xml转txt实例
2020/03/10 Python
pycharm部署、配置anaconda环境的教程
2020/03/24 Python
Python3.7将普通图片(png)转换为SVG图片格式(网站logo图标)动起来
2020/04/21 Python
Keras中的两种模型:Sequential和Model用法
2020/06/27 Python
python里glob模块知识点总结
2021/01/05 Python
python实现控制台输出颜色
2021/03/02 Python
阿玛尼美妆俄罗斯官网:Giorgio Armani Beauty RU
2020/07/19 全球购物
思想政治自我鉴定
2013/10/06 职场文书
中班上学期幼儿评语
2014/04/30 职场文书
CSS实现隐藏搜索框功能(动画正反向序列)
2021/07/21 HTML / CSS