首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >lxml.etree.ElementTree故障诊断

lxml.etree.ElementTree故障诊断
EN

Stack Overflow用户
提问于 2018-03-30 13:04:40
回答 2查看 299关注 0票数 1

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

用Python3.6将一些json响应转换成某种XML方言。json是正确的utf-8,我对数据所做的全部工作就是使用lxml.builder将其包装在XML-标记中。

我希望能够在浏览器中检查xml结果,所以我使用来自writelxml.etree.ElementTree方法来创建一个我用火狐打开的xml文件(或者Chrome,或者IE或Edge,没有什么区别)。

下面是一些测试代码,它使用一个带有对话的字符串,而不是json响应。这个很好用。注意xml_declaration=True可以将编码通知浏览器。

代码语言:javascript
复制
# -*- 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 

然而,当我对json的回应做同样的处理时,对话就会被破坏。

编辑:如下所示(在WindowsPython3.6虚拟环境中)。

代码语言:javascript
复制
# -*- coding: utf-8 -*-  

import requests  
import json 
from lxml import etree as ET  
from lxml.builder import E  

URL = '''http://vocab.getty.edu/sparql.json?query=SELECT ?term WHERE {?subject luc:term "löss*"; xl:prefLabel [dct:language gvp_lang:nl; xl:literalForm ?term]}'''

gvp_json = requests.get(URL).json()

with open('gvp_response.json', 'w') as f:           
    f.write(str(gvp_json))

for record in gvp_json['results']['bindings']: 
    term = record['term']['value']  # .encode('cp1252').decode('utf-8')
    print(term)    

xml = E.myXML(E.term(term)) 
tree = ET.ElementTree(xml)          
tree.write(open('1.xml', 'wb'), xml_declaration=True, encoding='utf-8')    

如果如注释中所示,将.encode('cp1252').decode('utf-8')追加到term子句,问题就解决了。但为什么有必要这样做呢?

编辑2:同时,我从这个老问题学到了一种可能的解决方法,即与平台无关甚至与机器无关的方法:

代码语言:javascript
复制
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) 
    ...    

它确实不漂亮,但很管用。而且它并不是不必要的encode().decode()

说明-请CMIIW:print()需要假设一些编码,没有办法从数据本身推断它,因此当打印到控制台时诉诸于locale.getpreferredencoding()

但是,为什么当我指定数据为utf-8时,lxml.etree.ElementTree.write()将数据解释为it 1252编码?encode().decode()根本不应该是必要的。

任何有学问的评论都将不胜感激。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-04-04 10:03:33

for服务器似乎没有为它交付的内容返回正确的HTTP报头。

如果您检查返回了哪些标头,您可以看到ISO-8859-1 (参见Content-Type标头):

代码语言:javascript
复制
$ python
Python 3.6.3 (default, Oct  3 2017, 21:45:48) 
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> 
>>> url = '''http://vocab.getty.edu/sparql.json?query=SELECT ?term WHERE {?subject luc:term "löss*"; xl:prefLabel [dct:language gvp_lang:nl; xl:literalForm ?term]}'''
>>>
>>> r = requests.get(url)

>>> r.encoding
'ISO-8859-1'
>>> r.apparent_encoding
'ISO-8859-9'
>>> 
>>> from pprint import pprint as pp
>>> pp(dict(r.headers))
{'Access-Control-Allow-Origin': '*',
 'Content-Disposition': 'attachment; filename="sparql.json"',
 'Content-Language': 'en-US',
 'Content-Type': 'application/sparql-results+json;charset=ISO-8859-1',
 'Date': 'Wed, 04 Apr 2018 09:55:40 GMT',
 'Link': '<http://opendatacommons.org/licenses/by/1.0/>; rel="license"',
 'Set-Cookie': 'BIGipServerForest=587573440.45165.0000; path=/; Httponly, '
               'TS01e0ec9b=01612fcdbaa1d82ab58469a933fdc88755f6f4d7323361b3f59734f898a9c7014e66f7c5cbf39c733fd24dc4e8817f73daf98f5aba52069337bdae2569cd6dbf2a6f05579c; '
               'Path=/',
 'Transfer-Encoding': 'chunked'}

文本确实是不可读的:

代码语言:javascript
复制
>>> 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}'

python尽力解码响应体并使用ISO-8859-1。有关发生的事情,请参阅医生们

响应内容的编码完全基于HTTP报头,遵循RFC 2616。如果您可以利用非HTTP知识对编码进行更好的猜测,那么在访问此属性之前,应该适当地设置r.encoding。

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

代码语言:javascript
复制
>>> # 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'}}]}}
>>> 

因此,强制对从Response获取的requests.get()对象进行编码,可以很好地为您提供可解码的JSON数据。

票数 3
EN

Stack Overflow用户

发布于 2018-04-05 13:31:09

这个问题是在盖蒂支援小组上讨论的,它在1000万年前就已经解决了,但还没有部署:-(我已经重新打开了问题ITSLOD-460,希望它很快就能被部署。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49575005

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档