2012-05-18 12 views
8

にUTF-8を使用しているとき、私は、操作、解析しよう、とPythonのElementTreeのを使用して、出力HTMLてる非破りスペースを変換しません。マックOS X 10.6上で、私が取得:のPythonのElementTreeは出力

<p>Less than &lt;</p> 

Traceback (most recent call last): 
    File "bar.py", line 20, in <module> 
    print ET.tostring(p, encoding='utf-8') 
    File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py", line 1120, in tostring 
    ElementTree(element).write(file, encoding, method=method) 
    File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py", line 815, in write 
    serialize(write, self._root, encoding, qnames, namespaces) 
    File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py", line 931, in _serialize_xml 
    write(_escape_cdata(text, encoding)) 
    File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/xml/etree/ElementTree.py", line 1067, in _escape_cdata 
    return text.encode(encoding, "xmlcharrefreplace") 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 19: ordinal not in range(128) 

は私が思ったことを指定する「エンコード= 『UTF-8』」非改行空白文字の世話をするが、どうやらそれはないでしょう。代わりに私は何をすべきですか?

答えて

3

XMLは、&lt;,&gt;,&apos;,&quot;および&amp;と定義しています。 &nbsp;などはHTMLのものです。だからあなたはいくつかの選択肢を持っています。

  1. あなたは&nbsp;と同等であり、どちらも&#160;または&#xA0;ような数値エンティティを使用するようにソースを変更することができます。
  2. これらの値を定義するDTDを使用できます。

XSLT FAQでいくつかの有用な情報が(それはXSLTについて書かれているが、XSLTはXMLを使用して書かれているので、同じことが適用されます)があります。


質問がスタックトレースを含むようになりました。物事が変わる文字列がUTF-8になっていますか? 1バイトの0xA0に解決される場合は、UTF-8ではなく、cp1252またはiso-8859-1である可能性が高くなります。

+0

問題は入力時ではありません。UseForeignDTDトリックはそれで問題ありません。問題は出力されています:メモリ内のテキストには0xA0が含まれています.Et.tostringによってUTF-8表現に変換されると思います(私は 'encoding = "UTF-8"と言っています)。 –

-1

HTMLはXMLと同じではないため、&nbsp;のようなタグは機能しません。あなたがXML経由でその情報を渡すためにしようとしている場合、それはこのようなものになりますので、理想的には、最初に、上記のデータをXML-エンコードすることができ:

<xml> 
<mydata> 
&lt;htm&gt; 
&lt;body&gt; 
&lt;p&gt;Less than &amp;lt;&lt;/p&gt; 
&lt;p&gt;Non-breaking space &amp;nbsp;&lt;/p&gt; 
&lt;/body&gt; 
&lt;/html&gt; 
</mydata> 
</xml> 

をそしてXMLを解析した後、あなたは、HTML-unencodeをすることができます文字列。

+0

問題は入力時ではありません。UseForeignDTDトリックはそれで問題ありません。問題は出力されています:メモリ内のテキストには0xA0が含まれています.Et.tostringによってUTF-8表現に変換されると思います(私は 'encoding = "UTF-8"と言っています)。 –

-1

ここで問題になっているのは、nbspエンティティではなく、printステートメントであると思います。

あなたのエラーは、次のとおりです。

UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 19: ordinal not in range(128)

私はあなたが(ET.tostring(p, encoding='utf-8')から)UTF-8文字列を取り、ASCII端末でそれをエコーし​​ようとしているためであると考えています。したがって、Pythonはその文字列を暗黙的にUnicodeに変換してからASCIIに変換し直します。 nbsp をutf-8で直接表すことができますが、をasciiで直接表すことはできません。したがって、エラー。

代わりに出力をファイルに保存して、期待通りの結果が得られたかどうかを確認してください。

また、print ET.toString(p, encoding='ascii')を試してください。これにより、ElementTreeは数字エンティティを使用してasciiで表現できないものを表現する必要があります。

+0

出力をファイルに保存しても効果がありません: "output = open( 'temp.txt'、 'w')"を使用してファイルを開き、 "output.twrite(ET.tostring(p、encoding = 'アスキー "))"、私は同じエラーを取得します。 –

6

0xA0は、Unicode文字ではなく、pの値であるlatin1文字です。ループ内のテキストは、Unicodeではなくstrです。つまり、utf-8でエンコードするには、最初にPythonによって暗黙的にUnicode文字列に変換する必要があります(つまり、デコードを使用する)。これを実行しているときには、他に何も言われていないので、asciiを仮定します。 0xa0は有効なascii文字ではありませんが、有効なlatin1文字です。

ユニコード文字の代わりにlatin1文字がある理由は、entitydefsが名前をlatin1エンコード文字列にマッピングしているためです。

import sys 
from cStringIO import StringIO 
from xml.etree import ElementTree as ET 
from htmlentitydefs import name2codepoint 

source = StringIO("""<html> 
<body> 
<p>Less than &lt;</p> 
<p>Non-breaking space &nbsp;</p> 
</body> 
</html>""") 

parser = ET.XMLParser() 
parser.parser.UseForeignDTD(True) 
parser.entity.update((x, unichr(i)) for x, i in name2codepoint.iteritems()) 
etree = ET.ElementTree() 

tree = etree.parse(source, parser=parser) 
for p in tree.findall('.//p'): 
    print ET.tostring(p, encoding='UTF-8') 
+0

これは正解です!より簡潔にするため、 'htmlentitydefs.entitydefs'は悪いです。 ElementTreeにユニコード文字列だけが必要なバイト文字列が追加されています。残念ながら、エラーは後で表示されません。 –

3

あなた&nbsp;がデフォルト(asciiです「\ XA0」に変換されている:あなたはあなたのためにそれを修正する必要がありますがhtmlentitydef.name2codepoint

から以下のバージョンを取得することができますUnicodeのコードポイントが必要改行なしスペース用)エンコーディング(UTF-8エンコーディングは「\ XC2 XA0 \」。)ラインUnicodeDecodeErrorで

'\xa0'.encode('utf-8') 

結果、デフォルトのコーデックは、アスキーは、唯一の128の文字とORDまで動作しますので、 ( '\ xa0')= 160です。デフォルトのエンコーディングをsometに設定しますヒンジelse:

import sys 
reload(sys) # must reload sys to use 'setdefaultencoding' 
sys.setdefaultencoding('latin-1') 

print '\xa0'.encode('utf-8', "xmlcharrefreplace") 

は問題を解決するはずです。

関連する問題