Computer >> 컴퓨터 >  >> 프로그래밍 >> Python

파이썬 XML 파싱 완벽 가이드: ElementTree로 XML 생성·수정·읽기

파이썬의 XML 파서는 XML 파일을 읽고 그 안에서 유용한 정보를 추출할 수 있는 가장 쉬운 방법 중 하나를 제공합니다. 이 튜토리얼에서는 파이썬의 ElementTree XML API를 사용해 XML 파일을 파싱하고, 수정하고, 새로 생성하는 방법을 단계별로 살펴보겠습니다.

ElementTree는 XML 데이터를 추출·파싱·변환하는 데 가장 널리 쓰이는 표준 라이브러리로, 별도의 설치 과정 없이 바로 사용할 수 있다는 큰 장점이 있습니다.

그럼 지금부터 파이썬 XML 파서를 ElementTree와 함께 활용하는 방법을 알아보겠습니다.

예제 1: XML 파일 생성하기

새 XML 파일 만들기

먼저 하나의 요소(element)와 하위 요소(sub-element)를 포함하는 새로운 XML 파일을 만들어 보겠습니다.

# 필요한 라이브러리 임포트
import xml.etree.ElementTree as xml

def createXML(filename):
    # 루트(root) 요소부터 시작합니다
    root = xml.Element("users")
    children1 = xml.Element("user")
    root.append(children1)

    tree = xml.ElementTree(root)
    with open(filename, "wb") as fh:
        tree.write(fh)

if __name__ == "__main__":
    createXML("testXML.xml")

위 프로그램을 실행하면 현재 작업 디렉터리에 testXML.xml이라는 새 파일이 생성됩니다.

생성된 파일의 내용은 다음과 같습니다:

<users><user /></users>

여기서 한 가지 주의할 점은, 파일을 저장할 때 'wb' 모드, 즉 바이너리(binary) 모드로 열었다는 것입니다. ElementTree의 write() 메서드는 바이너리 모드로 열린 파일 객체를 기대하기 때문입니다.

XML 요소에 값 추가하기

이번에는 위 프로그램의 XML 요소들에 실제 값을 넣어 보겠습니다. SubElement()를 사용하면 하위 요소를 추가할 수 있고, text 속성으로 값을 지정할 수 있습니다.

# 필요한 라이브러리 임포트
import xml.etree.ElementTree as xml

def createXML(filename):
    # 루트(root) 요소부터 시작합니다
    root = xml.Element("users")
    children1 = xml.Element("user")
    root.append(children1)

    userId1 = xml.SubElement(children1, "Id")
    userId1.text = "hello"

    userName1 = xml.SubElement(children1, "Name")
    userName1.text = "Rajesh"

    tree = xml.ElementTree(root)
    with open(filename, "wb") as fh:
        tree.write(fh)

if __name__ == "__main__":
    createXML("testXML.xml")

프로그램을 실행하면 값이 담긴 새 요소들이 추가된 것을 확인할 수 있습니다:

<users>
    <user>
        <Id>hello</Id>
        <Name>Rajesh</Name>
    </user>
</users>

출력 결과가 정상적으로 잘 나오는 것을 볼 수 있습니다.

이제 기존 XML 파일을 불러와 데이터를 수정하는 방법을 살펴보겠습니다.

XML 데이터 편집하기

다음과 같은 XML 파일이 있다고 가정해 보겠습니다.

newdata.xml

<users>
    <user>
        <id>1a</id>
        <name>Rajesh</name>
        <salary>NA</salary>
    </user>
    <user>
        <id>2b</id>
        <name>TutorialsPoint</name>
        <salary>NA</salary>
    </user>
    <user>
        <id>3c</id>
        <name>Others</name>
        <salary>NA</salary>
    </user>
</users>

위 XML 파일에서 각 사용자(user)의 salary(급여) 값을 일괄적으로 업데이트해 보겠습니다. iter() 메서드를 사용하면 특정 태그 이름을 가진 모든 요소를 한 번에 순회할 수 있습니다.

# 필요한 라이브러리 임포트
import xml.etree.ElementTree as ET

def updateET(filename):
    # 루트(root) 요소부터 시작합니다
    tree = ET.ElementTree(file=filename)
    root = tree.getroot()

    # 모든 salary 태그를 순회하며 값을 변경합니다
    for salary in root.iter('salary'):
        salary.text = '500000'

    tree = ET.ElementTree(root)
    with open("newdata.xml", "wb") as fh:
        tree.write(fh)

if __name__ == "__main__":
    updateET("newdata.xml")

실행 결과

프로그램 실행 후 파일을 확인해 보면, 모든 salary 값이 'NA'에서 '500000'으로 변경된 것을 볼 수 있습니다.

예제: 파이썬 XML 파서로 데이터 읽기

이번에는 파일에 저장된 XML 데이터를 파싱(parse)해서 화면에 출력하는 또 다른 프로그램을 작성해 보겠습니다.

# 필요한 라이브러리 임포트
import xml.etree.cElementTree as ET

def parseXML(file_name):
    # ElementTree로 XML을 파싱합니다
    tree = ET.ElementTree(file=file_name)
    print(tree.getroot())
    root = tree.getroot()
    print("tag=%s, attrib=%s" % (root.tag, root.attrib))

    # 자식 요소를 통해 정보를 가져옵니다!
    print("-" * 25)
    print("getchildren()으로 순회합니다")
    print("-" * 25)
    users = root.getchildren()
    for user in users:
        user_children = user.getchildren()
        for user_child in user_children:
            print("%s=%s" % (user_child.tag, user_child.text))

if __name__ == "__main__":
    parseXML("newdata.xml")

실행 결과

<Element 'users' at 0x0551A5A0>
tag = users, attrib = {}
-------------------------
Iterating using getchildren()
-------------------------
id = 1a
name = Rajesh
salary = 500000
id = 2b
name = TutorialsPoint
salary = 500000
id = 3c
name = Others
salary = 500000

루트 요소의 태그 이름(users)과 속성(attrib)이 먼저 출력되고, 이어서 각 user 요소의 자식 태그(id, name, salary)와 그 값들이 순서대로 화면에 표시됩니다.

참고: 최신 파이썬 버전에서의 주의사항

위 예제에서 사용된 getchildren() 메서드는 파이썬 3.2에서 폐기(deprecated)되었으며, 파이썬 3.9부터는 완전히 제거되었습니다. 최신 버전에서는 요소를 리스트처럼 직접 순회하는 방식이 권장됩니다:

for user in root:          # users 아래의 모든 user 요소
    for child in user:     # 각 user의 자식 요소(id, name, salary)
        print("%s=%s" % (child.tag, child.text))

또한 xml.etree.cElementTree 모듈 역시 폐기된 상태이므로, 항상 xml.etree.ElementTree를 사용하는 것이 좋습니다.