我正在使用 Python 的
xml.dom.minidom
创建 XML 文档。 (逻辑结构 -> XML 字符串,而不是相反。)
如何让它转义我提供的字符串,这样它们就不会弄乱 XML?
有这样的事吗?
>>> from xml.sax.saxutils import escape
>>> escape("< & >")
'< & >'
xml.sax.saxutils 不会转义引号字符 (")
所以这是另一个:
def escape( str_xml: str ):
str_xml = str_xml.replace("&", "&")
str_xml = str_xml.replace("<", "<")
str_xml = str_xml.replace(">", ">")
str_xml = str_xml.replace("\"", """)
str_xml = str_xml.replace("'", "'")
return str_xml
如果你查找它,那么 xml.sax.saxutils 只进行字符串替换
xml.sax.saxutils.escape
仅转义&
、<
和>
,但它确实提供了entities
参数来额外转义其他字符串:
from xml.sax.saxutils import escape
def xmlescape(data):
return escape(data, entities={
"'": "'",
"\"": """
})
xml.sax.saxutils.escape
在内部使用str.replace()
,因此您也可以跳过导入并编写自己的函数,如MichealMoser的答案所示。
你的意思是你做了这样的事情:
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><bar><a/><baz spam="eggs"> & blabla &entity;</></p>'
Andrey Vlasovskikh 接受的答案是对 OP 最完整的答案。但这个主题出现在最频繁搜索
python escape xml
的情况下,我想提供所讨论的三种解决方案的时间比较
在本文中,我们选择部署第四个选项,因为它提供了增强的性能。
所有四个都依赖于本机 python 数据处理或 python 标准库。这些解决方案按性能从最慢到最快的顺序提供。
选项 1 - 正则表达式
此解决方案使用 python 正则表达式库。它产生最慢的性能:
import re
table = {
"<": "<",
">": ">",
"&": "&",
"'": "'",
'"': """,
}
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={"'": "'", '"': """})
>>> %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("&", "&")
txt = txt.replace("<", "<")
txt = txt.replace(">", ">")
txt = txt.replace('"', """)
txt = txt.replace("'", "'")
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({
"<": "<",
">": ">",
"&": "&",
"'": "'",
'"': """,
})
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)
如果您不想导入另一个项目并且您已经有了
cgi
,您可以使用这个:
>>> import cgi
>>> cgi.escape("< & >")
'< & >'
但是请注意,此代码的易读性会受到影响 - 您可能应该将其放入函数中以更好地描述您的意图:(并在执行时为其编写单元测试;)
def xml_escape(s):
return cgi.escape(s) # escapes "<", ">" and "&"
xml_special_chars = {
"<": "<",
">": ">",
"&": "&",
"'": "'",
'"': """,
}
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
不仅接受字符串,还接受函数。
您可以使用自 Python 3.2 起可用的 内置库
import html
clean_txt = html.escape(dirty_txt)
如果已经使用 XSS 库清除了 dirty_txt,则需要先进行转义。
import html
clean_txt = html.escape(html.unescape(dirty_txt))