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中dictionary items()系列函数的用法实例
Aug 21 Python
在Python中使用dict和set方法的教程
Apr 27 Python
详解Django 中是否使用时区的区别
Jun 14 Python
Flask web开发处理POST请求实现(登录案例)
Jul 26 Python
Python 变量类型详解
Oct 10 Python
django框架实现一次性上传多个文件功能示例【批量上传】
Jun 19 Python
python使用pandas处理excel文件转为csv文件的方法示例
Jul 18 Python
Python Django Cookie 简单用法解析
Aug 13 Python
Python While循环语句实例演示及原理解析
Jan 03 Python
浅析python标准库中的glob
Mar 13 Python
通过实例简单了解Python sys.argv[]使用方法
Aug 04 Python
如何查看python关键字
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
建立动态的WML站点(三)
2006/10/09 PHP
谈PHP生成静态页面分析 模板+缓存+写文件
2009/08/17 PHP
Zend Framework连接Mysql数据库实例分析
2016/03/19 PHP
js实现iframe动态调整高度的代码
2008/01/06 Javascript
JavaScript DOM 添加事件
2009/02/14 Javascript
如何解决Jquery库及其他库之间的$命名冲突
2013/09/15 Javascript
基于jquery的手风琴图片展示效果实现方法
2014/12/16 Javascript
JavaScript的jQuery库中ready方法的学习教程
2015/08/14 Javascript
vue从使用到源码实现教程详解
2016/09/19 Javascript
js style.display=block显示布局错乱问题的解决方法
2016/09/21 Javascript
JavaScript浮点数及运算精度调整详解
2016/10/21 Javascript
JS实现探测网站链接的方法【测试可用】
2016/11/08 Javascript
模板视图和AngularJS之间冲突的解决方法
2016/11/22 Javascript
JS闭包与延迟求值用法示例
2016/12/22 Javascript
nodejs使用express创建一个简单web应用
2017/03/31 NodeJs
vuejs实现本地数据的筛选分页功能思路详解
2017/11/15 Javascript
vue 界面刷新数据被清除 localStorage的使用详解
2018/09/16 Javascript
JavaScript创建对象的四种常用模式实例分析
2019/01/11 Javascript
新手快速入门JavaScript装饰者模式与AOP
2019/06/24 Javascript
Python多线程编程(三):threading.Thread类的重要函数和方法
2015/04/05 Python
Python单元测试框架unittest使用方法讲解
2015/04/13 Python
Python中的if、else、elif语句用法简明讲解
2016/03/11 Python
python读取oracle函数返回值
2016/07/18 Python
Pandas之Fillna填充缺失数据的方法
2019/06/25 Python
Python openpyxl读取单元格字体颜色过程解析
2019/09/03 Python
详细分析Python垃圾回收机制
2020/07/01 Python
python从Oracle读取数据生成图表
2020/10/14 Python
实例教程 利用html5和css3打造一款创意404页面
2014/10/20 HTML / CSS
实习生自荐信范文分享
2013/11/27 职场文书
运动会解说词200字
2014/02/06 职场文书
大学生社团活动总结
2014/04/26 职场文书
培训科主任岗位职责
2014/08/08 职场文书
大班下学期幼儿评语
2014/12/30 职场文书
redis 查看所有的key方式
2021/05/07 Redis
Arthas排查Kubernetes中应用频繁挂掉重启异常
2022/02/28 MySQL
Python matplotlib绘制雷达图
2022/04/13 Python