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中的join()方法的使用
May 19 Python
Python 数据结构之旋转链表
Feb 25 Python
django模板语法学习之include示例详解
Dec 17 Python
python http接口自动化脚本详解
Jan 02 Python
Python简单实现的代理服务器端口映射功能示例
Apr 08 Python
python之线程通过信号pyqtSignal刷新ui的方法
Jan 11 Python
对python 通过ssh访问数据库的实例详解
Feb 19 Python
ML神器:sklearn的快速使用及入门
Jul 11 Python
Window系统下Python如何安装OpenCV库
Mar 05 Python
python代码xml转txt实例
Mar 10 Python
使用python画出逻辑斯蒂映射(logistic map)中的分叉图案例
Dec 11 Python
Python学习之time模块的基本使用
Jan 17 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中mysql_connect与mysql_pconncet的区别详解
2013/05/15 PHP
yii的CURD操作实例详解
2014/12/04 PHP
php操作mongoDB实例分析
2014/12/29 PHP
利用PHP获取访客IP、地区位置、浏览器及来源页面等信息
2017/06/27 PHP
PHP实现的Redis多库选择功能单例类
2017/07/27 PHP
Git命令之分支详解
2021/03/02 PHP
Jquery图形报表插件 jqplot简介及参数详解
2012/10/10 Javascript
JavaScript判断浏览器类型的方法
2015/02/10 Javascript
jQuery实现按钮只点击一次后就取消点击事件绑定的方法
2015/06/26 Javascript
实例详解jQuery结合GridView控件的使用方法
2016/01/04 Javascript
jQuery validate插件实现ajax验证重复的2种方法
2016/01/22 Javascript
js 博客内容进度插件详解
2017/02/19 Javascript
JavaScript中object和Object的区别(详解)
2017/02/27 Javascript
提升node.js中使用redis的性能遇到的问题及解决方法
2018/10/30 Javascript
NodeJs 模仿SIP话机注册的方法
2019/06/21 NodeJs
微信小程序实现蒙版弹出窗功能
2019/09/17 Javascript
Python使用正则表达式抓取网页图片的方法示例
2017/04/21 Python
利用python3随机生成中文字符的实现方法
2017/11/24 Python
实用自动化运维Python脚本分享
2018/06/04 Python
Python函数中参数是传递值还是引用详解
2019/07/02 Python
Django 拆分model和view的实现方法
2019/08/16 Python
Python 制作查询商品历史价格的小工具
2020/10/20 Python
如何让PyQt5中QWebEngineView与JavaScript交互
2020/10/21 Python
python3通过subprocess模块调用脚本并和脚本交互的操作
2020/12/05 Python
python 实现Harris角点检测算法
2020/12/11 Python
HTML5 canvas标签实现刮刮卡效果
2015/04/24 HTML / CSS
美国领先的机场停车聚合商:Airport Parking Reservations
2020/02/28 全球购物
财务人员岗位职责
2015/02/03 职场文书
幼儿园国庆节活动总结
2015/03/23 职场文书
好人好事新闻稿
2015/07/17 职场文书
2019银行员工个人工作自我鉴定
2019/06/27 职场文书
2019财务转正述职报告
2019/06/27 职场文书
Python实现智慧校园自动评教全新版
2021/06/18 Python
Vue3.0写自定义指令的简单步骤记录
2021/06/27 Vue.js
mysql数据插入覆盖和时间戳的问题及解决
2022/03/25 MySQL
Python之matplotlib绘制饼图
2022/04/13 Python