XML 파일을 그냥 읽으면 parsing되지않고, 모두 이어진 텍스트로 읽혀 가독성이 매우 좋지않다.
이를 가독성 좋게 읽기 위해서는 우선 python에서 지원하는 xml parsing 도구를 사용할 수 있다.
보편적으로 아래와 같은 코드로 xml 파일을 읽어들이게 된다.
import xml.etree.ElementTree as ET
tree = ET.parse(xml_path)
root = tree.getroot()
아래의 코드로 root에 저장된 내용을 각 계층에 맞게 출력해주면 가독성 좋은 텍스트로 출력할 수 있다.
def print_xml_structure(elem, level=0):
indent = '\t' * level
print(f"{indent}<{elem.tag}", end='')
if elem.attrib:
print(" " + " ".join([f'{k}="{v}"' for k, v in elem.attrib.items()]), end="")
# Print closing bracket
print(">")
if elem.text:
print(f"{indent} {elem.text.strip()}")
# 재귀적으로 호출하여 모든 계층의 자식노드까지 출력해준다.
for child in elem:
print_xml_structure(child, level+1)
print(f"{indent}</{elem.tag}>")
print_xml_structure(root)
가독성 좋은 xml
더보기
<annotation>
<folder>
OXIIIT
</folder>
<filename>
Abyssinian_1.jpg
</filename>
<source>
<database>
OXFORD-IIIT Pet Dataset
</database>
<annotation>
OXIIIT
</annotation>
<image>
flickr
</image>
</source>
<size>
<width>
600
</width>
<height>
400
</height>
<depth>
3
</depth>
</size>
<segmented>
0
</segmented>
<object>
<name>
cat
</name>
<pose>
Frontal
</pose>
<truncated>
0
</truncated>
<occluded>
0
</occluded>
<bndbox>
<xmin>
333
</xmin>
<ymin>
72
</ymin>
<xmax>
425
</xmax>
<ymax>
158
</ymax>
</bndbox>
<difficult>
0
</difficult>
</object>
</annotation>
여기에서 만약에 바로 xmin, ymin 과 같은 자식노드의 텍스트를 바로 접근하여 추출하고 싶다면 어떻게 할 수 있을까?
그럴 때는 아래와 같이 tag의 경로를 통해 바로 접근할 수 있다.
def find_text_by_tag(root, tag_name):
# Find all elements with the specified tag
elements = root.findall(f".//{tag_name}")
# Extract and return the text of each element
return [elem.text for elem in elements if elem is not None]
tag_names = ['xmin', 'ymin', 'xmax', 'ymax']
bbox = [int(find_text_by_tag(root, tag_name)[0]) for tag_name in tag_names]
bbox
# [333, 72, 425, 158]
그렇다면 findall에 들어가는 경로 문자열은 어떤 규칙을 입력할 수 있을까?
이 때 XPath가 사용된다. XML 문서 내의 특정 부분을 선택하거나 검색할 때 사용되는 언어이다. 경로 표현식(path expression)을 사용해서 XML 문서의 노드(node)를 선택하게 된다.
XPath 기본 문법과 형식
기본 구문
- /: 루트 노드를 선택합니다.
- //: 현재 노드의 자손 노드 중 모든 노드를 선택합니다.
- .: 현재 노드를 선택합니다.
- ..: 현재 노드의 부모 노드를 선택합니다.
- @: 속성을 선택합니다.
예제 XML
더보기
<library>
<section>
<shelf>
<book>
<title>Python Programming</title>
<author>John Doe</author>
<year>2020</year>
<info>
<publisher>XYZ Press</publisher>
<isbn>1234567890</isbn>
</info>
</book>
</shelf>
</section>
<section>
<shelf>
<book>
<title>Data Science Handbook</title>
<author>Jane Smith</author>
<year>2018</year>
<info>
<publisher>ABC Press</publisher>
<isbn>0987654321</isbn>
</info>
</book>
</shelf>
</section>
</library>
예제 XPath 표현식
더보기
- 루트 노드 선택:
- /library: 루트 노드인 library를 선택합니다.
- 모든 section 노드 선택:
- //section: 문서 내의 모든 section 노드를 선택합니다.
- 첫 번째 book 노드의 title 선택:
- /library/section/shelf/book/title: 첫 번째 book 노드의 title 요소를 선택합니다.
- 모든 title 요소 선택:
- //title: 문서 내의 모든 title 요소를 선택합니다.
- 특정 속성 선택:
- //book[@year="2020"]: year 속성이 2020인 모든 book 요소를 선택합니다.
- 부모 노드 선택:
- //title/..: 모든 title 요소의 부모 노드를 선택합니다.
- 속성 값 선택:
- //book/title/@lang: 모든 book 요소 내 title 요소의 lang 속성 값을 선택합니다 (속성 예제 필요).
'Programming > python' 카테고리의 다른 글
Anaconda없이 Python 가상환경 만들기 (0) | 2024.04.08 |
---|---|
PySpark SQL 시작하기 (1) | 2024.01.04 |
대용량 JSON파일 처리하기. python ijson (0) | 2024.01.04 |
PyCharm에서 anaconda 가상환경 구축하기 (0) | 2023.11.17 |
pip으로 opencv version 업데이트/재설치하기 (0) | 2023.11.08 |