4

XMLを作成するためにPythonのelementtreeモジュールを使用しています(Python 2.7および3.2を使用しています)。一部の要素のテキストフィールドには、数値文字参照が含まれています。

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

いくつか検索した後、私はこれを見つけました:elementtreeと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()

誰かが素晴らしいアイデアや提案を持っているなら!

4

2 に答える 2

2

上記の短い更新:コードをもう一度批判的に見て、少なくとも私にとっては機能するさらに単純なソリューション(主に@Duncanの回答に基づく)があることに気付きました。

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

@Duncan と @Inerdial のおかげで、ElementTree が Latin-15 から 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()

.decode("ascii")Python 3 (Python 2.7 とは異なりtestElementAsString、bytes オブジェクトとして返される)でこれを機能させるために、final を追加したことに注意してください。

@Duncan、@Inerdial、@Tomalak に正しい方向を示していただき、@Rik Poggi に元の投稿のフォーマットを修正していただき、ありがとうございます。

于 2012-02-16T10:07:45.450 に答える
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)

もちろん、最初から文字列内の文字参照を取得することを避けることができれば、作業がいくらか楽になります。

于 2012-02-14T14:07:56.680 に答える