python写入xml禁止转义问题的解决

这一篇博客以后回头来看可能很肤浅,但为了表示对Stack Overflow贡献者的感谢,顺便记录一下这次解决问题的过程,我还是决定写这篇博文。

以前很讨厌一些博主在写博客前写一堆“无用”的个人感想,但今天我也很想写一下。

好了,先说下我原本要做的需求。简单点讲,我就是要把xml文件中的一些内容修改后保存。但遇到了问题:如果直接调用(Document对象)api里的doc.writexml()函数,碰到xml标签的数据本身有<>尖括号等特殊字符时,会被自动转义成<等字符。

要解决这问题,按惯例我先是百度、谷歌了一遍,没能找到真正符合我使用场景的文章。那就先看看源码吧。发现这是由于minidom的所有内置节点类型在最后写入数据时,都是会调用_write_data()这个函数,这个函数如下:

python写入xml禁止转义问题-问题根源.png

所以,符号被转义的原因一目了然。

而且发现这个函数最终的一个写入操作是直接使用外部的文件写入对象的write方法写入的,于是我想尝试直接用外部open函数创建的写入对象(fw)反过来调用看能不能解决问题:

with open("/path.xls", 'w') as fw: fw.write(doc.toxml()))

但是发现toxml方法最终也还是会调用到每个子节点的writexml()方法,最终还是会调用上边截图的方法。虽然有别的方法可以直接把一个xml文件的内容从磁盘路径中读取出来,但我这个文件对象是在内存中修改后需要保存的,那种从磁盘读取的方式就很可惜了,用不了。然后发现doc实在是没有别的方法可以直接获取到整个文件的内容。毕竟它最终都要用到子节点的实现来读取内容,这也是python的dom解析xml为什么轻量的原因吧?它在需要读取内存数据时都是用了sax2解析器来解析。想到这,我放弃了查找能直接获取xml全部内容进行写入新文件这种方法了。当然也想过换一个库来实现等等。但是代价又太大了,而且python有使用比较普遍的也就sax、dom和elementtree外加几个有其它用途的库。这些库不说能不能解决这个问题,就是换过来也是很麻烦,其它调好的地方还得重新调试。更何况还会有别的问题。在这问题之前也有尝试使用这些库,但api使用不是那么符合我的使用场景,各种问题。

到了这会,如果不想换库的话,又要不用原本的实现,在没有api可以避开原有实现的前提下,我首先想到的是重写方法。于是真正开始使用python的第二天,我开始去搜怎么重写python的函数。正好这时,我在Stack Overflow上看到了一个禁止转义写入的答案,他的思路好像就是这样!但是他的答案没有被采纳。但看在他信誓旦旦地写了一堆代码,最后又各种ok的意思,我仔细看下他的代码,试图从中找点思路也好,看他实现过程,其实就是重写。按照这个思路去实现应该确实是可以的。不知道题主是出于何故,没有采纳他的答案。但既然答主也说可以那还是值得一试的,在看明白他的思路后,我就开始写了。仿照他的实现,我简化了下,因为他的答案考虑到了不是纯string才替换原节点,虽然这样是更合理一点,但我觉得会让我的业务代码增多,不便于维护,我就暂时考虑不管哪种节点,都一概替换成自定义的节点,以后有需求再更改好了。

这里我该附上Stack Overflow的问答链接了:

https://stackoverflow.com/questions/38015864/python-xml-dom-minidom-please-dont-escape-my-strings

在此,再次对答主spky和Stack Overflow平台表示感谢。

而我派生的类是这样:

python写入xml禁止转义问题-自定义节点.png

使用时只要对该标签元素的节点进行替换就可以了:

textNode = RawText() 
textNode.data = xxxxxxxx原始数据 
row.replaceChild(textNode, row.firstChild) 
# row 是从minidom Document对象中取出来的一个Element标签行

最后再正常写入就可以:

..... doc.writexml(fw) 或者 fw.write(doc.toxml())

至此大功告成。

你可能感兴趣的:(python写入xml禁止转义问题的解决)