[python] XML , XML 모듈
A A

목차

    728x90

     

    XML ?

    XML은 언어이다.

    XML은 스스로 그렇게 생각하지만 프로그래밍 언어는 아니며 ,

    XML 기반으로 실제 프로그래밍 언어를 구축할 수 있지만 본래의 영역은 아니다.

    XML은 JSON과 마찬가지로 모든 유형의 데이터를 전달하고 보편적이고 투명한 수단이다.

     

    XML을 사용하여 거의 모든 유형의 문서를 저장하고 전송할 수 있다.

    예를 들어 MS Office 애플리케이션에서 생성되는 docx 처럼 x로 끝나는 최신버젼의 문서 형식은 XML을 이용하여

    스프레드 시트나 프레젠테이션, 텍스트와 같은 다양한 데이터를 생성한다.

     

    XML은 JSON보다 훨씬 오래되었다.

    게다가 더 무겁고 유연성이 떨어진다.

    <?xml version = "1.0" encoding = "utf-8"?>
    <!-- cars.xml - List of cars ready to sell -->
    <!DOCTYPE cars_for_sale SYSTEM "cars.dtd">
    <cars_for_sale>
    	<car>
        	<id>1</id>
            <brand>Ford</brand>
            <model>Mustang</model>
            <production_year>1972</production_year>
            <price currency="USD">35900</price>
    	</car>
        <car>
        	<id>2</id>
            <brand>Aston Martin</brand>
            <model>Rapide</model>
            <production_year>2010</production_year>
            <price currency="GBP">32000</price>
    	</car>
    </cars_for_sale>

    위는 간단한 XML 문서 샘플이다.

     

    이러한 문서에 필수적인 요소가 무엇이고 어떻게 생겨먹었는지 살펴보자.

     

    <?xml version = "1.0" encoding = "utf-8"?>

    문서에 XML 텍스트가 포함되는 것을 선언한다.

    <? 와 ?>로 묶여있는 것을 볼 수 있다.

    첫번째 줄에 version과 encoding에 대한 속성을 포함하고 있는데

    말그대로 XML 버전과 텍스트 인코딩 방식을 말한다.

     

    <!-- cars.xml - List of cars ready to sell -->

    주석으로 아무 의미가 없고 XML parser는 이것을 완전히 무시하게 된다.

    주석은 <!-- 와 --> 로 감싸게 된다.

    여러줄에 걸쳐서 사용할 수 있고, 위와 같이 한줄로 표현할 수 도 있다.

     

    <!DOCTYPE cars_for_sale SYSTEM "cars.dtd">

    일반적으로 XML 문서는 두가지 방법으로 작성될 수 있다.

    문서에 내용이 전혀 정의되지 않음 이런 종류의 문서는 자체 정의가 가능하다.
    간단하지만 중요한 기능이 하나도 없다.
    XML parser는 문서에 필요한 모든 데이터가 포함되어있는지 아닌지 여부를 확인할 수 없다.
    문서에 원하는 문서 내용을 설명하는 추가 문서가 포함됨 위의 경우에서 발생하는 문제들을 해결하고
    이러한 도우미를 통해 parser가 문서의 정확성을 완벽하게 검사한다.

    메타 문서는 Document type 에 정의되고 이는 DOCTYPE에 정의된다. 위의 경우  dtd 접미사가 표시된다.

    문서를 외부 정의와 함께 집계하기 위해서는 DOCTYPE줄을 XML 문서 내부에 추가해야한다.

    정의는 어디든 위치할 수 있고, 대상 파싱 서버에 미리 배치하거나 인터넷의 어느 위치에나 배치할 수 있다.

    이 경우 DOCTYPE 줄엔 DTD의 전체 URL , URI가 포함된다.

    cars_for_sale 정의되는 XML 문서의 이름
    SYSTEM XML 1.0에서 가능한 키워드 중 하나로 SYSTEM 또는 PUBLIC을 명명하는데, DTD의 위치를 지정하는 방식에 차이가 있다.

    SYSTEM : DTD 파일이 외부에 존재하며, 그 DTD 파일의 물리적인 위치(URI 또는 URL)를 직접 지정할 때 사용
    <!DOCTYPE root_element PUBLIC "public_id" "uri/url_to_dtd_file.dtd">

    PUBLIC : DTD가 공개적으로(publicly) 알려진 표준 DTD임을 나타낼 때 사용한다. DTD의 실제 물리적 위치를 직접 지정하는 대신, 해당 DTD의 공개 식별자(Public Identifier)와 함께 시스템 식별자(System Identifier, 즉 URI/URL)를 함께 제공한다.
    <!DOCTYPE root_element PUBLIC "public_id" "uri/url_to_dtd_file.dtd">

    DTD는 XML 문서 내용을 완벽하게 설명하기 위해 SGML이라는 특수 언어를 사용한다는 것만 알고 있자.

     

    <cars_for_sale>
    	<car>
        	<id>1</id>
            <brand>Ford</brand>
            <model>Mustang</model>
            <production_year>1972</production_year>
            <price currency="USD">35900</price>
    	</car>
        <car>
        	<id>2</id>
            <brand>Aston Martin</brand>
            <model>Rapide</model>
            <production_year>2010</production_year>
            <price currency="GBP">32000</price>
    	</car>
    </cars_for_sale>

    XML 문서는 요소로 구성되어서 각 요소는 HTML 태그와 같이 여는 태그와 닫는 태그로 구성되어있다.

    값이 빈 요소도 있을 수 있고, 다음과 같이 표현될 수 있다.

    <!-- 빈요소 표현 -->
    
    <!-- 1 -->
    <요소><요소>
    
    <!-- 2 -->
    <요소 />

     

    요소 안에 하위 요소를 넣어 계층적인 표현이 가능하다.

    예시 코드를 보면 해당 요소와 요소의 값을 유추해서 충분히 알 수 있지만, 

    조금 독특한 형태도 볼 수 있다.

    <price currency="GBP">32000</price>

    요소와 요소의 값은 알겠는데 currency는 무엇일까 ?

    바로 요소의 속성이다.

    이것에 대한 표현을 요소로 계층적으로 나누어 표현할 수 있겠지만, 구문 분석이 쉽지 않고 보기 좋지 않다.

    이런 부분에 있어서 효과적이고 이와 같이 필요한 만큼 속성을 넣을 수 있다.

     


    Python에서의 XML

    그렇다면 파이썬에서 XML문서는 어떻게 처리할까 ?

    XML 문서 구조에 가장 적합한 모델은 무엇일까 ?

    충분히 유추해볼 수 있듯 "tree" 모델이며, 수학자나 컴퓨터 과학자들이 말하는 "graph"라고 부르는 모델이다.

    cars_for_sale
    |
    |______car
    |		|_ id : 1
    |		|_ brand: Ford
    |		|_ model: Mustang
    |		|_ production_year: 1972
    |		|_ price(USD): 35900
    |
    |______car
    		|_ id :2
    		|_ brand: Aston Martin
    		|_ model: Rapide
    		|_ production_year: 2010
    		|_ price(USD): 32500

     

     

     

    XML 파일을 생성, 작성, 읽기, 파싱 및 수정을 할 수 있는 다양한 파이썬 도구들이 있다.

    대부분의 도구는 XML 문서를 객체(object)로 구성된 트리 구조로 취급하며, 객체는 요소를 나타낸다.

    # 예제 파일 만들기
    cars = """<?xml version = "1.0" encoding = "utf-8"?>
    <!-- cars.xml - List of cars ready to sell -->
    <!DOCTYPE cars_for_sale SYSTEM "cars.dtd">
    <cars_for_sale>
    	<car>
        	<id>1</id>
            <brand>Ford</brand>
            <model>Mustang</model>
            <production_year>1972</production_year>
            <price currency="USD">35900</price>
    	</car>
        <car>
        	<id>2</id>
            <brand>Aston Martin</brand>
            <model>Rapide</model>
            <production_year>2010</production_year>
            <price currency="GBP">32000</price>
    	</car>
    </cars_for_sale>
    """
    with open("cars.xml", "w") as f:
        f.write(cars)
    import xml.etree.ElementTree as ET
    
    tree = ET.parse('cars.xml')
    root = tree.getroot()
    
    print(root.tag)
    
    for car in root.findall('car'):
        print("\t",car.tag)
        for in_car in car:
            print("\t\t",in_car.tag, end="")
            if in_car.tag == "price":
                print(in_car.attrib, end="")
            print(" =", in_car.text)

    해당 코드를 실행시킨다면 다음과 같은 결과가 나온다.

    tag 속성이 요소 명을 반환하고,

    text 속성이 요소 값을 반환한다.

    그리고 price의 경우 요소에 속성이 지정되어 있었는데, 해당 요소의 속성을 출력하기 위해 attrb라는 속성을 이용하여 출력한 결과가 딕셔너리 형태로 출력되는 것을 알 수 있다.

     

     

    xml.etree.ElementTree 모듈은 XML 파일을 만들고 수정하고 쓰는 데 사용될 수 있다.

    import xml.etree.ElementTree as ET
    
    tree = ET.parse('cars.xml')
    root = tree.getroot()
    
    for car in root.findall('car'):
        if car.find('brand').text == "Aston Martin":
            root.remove(car)
    
    new_cars = ET.Element('car')
    ET.SubElement(new_cars, 'id').text = '3'
    ET.SubElement(new_cars, 'brand').text = 'Audi'
    ET.SubElement(new_cars, 'model').text = 'A4'
    ET.SubElement(new_cars, 'production_year').text = '2018'
    ET.SubElement(new_cars, 'price', {'currency':'EUR'}).text = '45000'
    
    root.append(new_cars)
    tree.write('cars.xml')

    Elemnet 를 생성하는데 car의 인자를 두고 해당 요소를 생성하고,

    car의 하위 요소들의 이름과 text를 지정한다. 요소의 속성이 있는 경우 SubElement의 세번째 인자를 활용하여 담아준다.

    root에 append 하여 담아준 후 parse한 xml 파일을 write한다.

     

    이전 JSON에 비하면 복잡한 것을 확인할 수 있다.

    2025.07.10 - [Developer/Python] - [python] JSON, JSON 모듈

     

    Copyright 2024. GRAVITY all rights reserved