lxml.etree fromstring() 和 tostring() 返回的数据不同
我正在学习lxml(之前用的是ElementTree),但我搞不懂为什么.fromstring和.tostring这两个方法似乎不能互相转换。下面是我的例子:
import lxml.etree as ET
f = open('somefile.xml','r')
data = f.read()
tree_in = ET.fromstring(data)
tree_out = ET.tostring(tree_in)
f2 = open('samefile.xml','w')
f2.write(tree_out)
f2.close
我有一个名为'somefile.xml'的文件,大小是132 KB。 而输出的'samefile.xml'只有113 KB,并且在某个随机的地方缺少了文件的结尾部分。整个树的关闭标签和最后一个元素的一些部分都消失了。
我的代码是不是有问题,还是说原始XML文件的结构有问题?如果是这样,我是不是只能再用BeautifulSoup或者ElementTree(不使用xpath)了?
还有一点:很多元素里面的文本有很多杂乱的东西被转换成了文本,这会导致这个问题吗?
例子:
<QuestionIndex Id="Perm"><Answer><![CDATA[confirm]]></Answer><Answer><![CDATA[NotConfirm]]></Answer></QuestionIndex>
<QuestionIndex Id="Actor"><Answer><![CDATA[GirlLt16]]></Answer><Answer><![CDATA[Fem17to25]]></Answer><Answer><![CDATA[BoyLt16]]></Answer><Answer><![CDATA[Mal17to25]]></Answer><Answer><![CDATA[Moth]]></Answer><Answer><![CDATA[Fath]]></Answer><Answer><![CDATA[Elder]]></Answer><Answer><![CDATA[RelLead]]></Answer><Answer><![CDATA[Auth]]></Answer><Answer><![CDATA[Teach]]></Answer><Answer><![CDATA[Oth]]></Answer></QuestionIndex>
2 个回答
9
“在某个任意点缺少文件结尾”的问题很难解释,除非有一个完整的可重复的例子。
但我怀疑你所说的“很多垃圾”其实是指CDATA部分。在你的例子中有几个这样的部分(顺便说一下,这并不是一个单一的、格式正确的XML文档)。
一般来说,XML解析器并不一定要保留CDATA部分的完整性。像这样的标记
<Answer><![CDATA[confirm]]></Answer>
其实是等同于
<Answer>confirm</Answer>
不过,lxml.etree.XMLParser
类有一个strip_cdata
参数,可以用来保留CDATA部分。你可以把这个解析器的实例传给etree.fromstring()
。下面是一个例子:
from lxml import etree
XML = '<QuestionIndex Id="Perm"><Answer><![CDATA[confirm]]></Answer></QuestionIndex>'
print "Original size:", len(XML)
tree1 = etree.fromstring(XML)
out = etree.tostring(tree1)
print "With CDATA stripped:", len(out)
print out
parser = etree.XMLParser(strip_cdata=False)
tree2 = etree.fromstring(XML, parser)
out = etree.tostring(tree2)
print "With CDATA kept:", len(out)
print out
=>
Original size: 77
With CDATA stripped: 65
<QuestionIndex Id="Perm"><Answer>confirm</Answer></QuestionIndex>
With CDATA kept: 77
<QuestionIndex Id="Perm"><Answer><![CDATA[confirm]]></Answer></QuestionIndex>
2
这个问题其实比看起来简单多了,答案就在我提供的代码里。
f.close
应该是
f.close()
不同之处在于,有一些字符的剩余缓冲区没有被写入我检查结果的notepad++文件中。真正关闭文件后,一切都变得不同了,代码就正常工作了。