我正在努力通过xmltodict将一些XML转换成JSON字符串。基本上,XML重复一组特定的数据,我想提取这些重复的节点中的每个节点,并使其成为所有XML文件中的JSON字符串。我不是在生成此XML,而是从第三方下载它然后进行处理。这是我的简单代码。
my_list = []
for file in os.listdir(download_path):
if file.endswith('.xml'):
with open(os.path.join(download_path, file), encoding = 'utf-8') as xml:
print(file)
things = xmltodict.parse(xml.read())
for thing in things['things']['thing']:
my_list.append(json.dumps(thing))
我遇到了ExpatError: not well-formed (invalid token):
所以我使用Notepad ++调查了XML文件,问题似乎不是常见的罪魁祸首(&,<,>等),而是控制字符。
例如,在Notepad ++中,我得到了一个STX BEL BS
块,它表示错误所在。我以前从未遇到过这些东西,因此经过一番搜索,我发现它们是什么,对于XML来说它们是个坏消息。
所以现在的问题是,我如何摆脱它们或解决它们?我想在上面的代码中构建一些内容,以检查XML并在继续之前对其进行修复,或者在出现时使用Try
和Except
对其进行处理。也许甚至将我指向一些我可以在XML文件上运行的代码,以在通过上述过程运行它之前对其进行修复(我认为一个以上的文件可能会出现此问题)?
我还没有找到任何解决方案可以让我修复XML,但是将其保留为仍可以与xmltodict
一起使用的形式,以便最终获得一些解析的数据,然后可以将其传递给JSON
答案 0 :(得分:1)
这里的答案建立在现有的答案的基础上,但并不假定知道哪些字符是“可打印的”,哪些不是。将其留给Python的标准库来确定:
nonprintable = set([chr(i) for i in range(128)]).difference(string.printable)
filtered_str = "".join([b for b in data if b not in nonprintable])
因此,包含此内容的更新代码如下:
nonprintable = set([chr(i) for i in range(128)]).difference(string.printable)
my_list = []
for file in os.listdir(download_path):
if file.endswith('.xml'):
with open(os.path.join(download_path, file), encoding = 'utf-8') as xml:
print(file)
filtered_xml = "".join([b for b in xml.read() if b not in nonprintable])
things = xmltodict.parse(filtered_xml)
for thing in things['things']['thing']:
my_list.append(json.dumps(thing))
如果您正在谈论大型XML文件,则可以更有效地执行此操作,以避免创建字符数组然后再将其转换回字符串而产生的多余文件副本。除非您真正注意到延迟或遇到内存问题,否则我不必担心。我想你不会。如果内存成为问题,最好在读取文件时进行此转换,而不要先将整个文件读入内存。
答案 1 :(得分:0)
您可以从字符串中过滤掉不可打印的字符:
import string
with open('bad.xml', 'r') as f:
data = f.read()
print('Original')
for c in data:
print(ord(c), c if c in string.printable else '')
filtered_data = ''.join(c for c in data if c in string.printable)
print('Filtered')
for c in filtered_data:
print(ord(c), c if c in string.printable else '')
输出:
Original
2
7
8
60 <
120 x
109 m
108 l
62 >
10
60 <
47 /
120 x
109 m
108 l
62 >
10
Filtered
60 <
120 x
109 m
108 l
62 >
10
60 <
47 /
120 x
109 m
108 l
62 >
10
如果您不想过滤掉所有不可打印的字符,而只过滤特定的字符,则可以使用:
filtered_data = ''.join(c for c in data if c not in (0x2, 0x7, 0x8))
在您的代码中可能看起来像这样:
import string
my_list = []
for file in os.listdir(download_path):
if file.endswith('.xml'):
with open(os.path.join(download_path, file), 'r') as xml:
data = xml.read()
filtered = ''.join(c for c in data if c in string.printable)
print(file)
things = xmltodict.parse(filtered)
for thing in things['things']['thing']:
my_list.append(json.dumps(thing))