lxml.etree fromsting()和tostring()没有返回相同的数据

时间:2012-01-26 23:34:31

标签: python lxml 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,它在某个arbirtrary点缺少文件的结尾。整个树的结束标记和最终元素的一些部分刚刚消失。

我的代码有问题,或者原始XML文件中的嵌套是否有问题?如果是这样,我是否被迫再次使用ElementTree的BeautifulSoup(没有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 个答案:

答案 0 :(得分:9)

如果没有一个完整的可重复的例子,“在某些arbirtrary点缺少文件的结尾”问题很难解释。

但我怀疑你所谓的“一堆垃圾”是CDATA sections。您的示例中有几个(这不是一个格式良好的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

=&GT;

   
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>

答案 1 :(得分:2)

这个问题比看上去简单得多,答案隐藏在我提供的代码中。

f.close

应该是

f.close()

不同之处在于几十个字符的剩余缓冲区从未进入我检查结果的记事本++文件中。关闭文件 for real 会产生重大影响,代码可以正常工作。