2010-08-04 15 views
11

J'ai un fichier XML qui spécifie un encodage, et j'utilise UnicodeDammit pour le convertir en unicode (pour des raisons de stockage, je ne peux pas le stocker sous forme de chaîne). Je le passe plus tard à lxml mais il refuse d'ignorer l'encodage spécifié dans le fichier et de l'analyser en Unicode, et il déclenche une exception.Existe-t-il un moyen de forcer lxml à analyser les chaînes Unicode qui spécifient un codage dans une balise?

Comment puis-je forcer lxml à analyser le document? Ce comportement semble trop restrictif.

Répondre

3

Fondamentalement, la solution est de faire:

if isinstance(mystring, unicode): 
    mystring = mystring.encode("utf-8") 

sérieusement. Bon travail, lxml.

EDIT: Il s'avère que, dans ce cas, lxml détecte incorrectement le codage. Il semble que je vais devoir rechercher et supprimer manuellement "charset" et "encoding" de la page.

15

Vous ne pouvez pas analyser à partir de chaînes Unicode ET avoir une déclaration d'encodage dans la chaîne. Donc, soit vous en faites une chaîne encodée (comme vous ne pouvez apparemment pas la stocker en tant que chaîne, vous devrez la ré-encoder avant l'analyse) ou sérialiser l'arbre comme unicode avec lxml: etree.tostring(tree, encoding=unicode), SANS déclaration xml . vous pouvez facilement analyser le résultat à nouveau avec etree.fromunicode

voir http://lxml.de/parsing.html#python-unicode-strings

Edit:. Si, apparemment, vous avez déjà la chaîne unicode, et ne peut pas contrôler la façon dont cela a été fait, vous aurez à l'encoder à nouveau, et fournir à l'analyseur l'encodage que vous avez utilisé:

utf8_parser = etree.XMLParser(encoding='utf-8') 

def parse_from_unicode(unicode_str): 
    s = unicode_str.encode('utf-8') 
    return etree.fromstring(s, parser=utf8_parser) 

Cela assurera que tout ce qui était dans la déclaration xml sera ignoré, car l'analyseur utilisera toujours utf-8.

+0

Le problème est que je ne peux pas obtenir un arbre en premier lieu, si je pouvais, je n » J'ai des problèmes ... –

+0

@Stavros Korokithakis, etree est un module, pas l'arbre analysé. –

+0

@Daniel Kluev: Oui, mais "arbre" est un arbre. –

0

La solution ne réencode PAS la chaîne. La déclaration d'encodage à l'intérieur de la chaîne peut indiquer autre chose que UTF8. Ne pas ré-encoder aveuglément à utf8 et s'attendre à ce qu'il fonctionne tout le temps.

La solution consiste à supprimer la déclaration de codage. Vous avez déjà une chaîne Unicode à portée de main, elle n'est plus nécessaire!

# this is from lxml/apihelpers.pxi 
RE_XML_ENCODING = re.compile(
    ur'^(<\?xml[^>]+)\s+encoding\s*=\s*["\'][^"\']*["\'](\s*\?>|)', re.U) 

RE_XML_ENCODING.sub("", broken_xml_string, count=1) 

Le pire des cas (où aucune déclaration de codage xml se trouve) la complexité temporelle est O ici (n), ce qui est assez mauvais (mais toujours mieux que le codage aveuglément binaire) donc je suis ouvert aux suggestions ici .

PS: Certaines analyses intéressantes de problème d'encodage xml:

default encoding for XML is UTF-8 or UTF-16?

How default is the default encoding (UTF-8) in the XML Declaration?