xml을 json으로 변환하는 스크립트

xml을 json으로 변환하는 스크립트

다음과 같은 txt 파일에 5000개의 질문이 있습니다.

<quiz>
        <que>The question her</que>
        <ca>text</ca>
        <ia>text</ia>
        <ia>text</ia>
        <ia>text</ia>
    </quiz>

모든 문제를 다음과 같이 변환하기 위해 Ubuntu에서 스크립트를 작성하고 싶습니다.

  {
   "text":"The question her",
   "answer1":"text",
   "answer2":"text",
   "answer3":"text",
   "answer4":"text"
  },

답변1

실제로 Python 프로그래밍 없이도 2개의 Unix 유틸리티만 사용하면 이 문제를 해결할 수 있습니다.

  1. jtm- xml <-> json의 무손실 변환 허용
  2. jtc- JSON 조작을 허용합니다.

따라서 XML이 file.xmljtm에 있다고 가정하면 이를 다음 json으로 변환합니다.

bash $ jtm file.xml 
[
   {
      "quiz": [
         {
            "que": "The question her"
         },
         {
            "ca": "text"
         },
         {
            "ia": "text"
         },
         {
            "ia": "text"
         },
         {
            "ia": "text"
         }
      ]
   }
]
bash $ 

그런 다음 일련의 JSON 변환을 적용하면 원하는 결과를 얻을 수 있습니다.

bash $ jtm file.xml | jtc -w'<quiz>l:[1:][-2]' -ei echo { '"answer[-]"': {} }\; -i'<quiz>l:[1:]' | jtc -w'<quiz>l:[-1][:][0]' -w'<quiz>l:[-1][:]' -s | jtc -w'<quiz>l:' -w'<quiz>l:[0]' -s | jtc -w'<quiz>l: <>v' -u'"text"'
[
   {
      "answer1": "text",
      "answer2": "text",
      "answer3": "text",
      "answer4": "text",
      "text": "The question her"
   }
]
bash $ 

그러나 관련된 쉘 스크립트(명령)가 있기 때문에 echoPython보다 느릴 것입니다. 5000개의 질문에 대해서는 약 1분 안에 실행될 것으로 예상됩니다. (향후 버전에서는 jtc정적으로 지정된 JSON에서도 보간을 허용할 예정이므로 템플릿 작성에 외부 쉘 스크립트가 필요하지 않고 작업 속도가 매우 빨라질 것입니다)

구문에 대해 궁금한 경우 jtc여기에서 사용자 가이드를 찾을 수 있습니다.https://github.com/ldn-softdev/jtc/blob/master/User%20Guide.md

답변2

xq도구는 다음에서 제공됩니다.https://kislyuk.github.io/yq/XML을 다음으로 바꾸십시오.

{
  "quiz": {
    "que": "The question her",
    "ca": "text",
    "ia": [
      "text",
      "text",
      "text"
    ]
  }
}

ID 필터( xq . file.xml)를 사용하면 됩니다.

사용하고 싶은 형태에 가까운 형태로 마사지해 드립니다.

xq '.quiz | { text: .que, answers: .ia }' file.xml

어느 출력

{
  "text": "The question her",
  "answers": [
    "text",
    "text",
    "text"
  ]
}

answers열거형 키를 얻기 위해 이 비트를 수정하려면 :

xq '.quiz |
    { text: .que } +
    (
        [
            range(.ia|length) as $i | { key: "answer\($i+1)", value: .ia[$i] }
        ] | from_entries
    )' file.xml

이는 노드를 반복하고 키와 값 세트를 수동으로 생성하여 answer노드의 열거형 키와 값을 추가합니다. 그런 다음 이를 사용하여 실제 키 값 쌍으로 변환하고 우리가 만든 원본 개체( )에 추가합니다.iaiafrom_entries{ text: .que }

산출:

{
  "text": "The question her",
  "answer1": "text",
  "answer2": "text",
  "answer3": "text"
}

XML 문서에 quiz특정 루트 노드 아래에 여러 노드가 포함되어 있는 경우 위의 표현식을 변경하여 .quiz각 노드를 변환하고 결과 개체를 배열에 넣을 수 있습니다.jq.[].quiz[]

xq '.[].quiz[] |
    [ { text: .que } +
    (
        [
            range(.ia|length) as $i | { key: "answer\($i+1)", value: .ia[$i] }
        ] | from_entries
    ) ]' file.xml

답변3

귀하의 우분투에는 이미 Python이 설치되어 있다고 가정합니다.

#!/usr/bin/python3
import io
import json
import xml.etree.ElementTree

d = """<quiz>
        <que>The question her</que>
        <ca>text</ca>
        <ia>text</ia>
        <ia>text</ia>
        <ia>text</ia>
    </quiz>
"""

s = io.StringIO(d)
# root = xml.etree.ElementTree.parse("filename_here").getroot()
root = xml.etree.ElementTree.parse(s).getroot()
out = {}
i = 1
for child in root:
    name, value = child.tag, child.text
    if name == 'que':
        name = 'question'
    else:
        name = 'answer%s' % i
        i += 1
    out[name] = value

print(json.dumps(out))

그것을 저장하고 chmod텍스트 대신 파일을 입력으로 사용하도록 쉽게 수정할 수 있는 실행 파일로 저장합니다.

편집하다 좋습니다. 더 완전한 스크립트는 다음과 같습니다.

#!/usr/bin/python3
import json
import sys
import xml.etree.ElementTree


def read_file(filename):
    root = xml.etree.ElementTree.parse(filename).getroot()
    return root


# assule we have a list of <quiz>, contained in some other element
def parse_quiz(quiz_element, out):
    i = 1
    tmp = {}
    for child in quiz_element:

        name, value = child.tag, child.text
        if name == 'que':
            name = 'question'
        else:
            name = 'answer%s' % i
            i += 1
        tmp[name] = value
    out.append(tmp)


def parse_root(root_element, out):
    for child in root_element:
        if child.tag == 'quiz':
            parse_quiz(child, out)


def convert_xml_to_json(filename):
    root = read_file(filename)
    out = []
    parse_root(root, out)
    print(json.dumps(out))


if __name__ == '__main__':
    if len(sys.argv) > 1:
        convert_xml_to_json(sys.argv[1])
    else:
        print("Usage: script <filename_with_xml>")

다음 내용으로 파일을 만들었습니다 xmltest. 이름은 다음과 같습니다.

<questions>
    <quiz>
        <que>The question her</que>
        <ca>text</ca>
        <ia>text</ia>
        <ia>text</ia>
        <ia>text</ia>
    </quiz>
     <quiz>
            <que>Question number 1</que>
            <ca>blabla</ca>
            <ia>stuff</ia>
    </quiz>
</questions>

quiz따라서 다른 컨테이너 안에 목록이 있습니다.

$ chmod u+x scratch.py이제 다음 과 같이 시작합니다. scratch.py filenamewithxml

이것은 나에게 대답을 주었다:

$ ./scratch4.py xmltest
[{"answer3": "text", "answer2": "text", "question": "The question her", "answer4": "text", "answer1": "text"}, {"answer2": "stuff", "question": "Question number 1", "answer1": "blabla"}]

답변4

감사합니다 dgan, 하지만 귀하의 코드: 1은 json 파일 대신 화면에 출력을 인쇄하고 인코딩=utf-8을 지원하지 않으므로 변경했습니다.

 ##!/usr/bin/python3
import json, codecs
import sys
import xml.etree.ElementTree


def read_file(filename):
    root = xml.etree.ElementTree.parse(filename).getroot()
    return root


# assule we have a list of <quiz>, contained in some other element
def parse_quiz(quiz_element, out):
    i = 1
    tmp = {}
    for child in quiz_element:

        name, value = child.tag, child.text
        if name == 'que':
            name = 'question'
        else:
            name = 'answer%s' % i
            i += 1
        tmp[name] = value
    out.append(tmp)


def parse_root(root_element, out):
    for child in root_element:
        if child.tag == 'quiz':
            parse_quiz(child, out)


def convert_xml_to_json(filename):
    root = read_file(filename)
    out = []
    parse_root(root, out)
    with open('data.json', 'w') as outfile:
        json.dump(out, codecs.getwriter('utf-8')(outfile), sort_keys=True, ensure_ascii=False)


if __name__ == '__main__':
    if len(sys.argv) > 1:
        convert_xml_to_json(sys.argv[1])
    else:
        print("Usage: script <filename_with_xml>")

`

관련 정보