파이썬 XML 처리: 상호 운용 가능한 데이터 관리 가이드
XML은 운영 체제와 개발 언어에 관계없이 다른 애플리케이션에서 읽을 수 있는 애플리케이션을 개발할 수 있게 해주는 휴대 가능하고 오픈 소스 언어입니다.
XML이란?
Extensible Markup Language(XML)는 HTML이나 SGML과 매우 유사한 마크업 언어입니다. 이는 World Wide Web Consortium에서 권장하며 오픈 표준으로 제공됩니다.
XML은 SQL 기반 백본 없이 소량에서 중량의 데이터를 추적하는 데 매우 유용합니다.
XML 파서 아키텍처와 API
파이썬 표준 라이브러리는 XML 작업을 위한 최소하지만 유용한 인터페이스 세트를 제공합니다.
XML 데이터에 대한 가장 기본적이고 널리 사용되는 두 가지 API는 SAX와 DOM 인터페이스입니다.
Simple API for XML (SAX) - 관심 있는 이벤트에 대한 콜백을 등록한 다음 파서가 문서를 진행하도록 합니다. 문서가 크거나 메모리 제약이 있을 때 유용하며, 디스크에서 파일을 읽으면서 파싱하고 전체 파일이 메모리에 저장되지 않습니다.
Document Object Model (DOM) API - World Wide Web Consortium의 권장 사항으로, 전체 파일을 메모리에 읽어 들여 XML 문서의 모든 기능을 나타내는 계층적(트리 기반) 형태로 저장합니다.
SAX는 큰 파일 작업 시 DOM만큼 빠르게 정보를 처리할 수 없습니다. 반면, 많은 작은 파일에 DOM을 독점적으로 사용하면 리소스를 심각하게 소모할 수 있습니다.
SAX는 읽기 전용인 반면 DOM은 XML 파일 변경을 허용합니다. 이 두 가지 다른 API는 문자 그대로 서로를 보완하므로, 대규모 프로젝트에서 둘 다 사용하지 않을 이유가 없습니다.
모든 XML 코드 예제에서 입력으로 간단한 XML 파일 movies.xml을 사용하겠습니다.
<collection shelf="New Arrivals">
<movie title="Enemy Behind">
<type>War, Thriller</type>
<format>DVD</format>
<year>2003</year>
<rating>PG</rating>
<stars>10</stars>
<description>Talk about a US-Japan war</description>
</movie>
<movie title="Transformers">
<type>Anime, Science Fiction</type>
<format>DVD</format>
<year>1989</year>
<rating>R</rating>
<stars>8</stars>
<description>A schientific fiction</description>
</movie>
<movie title="Trigun">
<type>Anime, Action</type>
<format>DVD</format>
<episodes>4</episodes>
<rating>PG</rating>
<stars>10</stars>
<description>Vash the Stampede!</description>
</movie>
<movie title="Ishtar">
<type>Comedy</type>
<format>VHS</format>
<rating>PG</rating>
<stars>2</stars>
<description>Viewable boredom</description>
</movie>
</collection>
SAX API로 XML 파싱하기
SAX는 이벤트 기반 XML 파싱을 위한 표준 인터페이스입니다. SAX로 XML을 파싱하려면 일반적으로 xml.sax.ContentHandler를 서브클래싱하여 자신만의 ContentHandler를 생성해야 합니다.
사용자의 ContentHandler는 사용자 XML 버전의 특정 태그와 속성을 처리합니다. ContentHandler 객체는 다양한 파싱 이벤트를 처리하는 메서드를 제공합니다. 소유 파서는 XML 파일을 파싱하면서 ContentHandler 메서드를 호출합니다.
startDocument와 endDocument 메서드는 XML 파일의 시작과 끝에서 호출됩니다. characters(text) 메서드는 매개변수 text를 통해 XML 파일의 문자 데이터를 전달받습니다.
ContentHandler는 각 요소의 시작과 끝에서 호출됩니다. 파서가 네임스페이스 모드가 아닌 경우 startElement(tag, attributes)와 endElement(tag) 메서드가 호출되고, 그렇지 않으면 해당 startElementNS와 endElementNS 메서드가 호출됩니다. 여기서 tag는 요소 태그이고, attributes는 Attributes 객체입니다.
진행하기 전에 이해해야 할 다른 중요한 메서드들은 다음과 같습니다.
make_parser 메서드
다음 메서드는 새로운 파서 객체를 생성하여 반환합니다. 생성된 파서 객체는 시스템이 찾는 첫 번째 파서 유형이 됩니다.
xml.sax.make_parser([parser_list])
매개변수 세부 정보는 다음과 같습니다.
parse 메서드
다음 메서드는 SAX 파서를 생성하고 이를 사용하여 문서를 파싱합니다.
xml.sax.parse(xmlfile, contenthandler[, errorhandler])
매개변수 세부 정보는 다음과 같습니다.
parseString 메서드
지정된 XML 문자열을 파싱하기 위해 SAX 파서를 생성하는 메서드가 하나 더 있습니다.
xml.sax.parseString(xmlstring, contenthandler[, errorhandler])
매개변수 세부 정보는 다음과 같습니다.
xmlstring - 읽어올 XML 문자열 이름.
contenthandler - ContentHandler 객체여야 합니다.
errorhandler - 지정된 경우 errorhandler는 SAX ErrorHandler 객체여야 합니다.
예제
#!/usr/bin/python
import xml.sax
class MovieHandler(xml.sax.ContentHandler):
def __init__(self):
self.CurrentData = ""
self.type = ""
self.format = ""
self.year = ""
self.rating = ""
self.stars = ""
self.description = ""
# 요소 시작 시 호출
def startElement(self, tag, attributes):
self.CurrentData = tag
if tag == "movie":
print("*****Movie*****")
title = attributes["title"]
print("Title:", title)
# 요소 종료 시 호출
def endElement(self, tag):
if self.CurrentData == "type":
print("Type:", self.type)
elif self.CurrentData == "format":
print("Format:", self.format)
elif self.CurrentData == "year":
print("Year:", self.year)
elif self.CurrentData == "rating":
print("Rating:", self.rating)
elif self.CurrentData == "stars":
print("Stars:", self.stars)
elif self.CurrentData == "description":
print("Description:", self.description)
self.CurrentData = ""
# 문자 읽기 시 호출
def characters(self, content):
if self.CurrentData == "type":
self.type = content
elif self.CurrentData == "format":
self.format = content
elif self.CurrentData == "year":
self.year = content
elif self.CurrentData == "rating":
self.rating = content
elif self.CurrentData == "stars":
self.stars = content
elif self.CurrentData == "description":
self.description = content
if (__name__ == "__main__"):
# XMLReader 파서 생성
parser = xml.sax.make_parser()
# 네임스페이스 끄기
parser.setFeature(xml.sax.handler.feature_namespaces, 0)
# 기본 ContextHandler 오버라이드
Handler = MovieHandler()
parser.setContentHandler(Handler)
parser.parse("movies.xml")
이 코드는 다음과 같은 결과를 출력합니다.
*****Movie*****
Title: Enemy Behind
Type: War, Thriller
Format: DVD
Year: 2003
Rating: PG
Stars: 10
Description: Talk about a US-Japan war
*****Movie*****
Title: Transformers
Type: Anime, Science Fiction
Format: DVD
Year: 1989
Rating: R
Stars: 8
Description: A schientific fiction
*****Movie*****
Title: Trigun
Type: Anime, Action
Format: DVD
Rating: PG
Stars: 10
Description: Vash the Stampede!
*****Movie*****
Title: Ishtar
Type: Comedy
Format: VHS
Rating: PG
Stars: 2
Description: Viewable boredom
SAX API 문서에 대한 자세한 내용은 표준 파이썬 SAX API를 참조하세요.
DOM API로 XML 파싱하기
Document Object Model("DOM")은 World Wide Web Consortium(W3C)에서 제공하는 크로스 랭귀지 API로, XML 문서에 접근하고 수정하기 위한 것입니다.
DOM은 랜덤 액세스 애플리케이션에 매우 유용합니다. SAX는 문서의 한 비트만 한 번에 볼 수 있습니다. 한 SAX 요소를 보고 있으면 다른 요소에 접근할 수 없습니다.
XML 문서를 빠르게 로드하고 xml.dom 모듈을 사용하여 minidom 객체를 생성하는 가장 쉬운 방법은 다음과 같습니다. minidom 객체는 XML 파일로부터 DOM 트리를 빠르게 생성하는 간단한 파서 메서드를 제공합니다.
샘플 구문은 minidom 객체의 parse(file[, parser]) 함수를 호출하여 파일로 지정된 XML 파일을 DOM 트리 객체로 파싱합니다.
#!/usr/bin/python
from xml.dom.minidom import parse
import xml.dom.minidom
# minidom 파서를 사용하여 XML 문서 열기
DOMTree = xml.dom.minidom.parse("movies.xml")
collection = DOMTree.documentElement
if collection.hasAttribute("shelf"):
print("Root element : %s" % collection.getAttribute("shelf"))
# 컬렉션의 모든 영화 가져오기
movies = collection.getElementsByTagName("movie")
# 각 영화의 상세 정보 출력
for movie in movies:
print("*****Movie*****")
if movie.hasAttribute("title"):
print("Title: %s" % movie.getAttribute("title"))
type = movie.getElementsByTagName('type')[0]
print("Type: %s" % type.childNodes[0].data)
format = movie.getElementsByTagName('format')[0]
print("Format: %s" % format.childNodes[0].data)
rating = movie.getElementsByTagName('rating')[0]
print("Rating: %s" % rating.childNodes[0].data)
description = movie.getElementsByTagName('description')[0]
print("Description: %s" % description.childNodes[0].data)
이 코드는 다음과 같은 결과를 출력합니다.
Root element : New Arrivals
*****Movie*****
Title: Enemy Behind
Type: War, Thriller
Format: DVD
Rating: PG
Description: Talk about a US-Japan war
*****Movie*****
Title: Transformers
Type: Anime, Science Fiction
Format: DVD
Rating: R
Description: A schientific fiction
*****Movie*****
Title: Trigun
Type: Anime, Action
Format: DVD
Rating: PG
Description: Vash the Stampede!
*****Movie*****
Title: Ishtar
Type: Comedy
Format: VHS
Rating: PG
Description: Viewable boredom
DOM API 문서에 대한 자세한 내용은 표준 파이썬 DOM API를 참조하세요.