XML 데이터를 CSV로

XML 데이터를 CSV로

원하는 결과를 얻을 수 없으므로 빠른 도움이 필요합니다.

2020-05-19 19:03:07,135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><TYPE>RCTRFREQ</TYPE><DN1>99847</DN1><AMOUNT>49</AMOUNT></COMMAND> - 
2020-05-19 19:05:07,135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><PE>RC</PE><DN1>92847</DN1><AMOUNT>19</AMOUNT></COMMAND> - 
2020-05-19 19:05:07,135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><DN1>947</DN1><TYPE>RC</TYPE><AMOUNT>29</AMOUNT></COMMAND> - 

원하는 출력:

Time,DN1,AMOUNT
2020-05-19 19:03:07,99847,49
2020-05-19 19:05:07,92847,19
2020-05-19 19:05:07,947,29 

답변1

$ awk '
    BEGIN { FS=",|</?(DN1|AMOUNT)>"; OFS=","; print "Time", "DN1", "AMOUNT" }
    { print $1, $3, $(NF-1) }
' file
Time,DN1,AMOUNT
2020-05-19 19:03:07,99847,49
2020-05-19 19:05:07,92847,19
2020-05-19 19:05:07,947,29

FS위의 코드는 입력을 (예 ,: <DN1>, </DN1>, <AMOUNT>및 ) 에 저장된 정규식과 일치하는 문자열로 구분된 필드로 분할한 </AMOUNT>다음 마지막 첫 번째, 세 번째 및 두 번째 필드를 인쇄하도록 awk에 지시합니다.

위의 내용이 각 레코드를 필드로 분할하는 방법은 다음과 같습니다.

$ awk -F',|</?(DN1|AMOUNT)>' '{print "----" ORS $0; for (i=1;i<=NF;i++) print NR, i "/" NF, $i}' file
----
2020-05-19 19:03:07,135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><TYPE>RCTRFREQ</TYPE><DN1>99847</DN1><AMOUNT>49</AMOUNT></COMMAND> -
1 1/6 2020-05-19 19:03:07
1 2/6 135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><TYPE>RCTRFREQ</TYPE>
1 3/6 99847
1 4/6
1 5/6 49
1 6/6 </COMMAND> -
----
2020-05-19 19:05:07,135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><PE>RC</PE><DN1>92847</DN1><AMOUNT>19</AMOUNT></COMMAND> -
2 1/6 2020-05-19 19:05:07
2 2/6 135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><PE>RC</PE>
2 3/6 92847
2 4/6
2 5/6 19
2 6/6 </COMMAND> -
----
2020-05-19 19:05:07,135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND><DN1>947</DN1><TYPE>RC</TYPE><AMOUNT>29</AMOUNT></COMMAND> -
3 1/6 2020-05-19 19:05:07
3 2/6 135 INFO [Container : 8504] [HttpUtil.java]requestXML: <?xml version="1.0"? ><COMMAND>
3 3/6 947
3 4/6 <TYPE>RC</TYPE>
3 5/6 29
3 6/6 </COMMAND> -

답변2

잘 구성된 행은 다음과 같은 방법으로 구문 분석할 수 있습니다 sed.

sed -En 's|^([^,]+),.*<DN1>(.+)</DN1>.*<AMOUNT>(.+)</AMOUNT>.*|\1,\2,\3|p' file
  • -E확장 정규식 활성화
  • -n읽기 라인의 자동 인쇄 비활성화
  • s|...|___|해당 부분과 일치하는 줄을 검색 ...하고 다음으로 바꿉니다.___
  • ^([^,]+),처음부터 처음까지 맞춰서 ,넣어주세요\1
  • <DN1>(.+)</DN1> matches theDN1 element and puts its content into\2`
  • <AMOUNT>(.+)</AMOUNT>같은 일을AMOUNT
  • \1,\2,\3 교체 결과
  • p일치하는 행이 표준 출력에 인쇄되는지 확인하십시오.

답변3

awk이는 다음 명령을 사용하여 수행할 수 있습니다 sed.

awk 'BEGIN { FS="AMOUNT|,|DN1" ;OFS=","}; {print $1,$3,$5}' xmlfile | sed 's/<\|>\|\///g' > output.csv

답변4

이 상황은 oneliner로 처리하기에는 약간 이상합니다. 저는 XML을 문자열이 아닌 XML 객체로 처리해야 한다고 주장했기 때문에 Python을 선택했습니다. 날짜를 문자열로 구문 분석하고 로드할 XML 문자열을 찾습니다. 이 방법을 사용하면 나중에 XML 또는 입력 행의 다른 필드에서 더 많은 노드에 스크립트를 연결하려는 경우 더 많은 유연성을 얻을 수 있습니다.

스크립트에 전달된 첫 번째 매개변수는 입력 파일입니다.

#!/usr/bin/python

import sys
import xml.etree.ElementTree as ET


def get_lines():

    file_name = str(sys.argv[1])
    f = open(file_name, 'r')

    return f.readlines()


def print_header():

    print("Time,DN1,AMOUNT")


def process_xml(xml):

    doc = ET.ElementTree(ET.fromstring(xml))
    elements = [
            doc.find("DN1").text,
            doc.find("AMOUNT").text
            ]

    return (",").join(elements)


def process_date(line):

    date = line.split()[:2]
    date = " ".join(date).split(",")[0]

    return date


def process_line(line):

    fields = []
    date = process_date(line)
    xml = process_xml(line.split("<?xml version=\"1.0\"? >")[1][:-3])

    fields.append(date)
    fields.append(xml)

    return (",").join(fields)


def process_all(lines):

    print_header()
    for line in lines:
        print(process_line(line))


if __name__ == "__main__":

    lines = get_lines()
    process_all(lines)

관련 정보