使用 Python 将多个 xml files/links 转换为 JSON?
Converting multiple xml files/links to JSON using Python?
我知道如何使用 xmltodict 将 xml 文件或 link 转换为 python 中的 json。然而,我想知道是否有任何有效的方法可以将多个 xml 文件(按数百甚至数千个)转换为 Python 中的 json?或者,代替 Python,是否还有其他更适合它的工具?请注意,我不是一个非常熟练的程序员,只是偶尔使用 Python。
这取决于您处理的具体案例。
我的例子(背景):
例如,有一次我不得不从包含 3890 个目录的大集合 (1-million-word subcorpus)(大约 2.6 GB)中读取数据,其中有一个 ann_morphosyntax.xml 个文件。
来自 ann_morphosyntax.xml 个文件的片段供参考:
<?xml version="1.0" encoding="UTF-8"?>
<teiCorpus xmlns="http://www.tei-c.org/ns/1.0" xmlns:nkjp="http://www.nkjp.pl/ns/1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="NKJP_1M_header.xml"/>
<TEI>
<xi:include href="header.xml"/>
<text>
<body>
<p corresp="ann_segmentation.xml#segm_1-p" xml:id="morph_1-p">
<s corresp="ann_segmentation.xml#segm_1.5-s" xml:id="morph_1.5-s">
<seg corresp="ann_segmentation.xml#segm_1.1-seg" xml:id="morph_1.1-seg">
<fs type="morph">
<f name="orth">
<string>Jest</string>
</f>
每个 ann_morphosyntax.xml 文件都包含一个或多个对象(为简单起见,假设 段落 )我需要每个转换为 JSON 格式。
这样的 段落 对象以上面 xml 文件片段中的 <p
开头。
此外,还需要将这些 JSON 保存在一个文件中并将该文件的大小减小到尽可能小的大小,因此我决定使用 JSONL 格式。这种文件格式允许您将每个 JSON 存储为该文件的一行而没有任何空格,这最终让我将初始数据集的大小减少到大约 450 MB。
我在 Python 3.6 中实现了一个解决方案。我所做的是:
- 我已经使用 iglob 遍历了这些目录,以便从每个目录中获取 ann_morphosyntax.xml 文件。
- 为了解析每个 ann_morphosyntax.xml 文件,我使用了 ElementTree 库。
- 我已经将那些 JSON 保存在 output.jsonl 文件中。
解决方案:
要自行尝试此解决方案,请执行以下操作:
- 运行这个脚本在你项目根目录的output目录下创建两个文件:example_1.xml 和 example_2.xml:
import os
import xml.etree.ElementTree as ET
def prettify(element, indent=' '):
queue = [(0, element)] # (level, element)
while queue:
level, element = queue.pop(0)
children = [(level + 1, child) for child in list(element)]
if children:
element.text = '\n' + indent * (level+1) # for child open
if queue:
element.tail = '\n' + indent * queue[0][0] # for sibling open
else:
element.tail = '\n' + indent * (level-1) # for parent close
queue[0:0] = children # prepend so children come before siblings
def _create_word_object(sentence_object, number, word_string):
word = ET.SubElement(sentence_object, 'word', number=str(number))
string = ET.SubElement(word, 'string', number=str(number))
string.text = word_string
def create_two_xml_files():
xml_doc_1 = ET.Element('paragraph', number='1')
xml_doc_2 = ET.Element('paragraph', number='1')
sentence_1 = ET.SubElement(xml_doc_1, 'sentence', number='1')
sentence_2 = ET.SubElement(xml_doc_2, 'sentence', number='1')
_create_word_object(sentence_1, 1, 'This')
_create_word_object(sentence_2, 1, 'This')
_create_word_object(sentence_1, 2, 'is')
_create_word_object(sentence_2, 2, 'is')
_create_word_object(sentence_1, 3, 'first')
_create_word_object(sentence_2, 3, 'second')
_create_word_object(sentence_1, 4, 'example')
_create_word_object(sentence_2, 4, 'example')
_create_word_object(sentence_1, 5, 'sentence')
_create_word_object(sentence_2, 5, 'sentence')
_create_word_object(sentence_1, 6, '.')
_create_word_object(sentence_2, 6, '.')
prettify(xml_doc_1)
prettify(xml_doc_2)
tree_1 = ET.ElementTree(xml_doc_1)
tree_2 = ET.ElementTree(xml_doc_2)
os.mkdir('output')
tree_1.write('output/example_1.xml', encoding='UTF-8', xml_declaration=True)
tree_2.write('output/example_2.xml', encoding='UTF-8', xml_declaration=True)
def main():
create_two_xml_files()
if __name__ == '__main__':
main()
- 然后 运行 这个脚本将遍历 example_1.xml 和 example_2.xml 文件(使用 iglob) 并使用第一步创建的两个 XML 文件中的数据创建 output.jsonl 文件(将保存在项目的根目录中):
import os
import glob
import errno
import jsonlines
import xml.etree.ElementTree as ET
class Word:
def __init__(self, word_id, word_text):
self.word_id = word_id
self.word_text = word_text
def create_word_dict(self):
return {"word": {"id": self.word_id, "text": self.word_text}}
def parse_xml(file_path):
for event, element in ET.iterparse(file_path, events=("start", "end",)):
if event == "end":
if element.tag == 'word':
yield Word(element[0].get('number'), element[0].text)
element.clear()
def write_dicts_from_xmls_in_directory_to_jsonlines_file(parsing_generator):
path = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) + '/output/*'
xml_files = glob.iglob(path)
with jsonlines.open('output.jsonl', mode='a') as writer:
for xml_file_name in xml_files:
try:
with open(xml_file_name):
for next_word in parsing_generator(xml_file_name):
writer.write(next_word.create_word_dict())
except IOError as exec:
if exec.errno != errno.EISDIR:
raise
def main():
write_dicts_from_xmls_in_directory_to_jsonlines_file(parse_xml)
if __name__ == '__main__':
main()
output.jsonl 文件将在每一行中包含一个 JSON 对象,表示可以在 [ 中找到的单词元素第一步生成的=109=]和example_2.xml文件。
您可以详细说明该示例并使其更适合您的需要。
P.S.
第一个脚本基于postPretty printing XML in Python
我也有同样的问题
我在 Python 中使用此代码转换一个目录中的多个 xml 文件。
import xmltodict
import os
import json
path = "/home/bjorn/Nedlastinger/Doffin/1/5/"
for filename in os.listdir(path):
if not filename.endswith('.xml'):
continue
fullname = os.path.join(path, filename)
with open(fullname, 'r') as f:
xmlString = f.read()
jsonString = json.dumps(xmltodict.parse(xmlString, process_namespaces=True))
with open(fullname[:-4] + ".json", 'w') as f:
f.write(jsonString)
但它不控制数据类型。所以每个数字都转换为 string
之后你得到一份清理数据的工作。
我已将所有内容加载到 Couchbase 等 NoSQL 服务器中。
Couchbase 中将字符串转换为数字的代码是
UPDATE doffin SET DOFFIN_ESENDERS.FORM_SECTION.CONTRACT_AWARD.FD_CONTRACT_AWARD.AWARD_OF_CONTRACT.CONTRACT_VALUE_INFORMATION.COSTS_RANGE_AND_CURRENCY_WITH_VAT_RATE.VALUE_COST = TONUMBER(DOFFIN_ESENDERS.FORM_SECTION.CONTRACT_AWARD.FD_CONTRACT_AWARD.AWARD_OF_CONTRACT.CONTRACT_VALUE_INFORMATION.COSTS_RANGE_AND_CURRENCY_WITH_VAT_RATE.VALUE_COST);
doffin 是我的 dB 名称。
我知道如何使用 xmltodict 将 xml 文件或 link 转换为 python 中的 json。然而,我想知道是否有任何有效的方法可以将多个 xml 文件(按数百甚至数千个)转换为 Python 中的 json?或者,代替 Python,是否还有其他更适合它的工具?请注意,我不是一个非常熟练的程序员,只是偶尔使用 Python。
这取决于您处理的具体案例。
我的例子(背景):
例如,有一次我不得不从包含 3890 个目录的大集合 (1-million-word subcorpus)(大约 2.6 GB)中读取数据,其中有一个 ann_morphosyntax.xml 个文件。
来自 ann_morphosyntax.xml 个文件的片段供参考:
<?xml version="1.0" encoding="UTF-8"?>
<teiCorpus xmlns="http://www.tei-c.org/ns/1.0" xmlns:nkjp="http://www.nkjp.pl/ns/1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="NKJP_1M_header.xml"/>
<TEI>
<xi:include href="header.xml"/>
<text>
<body>
<p corresp="ann_segmentation.xml#segm_1-p" xml:id="morph_1-p">
<s corresp="ann_segmentation.xml#segm_1.5-s" xml:id="morph_1.5-s">
<seg corresp="ann_segmentation.xml#segm_1.1-seg" xml:id="morph_1.1-seg">
<fs type="morph">
<f name="orth">
<string>Jest</string>
</f>
每个 ann_morphosyntax.xml 文件都包含一个或多个对象(为简单起见,假设 段落 )我需要每个转换为 JSON 格式。
这样的 段落 对象以上面 xml 文件片段中的 <p
开头。
此外,还需要将这些 JSON 保存在一个文件中并将该文件的大小减小到尽可能小的大小,因此我决定使用 JSONL 格式。这种文件格式允许您将每个 JSON 存储为该文件的一行而没有任何空格,这最终让我将初始数据集的大小减少到大约 450 MB。
我在 Python 3.6 中实现了一个解决方案。我所做的是:
- 我已经使用 iglob 遍历了这些目录,以便从每个目录中获取 ann_morphosyntax.xml 文件。
- 为了解析每个 ann_morphosyntax.xml 文件,我使用了 ElementTree 库。
- 我已经将那些 JSON 保存在 output.jsonl 文件中。
解决方案:
要自行尝试此解决方案,请执行以下操作:
- 运行这个脚本在你项目根目录的output目录下创建两个文件:example_1.xml 和 example_2.xml:
import os
import xml.etree.ElementTree as ET
def prettify(element, indent=' '):
queue = [(0, element)] # (level, element)
while queue:
level, element = queue.pop(0)
children = [(level + 1, child) for child in list(element)]
if children:
element.text = '\n' + indent * (level+1) # for child open
if queue:
element.tail = '\n' + indent * queue[0][0] # for sibling open
else:
element.tail = '\n' + indent * (level-1) # for parent close
queue[0:0] = children # prepend so children come before siblings
def _create_word_object(sentence_object, number, word_string):
word = ET.SubElement(sentence_object, 'word', number=str(number))
string = ET.SubElement(word, 'string', number=str(number))
string.text = word_string
def create_two_xml_files():
xml_doc_1 = ET.Element('paragraph', number='1')
xml_doc_2 = ET.Element('paragraph', number='1')
sentence_1 = ET.SubElement(xml_doc_1, 'sentence', number='1')
sentence_2 = ET.SubElement(xml_doc_2, 'sentence', number='1')
_create_word_object(sentence_1, 1, 'This')
_create_word_object(sentence_2, 1, 'This')
_create_word_object(sentence_1, 2, 'is')
_create_word_object(sentence_2, 2, 'is')
_create_word_object(sentence_1, 3, 'first')
_create_word_object(sentence_2, 3, 'second')
_create_word_object(sentence_1, 4, 'example')
_create_word_object(sentence_2, 4, 'example')
_create_word_object(sentence_1, 5, 'sentence')
_create_word_object(sentence_2, 5, 'sentence')
_create_word_object(sentence_1, 6, '.')
_create_word_object(sentence_2, 6, '.')
prettify(xml_doc_1)
prettify(xml_doc_2)
tree_1 = ET.ElementTree(xml_doc_1)
tree_2 = ET.ElementTree(xml_doc_2)
os.mkdir('output')
tree_1.write('output/example_1.xml', encoding='UTF-8', xml_declaration=True)
tree_2.write('output/example_2.xml', encoding='UTF-8', xml_declaration=True)
def main():
create_two_xml_files()
if __name__ == '__main__':
main()
- 然后 运行 这个脚本将遍历 example_1.xml 和 example_2.xml 文件(使用 iglob) 并使用第一步创建的两个 XML 文件中的数据创建 output.jsonl 文件(将保存在项目的根目录中):
import os
import glob
import errno
import jsonlines
import xml.etree.ElementTree as ET
class Word:
def __init__(self, word_id, word_text):
self.word_id = word_id
self.word_text = word_text
def create_word_dict(self):
return {"word": {"id": self.word_id, "text": self.word_text}}
def parse_xml(file_path):
for event, element in ET.iterparse(file_path, events=("start", "end",)):
if event == "end":
if element.tag == 'word':
yield Word(element[0].get('number'), element[0].text)
element.clear()
def write_dicts_from_xmls_in_directory_to_jsonlines_file(parsing_generator):
path = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) + '/output/*'
xml_files = glob.iglob(path)
with jsonlines.open('output.jsonl', mode='a') as writer:
for xml_file_name in xml_files:
try:
with open(xml_file_name):
for next_word in parsing_generator(xml_file_name):
writer.write(next_word.create_word_dict())
except IOError as exec:
if exec.errno != errno.EISDIR:
raise
def main():
write_dicts_from_xmls_in_directory_to_jsonlines_file(parse_xml)
if __name__ == '__main__':
main()
output.jsonl 文件将在每一行中包含一个 JSON 对象,表示可以在 [ 中找到的单词元素第一步生成的=109=]和example_2.xml文件。
您可以详细说明该示例并使其更适合您的需要。
P.S.
第一个脚本基于postPretty printing XML in Python
我也有同样的问题
我在 Python 中使用此代码转换一个目录中的多个 xml 文件。
import xmltodict
import os
import json
path = "/home/bjorn/Nedlastinger/Doffin/1/5/"
for filename in os.listdir(path):
if not filename.endswith('.xml'):
continue
fullname = os.path.join(path, filename)
with open(fullname, 'r') as f:
xmlString = f.read()
jsonString = json.dumps(xmltodict.parse(xmlString, process_namespaces=True))
with open(fullname[:-4] + ".json", 'w') as f:
f.write(jsonString)
但它不控制数据类型。所以每个数字都转换为 string
之后你得到一份清理数据的工作。
我已将所有内容加载到 Couchbase 等 NoSQL 服务器中。 Couchbase 中将字符串转换为数字的代码是
UPDATE doffin SET DOFFIN_ESENDERS.FORM_SECTION.CONTRACT_AWARD.FD_CONTRACT_AWARD.AWARD_OF_CONTRACT.CONTRACT_VALUE_INFORMATION.COSTS_RANGE_AND_CURRENCY_WITH_VAT_RATE.VALUE_COST = TONUMBER(DOFFIN_ESENDERS.FORM_SECTION.CONTRACT_AWARD.FD_CONTRACT_AWARD.AWARD_OF_CONTRACT.CONTRACT_VALUE_INFORMATION.COSTS_RANGE_AND_CURRENCY_WITH_VAT_RATE.VALUE_COST);
doffin 是我的 dB 名称。