用LXML写XML头部

13 投票
1 回答
10861 浏览
提问于 2025-04-21 05:31

我现在正在写一个脚本,目的是把一堆不同编码的XML文件转换成统一的UTF-8编码。

首先,我尝试用LXML来确定文件的编码:

def get_source_encoding(self):
    tree = etree.parse(self.inputfile)
    encoding = tree.docinfo.encoding
    self.inputfile.seek(0)
    return (encoding or '').lower()

如果没有找到编码,我就会用chardet来获取编码:

def guess_source_encoding(self):
    chunk = self.inputfile.read(1024 * 10)
    self.inputfile.seek(0)
    return chardet.detect(chunk).lower()

接着,我使用codecs来转换文件的编码:

def convert_encoding(self, source_encoding, input_filename, output_filename):
    chunk_size = 16 * 1024

    with codecs.open(input_filename, "rb", source_encoding) as source:
        with codecs.open(output_filename, "wb", "utf-8") as destination:
            while True:
                chunk = source.read(chunk_size)

                if not chunk:
                    break;

                destination.write(chunk)

最后,我想重新写XML的头部。如果原来的XML头部是

<?xml version="1.0"?>

或者

<?xml version="1.0" encoding="windows-1255"?>

我希望把它改成

<?xml version="1.0" encoding="UTF-8"?>

我现在的代码似乎不太管用:

def edit_header(self, input_filename):
    output_filename = tempfile.mktemp(suffix=".xml")

    with open(input_filename, "rb") as source:
        parser = etree.XMLParser(encoding="UTF-8")
        tree = etree.parse(source, parser)

        with open(output_filename, "wb") as destination:
            tree.write(destination, encoding="UTF-8")

我正在测试的文件的头部没有指定编码。我该怎么做才能正确输出带有指定编码的头部呢?

1 个回答

17

试试这个:

tree.write(destination, xml_declaration=True, encoding='UTF-8')

来自 API文档

xml_declaration 控制是否在文件中添加XML声明。设置为 False 表示从不添加,设置为 True 表示总是添加,设置为 None 表示只有在不是US-ASCII或UTF-8编码时才添加(默认是 None)。

这是ipython的一个示例:

In [15]:  etree.ElementTree(etree.XML('<hi/>')).write(sys.stdout, xml_declaration=True, encoding='UTF-8')
<?xml version='1.0' encoding='UTF-8'?>
<hi/>

仔细想想,我觉得你可能太费劲了。 lxml 会自动检测编码,并根据该编码正确解析文件。

所以你实际上只需要做的(至少在Python2.7中)是:

def convert_encoding(self, source_encoding, input_filename, output_filename):
    tree = etree.parse(input_filename)
    with open(output_filename, 'w') as destination:
        tree.write(destination, encoding='utf-8', xml_declaration=True)

撰写回答