끄적거림

xml 접근 및 CSV파일로 변환 본문

Python

xml 접근 및 CSV파일로 변환

Signing 2020. 4. 16. 14:48
728x90
반응형

XML은 가장 잘 알려진 markup 형식의 데이터이다.

데이터를 구분하기 위해 tag라는 개념을 사용하는데 이는 html과 비슷하다고 생각하면 된다.

 

 

1. XML 접근

아래 간단한 xml 파일을 하나 가져왔다. 샘플 xml데이터를 보면서 그 특징을 알아보자.

만약 큰 xml 파일(예를 들어 GB단위의 큰 데이터)을 찾아봐야할 경우가 생기면 이 사이트에서 gvim 프로그램을 다운 받아 사용해보자. 시간이 다소 걸리긴 하지만 그래도 다른 에디터에 비해 빠른 편이고 유용한 편이다.

인코딩 문제가 있다면, 프로그램을 실행시키고

:set encoding=utf8
<?xml version="1.0"?>
<data>
    <country name="Liechtenstein">
        <rank>1</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank>4</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Panama">
        <rank>68</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>
  • 일반적으로 <data>, </data> 와 같은 테그를 시작(start), 끝(end) 테그라고 하며 그 사이에 내용이 들어간다.
  • tag 안에 tag를 중첩시킬 수 있다.
  • 계층적 하위 구조로 만들 수 있다.(하위 tag를 자식 tag라고 한다.)
  • 속성(attrib)은 시작 태그에 나올 수 있다.
    • e.g. <neighbor name="~~" direction="N"/>에서 attrib은 neighbor이다.
  • 각 tag는 값(value)를 가질 수 있다.
    • e.g. <year>2008</year>에서 2008이 값이다.
  • 테그에 값이나 자식이 없다면, <example/> 이런 식으로 단일 테그로 표현 가능하다.

 

 

그럼 python으로 한 번 읽어보자.

(보통 xml은 API와 같은 전송 플랫폼을 통하여 데이터를 주고 받을 때, 많이 사용하기도 하지만 본 글에서는 임의의 로컬 파일로 만들어 사용하겠다.)

 

 

1.1. 1st Depth

일단 depth에 있는 테그부터 순회해보겠다. 기본적으로 xml.etree.ElementTree 모듈을 사용하겠다.

(해당 모듈에 대한 자세한 설명은 여기에 있다.)

아무래도 계층적 구조이므로 직관적인 tree 구조를 활용하고 또 이름 또한 그렇게 명명한 것을 알 수 있다.

import xml.etree.ElementTree as et
tree = et.ElementTree(file = "C:/Users/~~~/sample.xml")
root = tree.getroot()

for child in root:
    print("tag : ",child.tag,"\t Attr : " ,child.attrib['name'])
    

# tag :  country 	 Attr :  Liechtenstein
# tag :  country 	 Attr :  Singapore
# tag :  country 	 Attr :  Panama

위의 코드와 원본 xml 데이터를 확인해보면, 첫 번째에 있는 자식 테그는 country임을 알 수 있다.

 

첫 번째로, 해당 파일을 ElementTree 함수를 사용하여 읽고 객체로 만든다.

두 번째로, 객체의 root를 찾아내는 getroot() 함수를 사용해 root를 찾는다.

root에 속한 각 1 depth의 child들을 순회하면서 각 child의 tag와 attrib를 출력해본다.

 

 

1.2. 2nd Depth

두번째 depth에 있는 내용을 얻기 위해서는 상식적으로 두번의 loop를 돌면 될 것 같다는 느낌이 온다.

물론 그렇게 할 수 있다.

for child in root:
    print("tag : ",child.tag,"\t Attr : " ,child.attrib['name'])
    for grandChild in child:
        print("\ttag : ",grandChild.tag,"\t Attr : " ,grandChild.attrib)

# tag :  country 	 Attr :  Liechtenstein
# 	tag :  rank 	 Attr :  {}
# 	tag :  year 	 Attr :  {}
# 	tag :  gdppc 	 Attr :  {}
# 	tag :  neighbor 	 Attr :  {'name': 'Austria', 'direction': 'E'}
# 	tag :  neighbor 	 Attr :  {'name': 'Switzerland', 'direction': 'W'}
# tag :  country 	 Attr :  Singapore
# 	tag :  rank 	 Attr :  {}
# 	tag :  year 	 Attr :  {}
# 	tag :  gdppc 	 Attr :  {}
# 	tag :  neighbor 	 Attr :  {'name': 'Malaysia', 'direction': 'N'}
# tag :  country 	 Attr :  Panama
# 	tag :  rank 	 Attr :  {}
# 	tag :  year 	 Attr :  {}
# 	tag :  gdppc 	 Attr :  {}
# 	tag :  neighbor 	 Attr :  {'name': 'Costa Rica', 'direction': 'W'}
# 	tag :  neighbor 	 Attr :  {'name': 'Colombia', 'direction': 'E'}

하지만 이렇게 이중루프를 사용하면 느낌적으로 기분이 좋지 않다.

어떤 문제가 있을까?

바로 O(n^2)이 된다는 문제가 있다. 이는 시간복잡도로 데이터의 양이 증가하거나 다양해질수록 굉장한 리소스 낭비를 초래한다.

 

 

 

그렇다면 어떻게 해야할까?

 

 

 

for child in root.findall("country"):
    print("rank: ", child.find("rank").text)

# rank:  1
# rank:  4
# rank:  68

위의 코드와 같이 root의 findall()이라는 함수를 사용하면 단일루프를 사용할 수 있을 뿐 아니라 코드의 가독성과 간편성부분에서도 크게 향상됨을 알 수 있다.

 

물론 같은 테그와 같은 구조의 하위 계층이 존재해야지 좀 더 효율적인 순회를 할 수가 있다.

 

 

 

그러면 <neighbor> tag에 들어있는 값에 접근하려면?

 

 

for child in root.findall("country"):
    print(child.find("neighbor").attrib)

# {'name': 'Austria', 'direction': 'E'}
# {'name': 'Malaysia', 'direction': 'N'}
# {'name': 'Costa Rica', 'direction': 'W'}

내가 원하는 테그를 접근하고 그 하위의 attrib를 지정해주면 된다.

 

 

 

 

 


 

 

1. Convert XML  to CSV

방법을 찾기위해 stackoverflow를 살펴보았지만 뭔가 와닿을만한 내용이 없었다.

(예를 들면 xml을 json으로 바꾸고 다시 csv로 바꾸라는... 심지어 코딩이 아닌 특정 변환 플랫폼을 활용하여..)

 

 

 

 

 

 

728x90
반응형
Comments