用Python转义XML中的未转义字符
我需要处理一个大约5000行的无效XML文件,里面有一些特殊字符需要转义。这里有一个我需要处理的XML示例:
<root>
<element>
<name>name & surname</name>
<mail>name@name.org</mail>
</element>
</root>
问题在于名字中的字符"&"。我该如何使用Python库来转义这样的特殊字符呢?我在BeautifulSoup中没有找到解决办法。
4 个回答
0
这个回答提供了一些XML清理的功能,不过它们并不是把未转义的字符处理成安全的形式,而是直接把这些字符丢掉了。
使用bs4和lxml
这个问题是想知道如何用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://stackoverflow.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
显然,如果只用 lxml
就能完成的事情,使用 bs4
和 lxml
一起就没什么意义了。这个使用清理功能的 lxml==4.4.0
是基本上来源于 jfs的回答。
import lxml.etree
def sanitize_xml(content: bytes) -> bytes:
# Ref: https://stackoverflow.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
1
你可能只是想在把HTML放进BeautifulSoup之前,先对它做一些简单的正则表达式处理。
其实更简单的是,如果代码里没有SGML实体(像&...;
这样的),你可以用html=html.replace('&','&')
来解决这个问题。
如果有的话,可以试试这个:
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
基本上,这个正则表达式是用来查找&
后面没有跟字母、数字或#字符的情况。它不会处理行末的&符号,但这个问题应该可以解决。
10
如果你不在乎 XML 中的无效字符,可以使用 XML 解析器的 recover
选项(详细内容可以查看 使用 lxml.etree.iterparse 解析损坏的 XML):
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>