I'm getting this error in my python program: ValueError: All strings must be XML compatible: Unicode or ASCII, no NULL bytes or control characters
This question, random text from /dev/random raising an error in lxml: All strings must be XML compatible: Unicode or ASCII, no NULL bytes, explains the issue.
The solution was to filter out certain bytes, but I'm confused about how to go about doing this.
Any help?
Edit: sorry if i didn't give enough info about the problem. the string data comes from an external api query of which i have no control over the how the data is formatted.
Another approach that's much faster than the answer above is to use regular expressions, like so:
Comparing to the answer above, it comes out to be more than 10X faster in my testing:
Output:
So, making sense of that, what we're doing is downloading this webpage once (the page you're currently reading), then running the functional technique and the regex technique over its contents 100X each.
Using the functional method takes about 2.6 seconds.
Using the regex method takes about 0.2 seconds.
Update: As identified in the comments, the regex in this answer previously deleted some characters, which should have been allowed in XML. These characters include anything in the Supplementary Multilingual Plane, which is includes ancient scripts like cuneiform, hieroglyphics, and (weirdly) emojis.
The correct regex is now above. A quick test for this in the future is using
re.DEBUG
, which prints:My apologies for the error. I can only offer that I found this answer elsewhere and put it in here. It was somebody else's error, but I propagated it. My sincere apologies to anybody this affected.
Update 2, 2017-12-12: I've learned from some OSX users that this code won't work on so-called narrow builds of Python, which apparently OSX sometimes has. You can check this by running
import sys; sys.maxunicode
. If it prints 65535, the code here won't work until you install a "wide build". See more about this here.you may refer to the solution on this website:
https://mailman-mail5.webfaction.com/pipermail/lxml/2011-July/006090.html
That solution works for me. You may also have to consider John Machin's solution.
Good luck!
As the answer to the linked question said, the XML standard defines a valid character as:
Translating that into Python:
You can then use that function however you need to, e.g.
I think this is harsh/overkill and it seems painfully slow, but my program is still quick and after struggling to comprehend what was going wrong (even after I attempted to implement @John's cleaned_string implementation), I just adapted his answer to purge ASCII-unprintable using the following (Python 2.7):
I'm not sure what I did wrong with the better option, but I just wanted to move on...