Get the character encoding of the XML document http_headers is a dictionary xml_data is a raw string (not Unicode) This is so much trickier than it sounds, it's not even funny. According to RFC 3023 ('XML Media Types'), if the HTTP Content-Type is application/xml, application/*
(http_headers, xml_data)
| 3567 | return None |
| 3568 | |
| 3569 | def _getCharacterEncoding(http_headers, xml_data): |
| 3570 | '''Get the character encoding of the XML document |
| 3571 | |
| 3572 | http_headers is a dictionary |
| 3573 | xml_data is a raw string (not Unicode) |
| 3574 | |
| 3575 | This is so much trickier than it sounds, it's not even funny. |
| 3576 | According to RFC 3023 ('XML Media Types'), if the HTTP Content-Type |
| 3577 | is application/xml, application/*+xml, |
| 3578 | application/xml-external-parsed-entity, or application/xml-dtd, |
| 3579 | the encoding given in the charset parameter of the HTTP Content-Type |
| 3580 | takes precedence over the encoding given in the XML prefix within the |
| 3581 | document, and defaults to 'utf-8' if neither are specified. But, if |
| 3582 | the HTTP Content-Type is text/xml, text/*+xml, or |
| 3583 | text/xml-external-parsed-entity, the encoding given in the XML prefix |
| 3584 | within the document is ALWAYS IGNORED and only the encoding given in |
| 3585 | the charset parameter of the HTTP Content-Type header should be |
| 3586 | respected, and it defaults to 'us-ascii' if not specified. |
| 3587 | |
| 3588 | Furthermore, discussion on the atom-syntax mailing list with the |
| 3589 | author of RFC 3023 leads me to the conclusion that any document |
| 3590 | served with a Content-Type of text/* and no charset parameter |
| 3591 | must be treated as us-ascii. (We now do this.) And also that it |
| 3592 | must always be flagged as non-well-formed. (We now do this too.) |
| 3593 | |
| 3594 | If Content-Type is unspecified (input was local file or non-HTTP source) |
| 3595 | or unrecognized (server just got it totally wrong), then go by the |
| 3596 | encoding given in the XML prefix of the document and default to |
| 3597 | 'iso-8859-1' as per the HTTP specification (RFC 2616). |
| 3598 | |
| 3599 | Then, assuming we didn't find a character encoding in the HTTP headers |
| 3600 | (and the HTTP Content-type allowed us to look in the body), we need |
| 3601 | to sniff the first few bytes of the XML data and try to determine |
| 3602 | whether the encoding is ASCII-compatible. Section F of the XML |
| 3603 | specification shows the way here: |
| 3604 | http://www.w3.org/TR/REC-xml/#sec-guessing-no-ext-info |
| 3605 | |
| 3606 | If the sniffed encoding is not ASCII-compatible, we need to make it |
| 3607 | ASCII compatible so that we can sniff further into the XML declaration |
| 3608 | to find the encoding attribute, which will tell us the true encoding. |
| 3609 | |
| 3610 | Of course, none of this guarantees that we will be able to parse the |
| 3611 | feed in the declared character encoding (assuming it was declared |
| 3612 | correctly, which many are not). iconv_codec can help a lot; |
| 3613 | you should definitely install it if you can. |
| 3614 | http://cjkpython.i18n.org/ |
| 3615 | ''' |
| 3616 | |
| 3617 | def _parseHTTPContentType(content_type): |
| 3618 | '''takes HTTP Content-Type header and returns (content type, charset) |
| 3619 | |
| 3620 | If no charset is specified, returns (content type, '') |
| 3621 | If no content type is specified, returns ('', '') |
| 3622 | Both return parameters are guaranteed to be lowercase strings |
| 3623 | ''' |
| 3624 | content_type = content_type or '' |
| 3625 | content_type, params = cgi.parse_header(content_type) |
| 3626 | charset = params.get('charset', '').replace("'", "") |
no test coverage detected
searching dependent graphs…