2012-02-14 14 views
3

私はいくつかのXMLを書くためにPythonのelementtreeモジュールを使用しています(私はPython 2.7と3.2を使用しています)。私の要素のいくつかのテキストフィールドには数字の文字参照が含まれています。Pythonのelementtreeによる数値参照のアンパサンドの置換

ただし、elementtreeのtostringを使用すると、文字参照内のすべてのアンパサンドが&に置き換えられます。明らかにelementtreeまたは基礎となるパーサーは、ここでのアンパサンドが数値参照の一部であることを認識しません。

は、いくつかの検索後、私はこれが見つかりました:elementtree and entities

を私の現在のコードで、私は、これは、独自の問題を引き起こしてしまうことが予見しかし、私は、このいずれかに熱心ではありませんよ。それ以外に私は驚くほど少ししか見つからなかったので、明らかに何かを見落としているだけでしょうか?

次の簡単なテストコードは、問題を示している(Pythonの2.7と3.2を使用してテスト):

import sys 
import xml.etree.ElementTree as ET 

def main(): 
    # Text string that contains numeric character reference 
    someText = "Ström" 

    # Create element object 
    testElement = ET.Element('rubbish') 

    # Add someText to element's text attribute 
    testElement.text = someText 

    # Convert element to xml-formatted text string 
    testElementAsString = ET.tostring(testElement,'ascii', 'xml') 

    print(testElementAsString) 

    # Result: ampersand replaced with '&amp;': <rubbish>Str&amp;#246;m</rubbish> 

main() 

誰もが素晴らしいだろう任意のアイデアや提案を持っている場合!

+1

XMLシリアライザへの実体参照を供給することはできません。それらの文字をそのまま使用してください。 – millimoose

+0

ありがとう!すでにそれを恐れていた... – johan

+1

'someText'は実際にどこから来たのですか? – Tomalak

答えて

2

入力の文字参照をデコードする必要があります。数値の文字参照とhtmlという名前の参照の両方をデコードする関数は次のとおりです。バイト文字列を入力として受け取り、ユニコードを返します。以下のコードは、Python 2.7または3.xで動作します。もちろん

import re 
try: 
    from htmlentitydefs import name2codepoint 
except ImportError: 
    # Must be Python 3.x 
    from html.entities import name2codepoint 
    unichr = chr 

name2codepoint = name2codepoint.copy() 
name2codepoint['apos']=ord("'") 

EntityPattern = re.compile('&(?:#(\d+)|(?:#x([\da-fA-F]+))|([a-zA-Z]+));') 

def decodeEntities(s, encoding='utf-8'): 
    def unescape(match): 
     code = match.group(1) 
     if code: 
      return unichr(int(code, 10)) 
     else: 
      code = match.group(2) 
      if code: 
       return unichr(int(code, 16)) 
      else: 
       code = match.group(3) 
       if code in name2codepoint: 
        return unichr(name2codepoint[code]) 
     return match.group(0) 

    return EntityPattern.sub(unescape, s.decode(encoding)) 

someText = decodeEntities(b"Str&#246;m") 
print(someText) 

、あなたの人生は多少楽になることで開始する文字列内の文字参照を避けることができます。

+0

ちょうどそれを試して、これは私が探していたものとまったく同じようです! – johan

+0

あまりにも速く入力してください:ちょうどそれを試してみて、これは私が探していたものとまったく同じです!文字参照を避けるためには、私はしたいと思いますが、ラテン15文字セットの文字を含むファイルから入力が得られ、出力ファイルにASCIIを使用したいと思います。だから私はこれを完全に避けることはできないのではないかと恐れている。 (事態を悪化させるために、私はかなり恣意的なバイナリデータも扱っていますが、これについて詳しく説明します!)しかし、あなたのコードは私の問題を大きく解決すると思います。ご協力いただき誠にありがとうございます! – johan

+0

@ johan:この回答があなたの問題を解決した場合は、おそらくそれを[同意する]と思うでしょう(http://meta.stackexchange.com/q/5234/177799)。 –

2

私はちょうど私のコードをもう一度見直しましたが、少なくとも私のためにはもっと簡単な解決策(ほとんど@Duncanの答えに基づいています)があることに気付きました。

元のコードでは、Latin-15でエンコードされたテキスト(バイナリファイルから読み込んでいたもの)のASCII表現を取得するためにエンティティ参照を使用していました。したがって、上記の変数someTextは、実際にはバイトオブジェクトとしての生活を開始しました。その後、Latin-15テキストにデコードされ、最後にASCIIに変換されました。

@Duncanと@Inerdialのおかげで、ElementTreeがLatin-15からASCIIへの変換を単独で行うことができます。いくつかの実験の後、私は決して簡単ではないほど単純な解決法を思いつきました。しかし、私はそれだけでいくつかのに役立つかもしれないと想像し、私はとにかくここでそれを共有することを決めた:(Iは、Python 3でこの仕事をするために、最終的な.decode("ascii")を追加

import sys 
import xml.etree.ElementTree as ET 

def main(): 
    # Bytes object 
    someBytes=b'Str\xf6m' 

    # Decode to Latin-15 
    someText=someBytes.decode('iso-8859-15','strict') 

    # Create element object 
    testElement=ET.Element('rubbish') 

    # Add someText to element's text attribute 
    testElement.text=someText 

    # Convert element to xml-formatted text string 
    testElementAsString=ET.tostring(testElement,'ascii', 'xml').decode('ascii') 

    print(testElementAsString) 

main() 

注意をされ、 Python 2.7とは異なり、バイトオブジェクトとしてtestElementAsStringを返します)。

もう一度@Duncan、@Inerdialと@Tomalakを私に正しい方向に向けてくれてありがとう、元の投稿の書式を修正するための@Rik Poggi!

+0

いつもお世話になりました、ありがとう@johan – adamnfish

関連する問題