4

我正在使用 Python 的 elementtree 模块来编写一些 XML(我正在使用 Python 2.7 和 3.2)。我的一些元素的文本字段包含数字字符引用。

但是,一旦我使用 elementtree 的tostring字符引用中的所有 & 符号,就会被替换为&. 显然 elementtree 或底层解析器不承认这里的&符号是数字字符引用的一部分。

经过一番搜索,我发现了这个:elementtree and entity

但是,我也不热衷于此,因为在我当前的代码中,我预见到这最终可能会导致其自身的问题。除此之外,我在这方面发现的很少,所以也许我只是忽略了一些明显的东西?

下面的简单测试代码说明了这个问题(使用 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

您需要解码输入中的字符引用。这是一个将解码数字字符引用和 html 命名引用的函数;它接受一个字节字符串作为输入并返回 unicode。下面的代码适用于 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 回答
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()

请注意,我添加了 final.decode("ascii")以使其与 Python 3 一起工作(与 Python 2.7 不同,testElementAsString它以字节对象的形式返回)。

再次感谢@Duncan、@Inerdial 和@Tomalak 为我指明了正确的方向,以及@Rik Poggi 更正了我原始帖子中的格式!

于 2012-02-16T10:07:45.450 回答