Python lxml.etree.ElementTree mangles变音符号

Python lxml.etree.ElementTree mangles变音符号,python,json,python-3.x,lxml,diacritics,Python,Json,Python 3.x,Lxml,Diacritics,另一个标题可能是为什么lxml.etree.ElementTree.write不相信我指定的编码 使用Python 3.6将一些json响应转换为一些XML方言。json是正确的utf-8,我对数据所做的就是使用lxml.builder将其包装在XML标记中 我希望能够在浏览器中检查xml结果,因此我使用lxml.etree.ElementTree中的write方法来生成一个xml文件,我使用Firefox或Chrome、IE或Edge打开该文件时不会有任何区别 下面是一些测试代码,使用带变音符

另一个标题可能是为什么lxml.etree.ElementTree.write不相信我指定的编码

使用Python 3.6将一些json响应转换为一些XML方言。json是正确的utf-8,我对数据所做的就是使用lxml.builder将其包装在XML标记中

我希望能够在浏览器中检查xml结果,因此我使用lxml.etree.ElementTree中的write方法来生成一个xml文件,我使用Firefox或Chrome、IE或Edge打开该文件时不会有任何区别

下面是一些测试代码,使用带变音符号的字符串代替json响应。这个很好用。注意xml_declaration=True以通知浏览器编码

# -*- coding: utf-8 -*-

from lxml import etree as ET
from lxml.builder import E          # E *is* ElementMaker()

s = 'Björn Nøsflùgl in Israël'      # ö = c3 b6, ø = c3 b8, ù = c3 b9, ë = c3 ab

xml = E.myXML(E.name(s))            # <class 'lxml.etree._Element'>
tree = ET.ElementTree(xml)          # <class 'lxml.etree._ElementTree'>

tree.write(open('1.xml', 'wb'), xml_declaration=True, encoding='utf-8')
# xml declaration says 'UTF-8', Firefox renders correctly 
如果我将.encode'cp1252'。解码'utf-8'添加到注释中所示的term子句中,问题就解决了。但为什么这是必要的呢

编辑2:同时,从中,我学到了一种可能的解决方法,即独立于平台,甚至独立于机器:

import locale 
...

myencoding = locale.getpreferredencoding()  
for record in gvp_json['results']['bindings']: 
    s = record['term']['value']
    if myencoding == 'utf-8':
        term = s
    else:
        term = s.encode(myencoding).decode('utf-8') 

    print(term) 
    ...    
它确实不漂亮,但它很管用。它不会不必要地编码、解码

解释-请CMIIW:print需要采用某种编码,无法从数据本身推断编码,因此在打印到控制台时采用locale.getpreferredencoding

但是,当我指定数据为utf-8时,为什么lxml.etree.ElementTree.write会将其解释为cp1252编码的数据呢?我想,根本不需要encode.decode


如果您能提供任何有用的意见,我们将不胜感激

Web服务器似乎没有为其提供的内容返回正确的HTTP头

如果您检查返回的标题,您可以看到ISO-8859-1请参阅内容类型标题:

python请求尽力解码响应体,并使用ISO-8859-1。 看看会发生什么

响应内容的编码仅基于 HTTP头,完全遵循RFC2616。如果你能 利用非HTTP知识更好地猜测 编码,您应该在访问之前适当地设置r.encoding 这是我的财产

问题是您知道响应是UTF-8编码的,所以您可以强制它:

>>> # force encoding used when accessing r.text
... # see http://docs.python-requests.org/en/master/api/#requests.Response.text
... 
>>> r.encoding = 'utf-8'
>>> 
>>> 
>>> r.text
'{\n  "head" : {\n    "vars" : [ "term" ]\n  },\n  "results" : {\n    "bindings" : [ {\n      "term" : {\n        "xml:lang" : "nl",\n        "type" : "literal",\n        "value" : "lössgronden"\n      }\n    } ]\n  }\n}'
>>> 
>>> 
>>> r.json()
{'head': {'vars': ['term']}, 'results': {'bindings': [{'term': {'xml:lang': 'nl', 'type': 'literal', 'value': 'lössgronden'}}]}}
>>> 
>>> pp(r.json())
{'head': {'vars': ['term']},
 'results': {'bindings': [{'term': {'type': 'literal',
                                    'value': 'lössgronden',
                                    'xml:lang': 'nl'}}]}}
>>> 

因此,对从requests.get获得的响应对象强制编码将为您提供可良好解码的JSON数据。

Web服务器似乎没有为其提供的内容返回正确的HTTP头

如果您检查返回的标题,您可以看到ISO-8859-1请参阅内容类型标题:

python请求尽力解码响应体,并使用ISO-8859-1。 看看会发生什么

响应内容的编码仅基于 HTTP头,完全遵循RFC2616。如果你能 利用非HTTP知识更好地猜测 编码,您应该在访问之前适当地设置r.encoding 这是我的财产

问题是您知道响应是UTF-8编码的,所以您可以强制它:

>>> # force encoding used when accessing r.text
... # see http://docs.python-requests.org/en/master/api/#requests.Response.text
... 
>>> r.encoding = 'utf-8'
>>> 
>>> 
>>> r.text
'{\n  "head" : {\n    "vars" : [ "term" ]\n  },\n  "results" : {\n    "bindings" : [ {\n      "term" : {\n        "xml:lang" : "nl",\n        "type" : "literal",\n        "value" : "lössgronden"\n      }\n    } ]\n  }\n}'
>>> 
>>> 
>>> r.json()
{'head': {'vars': ['term']}, 'results': {'bindings': [{'term': {'xml:lang': 'nl', 'type': 'literal', 'value': 'lössgronden'}}]}}
>>> 
>>> pp(r.json())
{'head': {'vars': ['term']},
 'results': {'bindings': [{'term': {'type': 'literal',
                                    'value': 'lössgronden',
                                    'xml:lang': 'nl'}}]}}
>>> 

因此,对从requests.get获得的响应对象强制编码将为您提供可良好解码的JSON数据。

这个问题将在
它在10万年前已修复,但尚未部署:-我已重新打开此问题,希望它能很快部署。

此问题将在
它在10万年前已修复,但尚未部署:-我已重新打开此问题,希望它能很快部署。

当我对json响应执行相同操作时,发音符号会被弄乱。他们是怎么被弄坏的?我们如何重现这个问题?@mzjn很好,谢谢。我添加了一些代码来演示我可以重现的问题。它说的是lössgrunden,如果用UTF-8编码的lössgrunden被解释为用CP1252或拉丁语-1编码,你就会得到它。@mzjn完全正确。但我不明白为什么会发生这种情况,也不明白是什么原因导致了这种情况。当我对json响应执行同样的操作时,发音符号会被弄乱。他们是怎么被弄坏的?我们如何重现这个问题?@mzjn很好,谢谢。我添加了一些代码来演示我可以重现的问题。它说的是lössgrunden,如果用UTF-8编码的lössgrunden被解释为用CP1252或拉丁语-1编码,你就会得到它。@mzjn完全正确。但我不明白为什么会这样,也不明白是什么原因造成的。。非常感谢。但是,为什么将json响应写入文件不会损坏发音符号呢?对不起,在您的问题中,我没有发现将json响应写入文件不会损坏发音符号的情况。如果您将原始响应字节作为json文件写入文件,任何符合json的读取器都会很好地处理它,默认情况下原始响应为UTF-8。问题在于访问r.text或r.json时,它们试图解码字节。您也可以使用json.loadsr.content来解码原始字节。没问题,但是我使用r.json进行访问,并以文本“w”而不是“wb”的形式写入。所以我在这方面仍然有点困惑,但我对解决方案很满意。啊哈。。非常感谢。但是
为什么将json响应写入文件不会损坏发音符号?对不起,我没有在您的问题中指出将json响应写入文件不会损坏发音符号的情况。如果您将原始响应字节作为json文件写入文件,任何符合json的读取器都会很好地处理它,默认情况下原始响应为UTF-8。问题在于访问r.text或r.json时,它们试图解码字节。您也可以使用json.loadsr.content来解码原始字节。没问题,但是我使用r.json进行访问,并以文本“w”而不是“wb”的形式写入。所以我在这方面仍然有点困惑,但我对这个解决方案很满意。它现在已经部署好了。谢谢大家!现在已经部署好了。谢谢大家!
>>> r.text
'{\n  "head" : {\n    "vars" : [ "term" ]\n  },\n  "results" : {\n    "bindings" : [ {\n      "term" : {\n        "xml:lang" : "nl",\n        "type" : "literal",\n        "value" : "lössgronden"\n      }\n    } ]\n  }\n}'
>>> # force encoding used when accessing r.text
... # see http://docs.python-requests.org/en/master/api/#requests.Response.text
... 
>>> r.encoding = 'utf-8'
>>> 
>>> 
>>> r.text
'{\n  "head" : {\n    "vars" : [ "term" ]\n  },\n  "results" : {\n    "bindings" : [ {\n      "term" : {\n        "xml:lang" : "nl",\n        "type" : "literal",\n        "value" : "lössgronden"\n      }\n    } ]\n  }\n}'
>>> 
>>> 
>>> r.json()
{'head': {'vars': ['term']}, 'results': {'bindings': [{'term': {'xml:lang': 'nl', 'type': 'literal', 'value': 'lössgronden'}}]}}
>>> 
>>> pp(r.json())
{'head': {'vars': ['term']},
 'results': {'bindings': [{'term': {'type': 'literal',
                                    'value': 'lössgronden',
                                    'xml:lang': 'nl'}}]}}
>>>