2024년 3월 22일 금요일

python xml comment parsing

python xml comment parsing

python에서는 xml 파싱하는 방법은 여러가지 준비가 되어 있습니다.

그런데 간혹 comment 까지 파싱 해야 하는 경우가 있습니다. 

XML은 데이터를 저장하고 전송하는 데 사용되는 마크업 언어입니다. 다음은 XML의 간단한 예제입니다

python에서 아래와 같은 xml을 string에 담았습니다.

xml_str = \
"""<?xml version="1.0" encoding="UTF-8"?>
<!-- hello -->
<note>
<!-- dash1 -->
<to>kim</to><!-- dash2 -->
<from>lee</from>
<heading>alert</heading>
<body>i am a boy</body>
</note>
"""

여기에서 XML 파서는 lxml 을 사용합니다. 이 패키지는 comment까지 완벽하게 처리해냅니다.

기본 xml 처리는 아래와 같은 형태를 사용 가능합니다.

def print_xml(xml_str_):
# XML 파일을 불러옵니다.
root = etree.fromstring(xml_str.encode())

# 루트 엘리먼트의 태그와 속성을 출력합니다.
print(f'Root element: {root.tag}')
for name, value in root.attrib.items():
print(f'Attribute - {name}: {value}')

# 모든 자식 엘리먼트를 순회하며 출력합니다.
for child in root:
print(f'Child element: {child.tag}')
for name, value in child.attrib.items():
print(f'Attribute - {name}: {value}')

결과를 아래와 같이 실행시키면

print_xml(xml_str)

다음과 같은 결과를 얻습니다.

Root element: note
Child element: <cyfunction Comment at 0x00000234BF7132B0>
Child element: to
Child element: <cyfunction Comment at 0x00000234BF7132B0>
Child element: from
Child element: heading
Child element: body

cyfunction 이라고 나오는곳이 comment가 됩니다. 이 부분을 처리하려면 아래와 같은 코드가 필요합니다. tag가 etree.Comment 인지 비교해서 따로 처리하는 방법입니다.

if child.tag == etree.Comment:
print("comment:", child.text)

그러면 처음 예제와 합쳐서 구현해보도록 하겠습니다.

def print_xml_wc(xml_str_):
# XML 파일을 불러옵니다.
root = etree.fromstring(xml_str.encode())

# 루트 엘리먼트의 태그와 속성을 출력합니다.
print(f'Root element: {root.tag}')
for name, value in root.attrib.items():
print(f'Attribute - {name}: {value}')

# 모든 자식 엘리먼트를 순회하며 출력합니다.
for child in root:
print(f'Child element: {child.tag}')
if child.tag == etree.Comment:
print("comment:", child.text)
continue
for name, value in child.attrib.items():
print(f'Attribute - {name}: {value}')

이런 식으로 됩니다.

print_xml_wc(xml_str)

수행한 결과는 아래와 같습니다.

Root element: note
Child element: <cyfunction Comment at 0x00000234BF7132B0>
comment: dash1
Child element: to
Child element: <cyfunction Comment at 0x00000234BF7132B0>
comment: dash2
Child element: from
Child element: heading
Child element: body


xml 데이터의 root node보다 앞쪽에 있는 comment 처리 방법

xml을 자세히 보면 앞쪽 hello 라는 주석을 파싱하지 못하는 부분이 있습니다.

이건 어떻게 해야할까요?

처음에 문서도 보고 한참 헤맸는데요. 의외로 간단합니다.

element의 getprevious() 함수를 사용합니다.

변경된 코드는 아래와 같습니다.

def print_xml_wc_root(xml_str_):
# XML 파일을 불러옵니다.
root = etree.fromstring(xml_str.encode())

if root.getprevious() != None:
if root.getprevious().tag == etree.Comment:
print("comment:", root.getprevious().text)

# 루트 엘리먼트의 태그와 속성을 출력합니다.
print(f'Root element: {root.tag}')
for name, value in root.attrib.items():
print(f'Attribute - {name}: {value}')

# 모든 자식 엘리먼트를 순회하며 출력합니다.
for child in root:
print(f'Child element: {child.tag}')
if child.tag == etree.Comment:
print("comment:", child.text)
continue
for name, value in child.attrib.items():
print(f'Attribute - {name}: {value}')

root node의 앞쪽 tag 가 comment 라면 출력하는 코드를 넣었습니다.

실행한 결과는 아래와 같고

comment:  hello 
Root element: note
Child element: <cyfunction Comment at 0x0000026F045732B0>
comment: dash1
Child element: to
Child element: <cyfunction Comment at 0x0000026F045732B0>
comment: dash2
Child element: from
Child element: heading
Child element: body

전체 소스는 git hub에서 보시기 바랍니다.

sourcecode/python/example/_63_lxml/lxml_comment.py at main · donarts/sourcecode · GitHub



댓글 없음:

댓글 쓰기