转义字符串以在XML中使用

时间:2009-10-10 00:51:11

标签: python xml security escaping

我正在使用Python的xml.dom.minidom来创建XML文档。 (逻辑结构 - > XML字符串,而不是相反。)

如何让它逃脱我提供的字符串,这样他们就无法搞砸XML?

7 个答案:

答案 0 :(得分:65)

这样的东西?

>>> from xml.sax.saxutils import escape
>>> escape("< & >")   
'&lt; &amp; &gt;'

答案 1 :(得分:12)

你的意思是你做这样的事情:

from xml.dom.minidom import Text, Element

t = Text()
e = Element('p')

t.data = '<bar><a/><baz spam="eggs"> & blabla &entity;</>'
e.appendChild(t)

然后你将得到很好的转义XML字符串:

>>> e.toxml()
'<p>&lt;bar&gt;&lt;a/&gt;&lt;baz spam=&quot;eggs&quot;&gt; &amp; blabla &amp;entity;&lt;/&gt;</p>'

答案 2 :(得分:11)

默认情况下,

xml.sax.saxutils.escape仅会转义&<>,但它会提供entities参数以额外转义其他字符串:

from xml.sax.saxutils import escape

def xmlescape(data):
    return escape(data, entities={
        "'": "&apos;",
        "\"": "&quot;"
    })

xml.sax.saxutils.escape在内部使用str.replace(),因此您也可以跳过导入并编写自己的函数,如MichealMoser的回答所示。

答案 3 :(得分:9)

xml.sax.saxutils不会转义引号字符(“)

所以这是另一个:

def escape( str ):
    str = str.replace("&", "&amp;")
    str = str.replace("<", "&lt;")
    str = str.replace(">", "&gt;")
    str = str.replace("\"", "&quot;")
    return str

如果你查找它,那么xml.sax.saxutils只会执行字符串替换

答案 4 :(得分:4)

如果您不希望其他项目导入,并且您已经拥有cgi,则可以使用此项:

>>> import cgi
>>> cgi.escape("< & >")
'&lt; &amp; &gt;'

但请注意,由于此代码易读性受到影响 - 您可能应该将其放在一个函数中以更好地描述您的意图:(并在您使用时为其编写单元测试;)

def xml_escape(s):
    return cgi.escape(s) # escapes "<", ">" and "&"

答案 5 :(得分:2)

xml_special_chars = {
    "<": "&lt;",
    ">": "&gt;",
    "&": "&amp;",
    "'": "&apos;",
    '"': "&quot;",
}

xml_special_chars_re = re.compile("({})".format("|".join(xml_special_chars)))

def escape_xml_special_chars(unescaped):
    return xml_special_chars_re.sub(lambda match: xml_special_chars[match.group(0)], unescaped)

所有魔术都发生在re.sub()中:参数repl不仅接受字符串,还接受函数。

答案 6 :(得分:1)

Andrey Vlasovskikh 接受的答案是对 OP 最完整的答案。但是这个主题出现在最频繁的 /div//text() 搜索中,我想对所讨论的三种解决方案进行时间比较 在本文中以及提供第四个选项,我们选择部署,因为它提供了增强的性能。

所有四个都依赖于原生 python 数据处理或 python 标准库。解决方案按性能从最慢到最快的顺序提供。

选项 1 - 正则表达式

此解决方案使用 python 正则表达式库。它产生最慢的性能:

python escape xml

仅供参考:µs 是微秒的符号,即百万分之一秒。另一个实现的完成时间以纳秒 (ns) 为单位,即十亿分之一秒。

选项 2 -- xml.sax.saxutils

此解决方案使用 python import re table = { "<": "&lt;", ">": "&gt;", "&": "&amp;", "'": "&apos;", '"': "&quot;", } pat = re.compile("({})".format("|".join(table))) def xmlesc(txt): return pat.sub(lambda match: table[match.group(0)], txt) >>> %timeit xmlesc('<&>"\'') 1.48 µs ± 1.73 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 库。

xml.sax.saxutils

选项 3 - str.replace

此解决方案使用字符串 from xml.sax.saxutils import escape def xmlesc(txt): return escape(txt, entities={"'": "&apos;", '"': "&quot;"}) >>> %timeit xmlesc('<&>"\'') 832 ns ± 4.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 方法。在底层,它实现了与 python 的 replace() 类似的逻辑。 saxutils 代码有一个 for 循环,它会消耗一些性能,使这个版本稍微快一些。

xml.sax.saxutils

选项 4 - str.translate

这是最快的实现。它使用字符串 def xmlesc(txt): txt = txt.replace("&", "&amp;") txt = txt.replace("<", "&lt;") txt = txt.replace(">", "&gt;") txt = txt.replace('"', "&quot;") txt = txt.replace("'", "&apos;") return txt >>> %timeit xmlesc('<&>"\'') 503 ns ± 0.725 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each) 方法。

translate()