使用 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 中实现了一个解决方案。我所做的是:

  1. 我已经使用 iglob 遍历了这些目录,以便从每个目录中获取 ann_morphosyntax.xml 文件。
  2. 为了解析每个 ann_morphosyntax.xml 文件,我使用了 ElementTree 库。
  3. 我已经将那些 JSON 保存在 output.jsonl 文件中。

解决方案:

要自行尝试此解决方案,请执行以下操作:

  1. 运行这个脚本在你项目根目录的output目录下创建两个文件:example_1.xmlexample_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()

  1. 然后 运行 这个脚本将遍历 example_1.xmlexample_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 名称。