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的常见命令注入威胁
Feb 18 Python
pyqt4教程之messagebox使用示例分享
Mar 07 Python
python使用matplotlib绘图时图例显示问题的解决
Apr 27 Python
Python实现的破解字符串找茬游戏算法示例
Sep 25 Python
python实现支付宝当面付(扫码支付)功能
May 30 Python
python代码实现逻辑回归logistic原理
Aug 07 Python
python通过链接抓取网站详解
Nov 20 Python
windows上彻底删除jupyter notebook的实现
Apr 13 Python
Python爬虫实现vip电影下载的示例代码
Apr 20 Python
详解numpy.ndarray.reshape()函数的参数问题
Oct 13 Python
python os.rename实例用法详解
Dec 06 Python
利用Python函数实现一个万历表完整示例
Jan 23 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中使用gd库实现远程图片下载实例
2015/05/12 PHP
WordPress中用于检索模版的相关PHP函数使用解析
2015/12/15 PHP
PHP获取用户访问IP地址的5种方法
2016/05/16 PHP
Javascript 圆角div的实现代码
2009/10/15 Javascript
对采用动态原型方式无法展示继承机制得思考
2009/12/04 Javascript
jQuery学习笔记 操作jQuery对象 文档处理
2012/09/19 Javascript
JQuery右键菜单插件ContextMenu使用指南
2014/12/19 Javascript
详解javascript的变量与标识符
2016/01/04 Javascript
基于jQuery实现的幻灯图片切换
2016/12/02 Javascript
详解jQuery lazyload 懒加载
2016/12/19 Javascript
Javascript中for循环语句的几种写法总结对比
2017/01/23 Javascript
jQuery代码实现实时获取时间
2017/01/29 Javascript
详解Vue路由钩子及应用场景(小结)
2017/11/07 Javascript
JS表单传值和URL编码转换
2018/03/03 Javascript
vue插件实现v-model功能
2018/09/10 Javascript
详解关于Vue2.0路由开启keep-alive时需要注意的地方
2018/09/18 Javascript
vue移动端html5页面根据屏幕适配的四种解决方法
2018/10/19 Javascript
JavaScript时间与时间戳的转换操作实例分析
2018/12/07 Javascript
前端路由&amp;webpack基础配置详解
2019/06/10 Javascript
Python实现的石头剪子布代码分享
2014/08/22 Python
Python MySQLdb模块连接操作mysql数据库实例
2015/04/08 Python
Python正则表达式完全指南
2017/05/25 Python
python实现一个简单的udp通信的示例代码
2019/02/01 Python
详解Django3中直接添加Websockets方式
2020/02/12 Python
python实现学生信息管理系统(精简版)
2020/11/27 Python
python中字符串的编码与解码详析
2020/12/03 Python
简单掌握CSS3将文字描边及填充文字颜色的方法
2016/03/07 HTML / CSS
德国体育用品网上商店:SC24.com
2016/08/01 全球购物
金宝贝童装官网:Gymboree
2016/08/31 全球购物
俄罗斯玩具、儿童用品、儿童服装和鞋子网上商店:MyToys.ru
2019/10/14 全球购物
世界上最受欢迎的花店:1-800-Flowers.com
2020/06/01 全球购物
银行竞聘演讲稿范文
2014/04/23 职场文书
2015年国培研修感言
2015/08/01 职场文书
Golang实现AES对称加密的过程详解
2021/05/20 Golang
使用Redis实现点赞取消点赞的详细代码
2022/03/20 Redis
Java结构型设计模式之组合模式详解
2022/09/23 Java/Android