使用 Python 转义 XML 中的未转义字符
Posted
技术标签:
【中文标题】使用 Python 转义 XML 中的未转义字符【英文标题】:Escape unescaped characters in XML with Python 【发布时间】:2011-06-25 17:24:39 【问题描述】:我需要在大约 5000 行长的无效 XML 文件中转义特殊字符。这是我必须处理的 XML 示例:
<root>
<element>
<name>name & surname</name>
<mail>name@name.org</mail>
</element>
</root>
这里的问题是名称中的字符“&”。你将如何使用 Python 库转义这样的特殊字符?我没有找到使用BeautifulSoup 的方法。
【问题讨论】:
【参考方案1】:如果您不关心 xml 中的无效字符,您可以使用 XML 解析器的 recover
选项(请参阅 Parsing broken XML with lxml.etree.iterparse):
from lxml import etree
parser = etree.XMLParser(recover=True) # recover from bad characters.
root = etree.fromstring(broken_xml, parser=parser)
print etree.tostring(root)
输出
<root>
<element>
<name>name surname</name>
<mail>name@name.org</mail>
</element>
</root>
【讨论】:
最后我使用了 lxml.html.soupparser 的 parse 方法:它可以解析我丑陋的 xml 而不会哭:) 谢谢你的回答 这个答案虽然有用,但不会转义未转义的字符。它显然会简单地丢弃它们。【参考方案2】:您可能只是想在将 HTML 放入 BeautifulSoup 之前对其进行一些简单的正则表达式。
更简单的是,如果代码中没有任何 SGML 实体 (&...;
),html=html.replace('&','&amp;')
就可以解决问题。
否则,试试这个:
x ="<html><h1>Fish & Chips & Gravy</h1><p>Fish & Chips & Gravy</p>"
import re
q=re.sub(r'&([^a-zA-Z#])',r'&\1',x)
print q
本质上,正则表达式查找&
,后面没有字母数字或# 字符。它不会处理行尾的 & 符号,但这可能是可以修复的。
【讨论】:
【参考方案3】:<name>name & surname</name>
不是格式良好的 XML。应该是:
<name>name & surname</name>
所有符合标准的 XML 工具都应该创建它——您通常不必担心。如果您使用“&”字符创建字符串,则 XML 工具将输出转义版本。如果您手动创建字符串,您有责任确保它被转义。如果您使用 XML 编辑器,它应该为您转义它。
如果文件是由其他人提供给您的,请将其发回并告诉他们格式不正确。如果它们不再存在,您将不得不使用纯文本编辑器。那是脆弱和混乱的,但没有其他办法。如果文件在其他地方有用于转义的 & 符号,则该文件是垃圾。
查看 10 年前的帖子 here 和后来的帖子 here。
【讨论】:
xml 是由一个名为 metamig 的 Novell 工具生成的:它从 nss 服务器 导出受托人:有带有 & 字符的文件夹,所以我必须转义所有这些文件才能正确解析文件 Assuning 你已经正确引用它是 PSEUDO-xml。我不知道这个工具,但如果你正确地报告了它,它就永远不会出来。这是错误的。如果您为此付钱,请要求退还您的钱。 谢谢彼得,我不知道 '&' 应该在正确的 XML 文件中转义。你帮我研究了为什么 Python ElementTree 没有显示 '&' 字符【参考方案4】:这个答案提供了 XML sanitizer 函数,尽管它们不会转义未转义的字符,而是简单地删除它们。
在 lxml 中使用 bs4
这个问题想知道如何用 Beautiful Soup 来做到这一点。这是一个函数,它将用它清理一个小的 XML bytes
对象。它已根据包装要求 beautifulsoup4==4.8.0
和 lxml==4.4.0
进行了测试。请注意,bs4
此处需要 lxml
。
import xml.etree.ElementTree
import bs4
def sanitize_xml(content: bytes) -> bytes:
# Ref: https://***.com/a/57450722/
try:
xml.etree.ElementTree.fromstring(content)
except xml.etree.ElementTree.ParseError:
return bs4.BeautifulSoup(content, features='lxml-xml').encode()
return content # already valid XML
仅使用 lxml
很明显,同时使用bs4
和lxml
并没有多大意义,因为这可以单独使用lxml
。这个lxml==4.4.0
使用sanitizer函数本质上是从answer by jfs派生的。
import lxml.etree
def sanitize_xml(content: bytes) -> bytes:
# Ref: https://***.com/a/57450722/
try:
lxml.etree.fromstring(content)
except lxml.etree.XMLSyntaxError:
root = lxml.etree.fromstring(content, parser=lxml.etree.XMLParser(recover=True))
return lxml.etree.tostring(root)
return content # already valid XML
【讨论】:
以上是关于使用 Python 转义 XML 中的未转义字符的主要内容,如果未能解决你的问题,请参考以下文章