【问题标题】:Escaping ampersand and other special characters in XML using Python使用 Python 在 XML 中转义 & 和其他特殊字符
【发布时间】:2020-05-31 07:44:53
【问题描述】:

我必须解析大量 XML 文件并将其写入文本文件。但是,某些 XML 文件包含特殊/非法字符。我尝试过使用不同的方法,例如Escaping strings for use in XML 但我无法让它工作。我知道解决这个问题的一种方法是编辑 XML 文件本身,但是有数千个文件。

import os
from xml.etree import ElementTree
from xml.sax.saxutils import escape

fileNum = 0;
saveFile = open('NewYork_1.txt','w')

for path, dirs, files in os.walk("NewYork_1"):
   for f in files:
      fileName = os.path.join(path, f)
      with open(fileName,'r', encoding='utf-8') as myFile:
        # print(myFile.read())
        if "&" in myFile:
            myFile = myFile.replace("&", "&") #This does not work.

此外,一些 XML 文件中还包含 unicode。有表情符号。

<Thread>
   <ThreadID></ThreadID>
   <Title></Title>
   <InitPost>
      <UserID></UserID>
      <Date></Date>
      <icontent></icontent>
   </InitPost>
   <Post>
      <UserID></UserID>
      <Date></Date>
      <rcontent></rcontent>
  </Post>
</Thread>

【问题讨论】:

  • 你检查print(myFile)了吗?如果你想要这个文件,那么你必须write()它。
  • 您是否有一个表现不佳的 xml 的简短示例?你是如何解析xml的? Unicode 在 xml 中是合法的,表情符号应该不会造成问题。
  • 我的错误。上面的代码只是为了展示我如何解析文件。完整的程序能够写入输出文件。当 XML 文件中有特殊字符时,会报错 xml.etree.ElementTree.ParseError: undefined entity。因此它不会写出完整的结果。
  • 它实际上是一个实体 (&amp;something;) 并且 xml 顶部是否有类似 &lt;?xml version = "1.0" encoding = "UTF-8" standalone = "no" ?&gt; 的声明?举一个例子的原因是为了让我们可以看到有哪些可用的替代方案。
  • 如果将所有"&amp;" 替换为"&amp;#38;",则存在损坏合法xml 实体的风险。

标签: python python-3.x xml xml-parsing elementtree


【解决方案1】:

试试这个:

import os
from xml.etree import ElementTree
from xml.sax.saxutils import escape

fileNum = 0;
saveFile = open('NewYork_1.txt','w')
saveFile.close()
for path, dirs, files in os.walk("NewYork_1"):
   for f in files:
       fileName = os.path.join(path, f)
       with open(fileName,'a', encoding='utf-8') as myFile:
           myFile=myFile.read()
           if "&" in myFile:
                myFile = myFile.replace("&", "&#38;")

我个人会生成一个文件列表来读取和遍历该列表,而不是使用 os.walk(如果您从以前的函数或单独的脚本中获取列表,您总是可以创建一个文本文件,每个txt 文件放在单独的行上并遍历行而不是从变量中获取以节省 RAM),但每个人都有自己的。

不过,正如我所说,我会放弃替换特殊字符的整个想法,并使用 bs4 打开文件,搜索您要查找的元素,然后从那里抓取。

import bs4
list_of_USER_IDs=[]
with open(fileName,'r', encoding='utf-8') as myFile:
    a=myFile.read()
    b=bs4.beautifulSoup(a)
    for elem in b.findAll('USERID'):
        list_of_USER_IDs.append(elem)

这将返回 USERID 标签之间的数据,但它适用于您想要从中获取数据的任何标签。无需直接解析xml。它与 HTML 并没有太大区别,beautifulSoup 就是为此而生的,那么为什么要重新发明轮子呢?

【讨论】:

  • saveFile = open('NewYork_1.txt','w') 不在 with 子句中...并且 str(string) 可能是多余的,但有些机器会将字符串解析为对象.我已经看到即使在某些版本的 python 上使用列表元素也会发生这种情况。例如,for 循环中的“elem[i]”可能可能在没有 str() 的情况下与使用它时表现不同,即使默认情况下采用这种方式的列表元素是一个字符串对象。跨度>
  • MyFile D: ... my_file :D
  • 我假设这两行是在with open(fileName,'r', encoding='utf-8') as myFile: 之后插入的。如果是这样,它会给我一条错误消息。出于某种原因,它给了我 FileNotFoundError: [Errno 2] No such file or directory。奇怪的是当我删除你的代码时它不会给出那个错误。
  • 不太清楚你的意思。 '是撇号的 unicode,所以只需在替换代码中用单引号替换 & 符号,并将 unicode 作为它要替换的内容。如果您不知道特定转义序列指的是什么,请搜索转义序列。例如 $#40;如果您搜索 $#40; 将被翻译为 ( 在谷歌中。为您需要 unicode 的每个字符进行替换。
  • 例如:myFile=myFile.replace("'", "'").replace(")","(")。我认为您在这种情况下使用该反斜杠作为括号。今天有点烧坏了。尝试使用和不使用,看看哪个有效。或者你可以下载一个字符表和它们的 unicode 等价物
【解决方案2】:

还有一件事……

您可以使用 BeautifulSoup 来查找要从中提取数据的 xml 文件的部分。会根据需要错开处理,而不是将整个文件加载到变量中,然后逐个元素地迭代。

例如:

如果你的 xml 文件有如下标签:

<pos reviews>
<review_id>001<review_id>
<reviewer_name>John Stamos (From full house)</reviewer_name>
<review_text>This is a great item</review_text>

您可以只使用 beautifulsoup.findAll(whatever tag) 并获取该数据。不过我不知道你具体在做什么。觉得值得推荐。

【讨论】:

  • 这可能应该是对您其他答案的编辑,不是吗? 会根据需要错开处理,而不是将整个文件加载到一个变量中,然后逐个元素地迭代。 使用 BeautifulSoup 是如何导致这种情况的?
  • BeautifulSoup 打开并读取文档,但仅返回请求的标签。变量占用 RAM,即使它是字符串或整数。想象一下将包含千兆字节数据的 xml 文件加载到变量中。占用的内存比该文件中的几 kb 数据要多。并且迭代该变量会占用处理。更大的变量->更大的处理任务。我最近构建了一个 NLP 程序,严重地使我的处理器负担过重。必须重写 3 次才能让它在我的硬件上正常运行。
  • BeautifulSoup 打开并读取文档,但只返回请求的标签。 我以为所有数据都读入了内存?
  • 也许只要提取信息所需的时间,当然可以。但是假设您将整个文档加载为字符串。不确定它是否甚至将整个内容加载到内存中。我认为 beautifulSoup findALL 只是打开文档并查找实例。在这种情况下,它不会将该文件放入内存中 - 它只是从 ROM 中读取并将搜索到的元素存储到内存中。如果它是一个千兆字节大小的文件,并且您将整个内容加载到一个变量中,那么它在整个程序的其余部分中不必要地在 RAM 中保存了一个千兆字节的数据......
  • 但是假设您将整个文档加载为字符串。不确定它是否甚至将整个内容加载到内存中。 如果将整个文件读入字符串将内容保留在内存中? 我认为beautifulSoup findALL 只是打开文档并查找实例。 我不认为我听说过BeautifulSoup 是这样工作的,你有关于这个主题的任何资源吗?
【解决方案3】:

您可以做的是将文件作为字符串读取。

file_str = open("xml_file.xml", "r+")

然后使用xml.etree.ElementTreefromString函数

tree = xml.etree.ElementTree.fromString(file_str)

然后用它做一些事情。

root = tree.getRoot()

这样您就不必担心为每个表情符号编写代码和无效符号。 如果你想将表情符号和特殊的 utf-8 字符写入 xml,你必须在顶部添加这一行。

 <?xml version="1.0" encoding="utf-8" ?>

【讨论】:

  • 如果我错了,请纠正我。您是否建议将 xml 文件解析为字符串?这样它就可以读取 & 和其他特殊字符?这样就不必解释文件中的单个字符了?
  • 我是说将 xml 文件作为字符串读取。然后将该字符串放入 fromStringFunction。所以基本上像普通文本文件一样阅读它``` file1 = open("myfile.txt","r+") file_str = file1.read() tree = xml.etree.ElementTree.fromString(file_str) root = tree.getRoot () ```
  • 我之前的评论格式很糟糕,抱歉。这就是我想说的,如果你不明白的话。将 XML 文件作为字符串读取 file_str = open("myfile.txt", "r+").read() 然后将其传递给 fromString 函数 tree = xml.etree.ElementTree.fromString(file_str) 然后用它做一些事情root = tree.getRoot() 我也会为你编辑我的答案
  • 是的,没关系,只要您不尝试将所有文​​件读入一个字符串并传递该字符串,因为那样的话,就没有根了,这可能会在以后引起一些问题.但这可以通过在字符串的开头和结尾附加一个根标签来解决。
  • ElementTree 函数的名称是fromstring(全部小写)。如果 XML 内容格式不正确,则将其解析为字符串并不能解决问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-26
  • 1970-01-01
  • 1970-01-01
  • 2018-12-14
相关资源
最近更新 更多