python:在XML中转义非ascii字符

Jas*_*n S 5 python xml

我使用以下源文件打印我的测试XML文件,但它不能正确处理非ASCII字符:

xmltest.py:

import xml.sax.xmlreader
import xml.sax.saxutils

def testJunk(file, e2content):
  attr0 = xml.sax.xmlreader.AttributesImpl({})
  x =  xml.sax.saxutils.XMLGenerator(file)
  x.startDocument()
  x.startElement("document", attr0)

  x.startElement("element1", attr0)
  x.characters("bingo")
  x.endElement("element1")

  x.startElement("element2", attr0)
  x.characters(e2content)
  x.endElement("element2")

  x.endElement("document")
  x.endDocument()
Run Code Online (Sandbox Code Playgroud)

如果我做

>>> import xmltest
>>> xmltest.testJunk(open("test.xml","w"), "ascii 001: \001")
Run Code Online (Sandbox Code Playgroud)

然后我得到一个字符代码为001的xml文件.我无法弄清楚如何逃避这个角色.Firefox告诉我它不是格式良好的XML并抱怨该角色.我怎样才能解决这个问题?

澄清:我正在尝试记录一个我无法控制的函数的输出,它输出非ASCII字符.


更新:好的,现在我知道其中一个可接受范围之外的字符无法在表单中编码.(或者更确切地说,它们可以被编码,但这并不能帮助任何w/r/t XML格式不正确.)但是如果我定义了这样做的方法,它们就可以被转义.

(供将来参考:W3C 在XML标准本身之外有一个有用的页面,上面写着"控制代码应该用适当的标记替换",但并没有真正建议这样做的例子.)

如果我想以下列方式转义可接受范围之外的字符:

在转义之前:( 代表一个字符,而不是字面上的8个字符的字符串)

 abcdefghijkl
Run Code Online (Sandbox Code Playgroud)

逃跑后:

 abcd<u>0001</u>efgh<u>0002</u>ijkl
Run Code Online (Sandbox Code Playgroud)

我怎么能在python中这样做?

def escapeXML(src)
    dest = ??????
    return dest
Run Code Online (Sandbox Code Playgroud)

Joh*_*hin 4

"\001"又名“\x01”是一个 ASCII 控制代码。但它不是允许的 XML 字符之一。唯一符合条件的 ASCII 控制代码是“\t”、“\n”和“\r”。

例子:

>>> import xml.etree.cElementTree as ET
# Raw newline works
>>> t = ET.fromstring("<e>\n</e>")
>>> t.text
'\n'

# Hex escaping of a newline works
>>> t = ET.fromstring("<e>&#xa;</e>")
>>> t.text
'\n'

# Hex escaping of "\x01" doesn't work; it's not a valid XML character
>>> t = ET.fromstring("<e>&#x1;</e>")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 106, in XML
cElementTree.ParseError: reference to invalid character number: line 1, column 3
Run Code Online (Sandbox Code Playgroud)

如果您希望以某种方式在 XML 文档中包含无效的 XML 字符,则必须通过额外的转义级别将它们隐藏起来,不让 XML 解析器看到。该机制需要被记录、发布并被文档的读者理解。

例如,在 Microsoft Excel 2007+ XLSX 文件中,不是有效 XML 字符的 Unicode 代码点通过将其表示为代码点的十六进制表示形式_xhhhh_来走私通过解析器。hhhh在您的示例中,这将是 7 bytes _x0001_。请注意,必须对_文本中的任何字符进行转义,否则会被错误地解释为引入_xhhhh_序列。

这是丑陋的、痛苦的、低效的等等。你不妨考虑其他方法。是否有必要使用XML?CSV 文件(令人震惊,恐怖!)会在您的应用程序中做得更好吗?

编辑关于OP编码建议的一些注释:

答:虽然\r是有效的 XML 1.0 输入字符,但它会受到强制立即变形,因此您也应该转义它。

B. 该方案假设/希望不能<u>hhhh</u>与任何其他标记相混淆。

C. 我收回上面所说的关于微软转义计划的言论。它相对美观、无痛、高效。为了让温和的读者完整地了解您的方案,您应该显示转义令人讨厌的部分并将各个部分重新粘在一起所需的代码。请记住,MS 方案要求有人编写一个转义函数和一个非转义函数,而您的方案需要对每种工具(SAX、DOM、ElementTree)进行不同的处理。

D. 在详细层面上,代码有点奇怪:

if (len(g1) > 0):应该if g1:

if (not foo == None):有记录与普遍接受的习语有三个偏差:(1)括号(2)not x == y代替x != y(3)!= None代替is not None

不要使用list(以及其他内置对象的名称)作为您自己的变量的名称。

编辑2您想使用正则表达式拆分字符串。为什么不使用re.split

splitInvalidXML2 = re.compile(
    ur'([^\x09\x0A\x0D\x20-\x7E\x85\xA0-\xFF\u0100-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD])'
    ).split

def submitCharacters2(x, string):
    badchar = True
    for fragment in splitInvalidXML2(string):
        badchar = not badchar
        if badchar:
            x.startElement("u", attr0)
            x.characters('%04X' % ord(fragment))
            x.endElement("u")
        elif fragment:
            x.characters(fragment)
Run Code Online (Sandbox Code Playgroud)