使用 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 实体 (&amp;...;),html=html.replace('&amp;','&amp;amp;') 就可以解决问题。

否则,试试这个:

x ="<html><h1>Fish & Chips & Gravy</h1><p>Fish &amp; Chips &#x0026; Gravy</p>"
import re
q=re.sub(r'&([^a-zA-Z#])',r'&amp;\1',x)
print q

本质上,正则表达式查找&amp;,后面没有字母数字或# 字符。它不会处理行尾的 & 符号,但这可能是可以修复的。

【讨论】:

【参考方案3】:
<name>name & surname</name>

不是格式良好的 XML。应该是:

<name>name &amp; 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.0lxml==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

很明显,同时使用bs4lxml 并没有多大意义,因为这可以单独使用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 中的未转义字符的主要内容,如果未能解决你的问题,请参考以下文章

使用正则表达式查找 C# 样式的未转义字符串

(转)XML中必须进行转义的字符

请求路径包含 axios 获取请求上的未转义字符

如何转义xml中的特殊字符

XML中的转义字符

转义字符串以在 XML 中使用