ElementTree and unicode
Solution 1
You do not need to decode XML for ElementTree to work. XML carries it's own encoding information (defaulting to UTF-8) and ElementTree does the work for you, outputting unicode:
>>> data = '''\
... <data>
... <products>
... <color>fumè</color>
... </products>
... </data>
... '''
>>> x = ElementTree.fromstring(data)
>>> x[0][0].text
u'fum\xe8'
If your data is contained in a file(like) object, just pass the filename or file object directly to the ElementTree.parse()
function:
x = ElementTree.parse('file.xml')
Solution 2
Might you have stumbled upon this problem while using Requests (HTTP for Humans), response.text
decodes the response by default, you can use response.content
to get the undecoded data, so ElementTree can decode it itself. Just remember to use the correct encoding.
More info: http://docs.python-requests.org/en/latest/user/quickstart/#response-content
Solution 3
You need to decode utf-8 strings into a unicode object. So
string_data.encode('utf-8')
should be
string_data.decode('utf-8')
assuming string_data
is actually an utf-8 string.
So to summarize: To get an utf-8 string from a unicode object you encode the unicode (using the utf-8 encoding), and to turn a string to a unicode object you decode the string using the respective encoding.
For more details on the concepts I suggest reading The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (not Python specific).
Solution 4
Have you tried using the parse
function, instead of opening the file... (which BTW would require a .read()
after it for the .fromstring()
to work...)
import xml.etree.ElementTree as ET
tree = ET.parse('file.xml')
root = tree.getroot()
# etc...
Solution 5
The most likely your file is not UTF-8. è
character can be from some other encoding, latin-1
for example.
pistacchio
Updated on October 10, 2020Comments
-
pistacchio over 3 years
I have this char in an xml file:
<data> <products> <color>fumè</color> </product> </data>
I try to generate an instance of ElementTree with the following code:
string_data = open('file.xml') x = ElementTree.fromstring(unicode(string_data.encode('utf-8')))
and I get the following error:
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe8' in position 185: ordinal not in range(128)
(NOTE: The position is not exact, I sampled the xml from a larger one).
How to solve it? Thanks
-
pistacchio over 11 yearsthis doesn't change anything, unfortunately
-
Martijn Pieters over 11 yearsThe OP's problem is that he/she is trying to handle decoding, instead of leaving it to ElementTree itself...
-
pistacchio over 11 yearsi made sure that the file is save with utf-8 encoding.
-
Lukas Graf over 11 years@MartijnPieters: Absolutely, I wrote my answer while on the go, should've looked at the question a bit more carefully. While encoding a bytestring to get unicode is definitely wrong, it wasn't the (real) problem here.
-
aman.gupta about 9 yearsSadly there are times when we have XML that does not have embedded encoding information and Elementree is getting it wrong, returning strs with broken characters in.
-
Martijn Pieters about 9 years@Kylotan: then those XML documents are at fault. The XML specification is very clear about this; the document is encoded as UTF8 unless specifically stated otherwise in the XML header.
-
Martijn Pieters about 9 years@Kylotan: you can override the XML declaration with an
ElementTree.XMLParser()
object passed in to theElementTree.parse()
function, use that for broken XML input. -
Martijn Pieters about 9 years@Kylotan: that doesn't make my answer incorrect just because you have broken XML, however.
-
aman.gupta about 9 yearsWell, it's hard for me to know if there's anything wrong with the XML given that it seemed to render ok elsewhere but I have had problems with the output, that's all I know. (Would undo the downvote, but SO doesn't allow me to.)
-
Martijn Pieters about 9 years@Kylotan: make sure you didn't make any errors with the Unicode output when extracting data from the XML file either; Unicode can be tricky and are not precise about encodings.
-
Charlie Clark about 9 years@MartijnPieters FWIW I've just hit this in Python 2.6 on Windows. Have to pass a string into a function which then uses
fromstring
. Source is a UTF8 file read usingcodecs.open()
. The solution does seem to be to force a conversion to utf8 in such situations. -
Martijn Pieters about 9 years@CharlieClark:
codecs.open()
produces a Unicode value, so<type 'unicode'>
, not a byte string. Yes, you'd have to encode back to UTF-8. -
Charlie Clark about 9 yearsI'm only experiencing problems with
xml.etree.ElementTree.fromstring()
in Python 2.6 on Windows. Other platforms (Mac, Linux) don't seem to need to conversion back to an encoded string. For future reference just in case anyone else comes across the same issue. -
jfs almost 9 yearsIn general, you should pass xml data (as bytes) directly to an XML parser unless
response.text
takes into account thatresponse.content
is XML and follows the corresponding standards e.g., reads the xml declaration fi any to find out the character encoding (it seems unlikely thatrequests
would do that and it shouldn't). -
Thang Nguyen over 8 yearsYou saved my life :).
-
EvertW almost 4 yearsTried the encoding 'cp-1250', that didn't work. 'latin-1' did. Thanks!