转义字符串以在 XML 中使用

问题描述 投票:0回答:8

我正在使用 Python 的

xml.dom.minidom
创建 XML 文档。 (逻辑结构 -> XML 字符串,而不是相反。)

如何让它转义我提供的字符串,这样它们就不会弄乱 XML?

python xml security escaping
8个回答
87
投票

有这样的事吗?

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

23
投票

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

所以这是另一个:

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

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


19
投票
默认情况下,

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的答案所示。


15
投票

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

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>'

11
投票

Andrey Vlasovskikh 接受的答案是对 OP 最完整的答案。但这个主题出现在最频繁搜索

python escape xml
的情况下,我想提供所讨论的三种解决方案的时间比较 在本文中,我们选择部署第四个选项,因为它提供了增强的性能。

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

选项 1 - 正则表达式

此解决方案使用 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)

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

选项 2 -- xml.sax.saxutils

此解决方案使用 python

xml.sax.saxutils
库。

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)

选项 3 - str.replace

此解决方案使用字符串

replace()
方法。在底层,它实现了与 python 的
xml.sax.saxutils
类似的逻辑。 saxutils 代码有一个 for 循环,会消耗一些性能,使这个版本稍微快一些。

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)

选项 4 - str.translate

这是最快的实施。它使用字符串

translate()
方法。

table = str.maketrans({
    "<": "&lt;",
    ">": "&gt;",
    "&": "&amp;",
    "'": "&apos;",
    '"': "&quot;",
})
def xmlesc(txt):
    return txt.translate(table)

>>> %timeit xmlesc('<&>"\'')
352 ns ± 0.177 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

4
投票

如果您不想导入另一个项目并且您已经有了

cgi
,您可以使用这个:

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

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

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

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
不仅接受字符串,还接受函数。


0
投票

您可以使用自 Python 3.2 起可用的 内置库

import html clean_txt = html.escape(dirty_txt)
如果已经使用 XSS 库清除了 dirty_txt,则需要先进行转义。

import html clean_txt = html.escape(html.unescape(dirty_txt))
    
© www.soinside.com 2019 - 2024. All rights reserved.