GIS에서 흔하게 볼 수 있는 데이터 포멧은 shp, kml, geojson이 있는데 구글어스에 뭔가를 올려서 보고싶다면 kml을 피할 수 없다.

xml 문서답게 kml은 그 트리 구조부터 attribute까지 사람을 헷갈리게 하는 경우가 많다.

그래서 이번에 특정 조건 하에 kml 파일을 대량 생산하면서 배운 것들을 여기에 정리하려 한다.

1. 쓰기

이전에 코드를 받아 써서 simplekml으로 파일을 썼는데 주의할 점이 있다.
루프당 kml을 생성한다면 반드시 kml 문서 instance를 초기화했는지 확인하자.
그렇지 않다면 나처럼 눈덩이처럼 불어버린 kml을 마주할 수 있게 된다.

'''
- key(str) : 문서 식별자
- input_df(dataframe) : kml로 쓸 내용들을 담은 dataframe
- root_folder_path : kml 문서들을 저장할 폴더 주소
'''
def create_single_kml_file(key, input_df, root_folder_path) : 
    // 이 아래에서 이렇게 kml 문서(xml문서로 치면 root) instance를 생성한다. 
    kml = simplekml.Kml()
    for i in range(len(input_df)) : 
        row_name = input_df.iloc[i]['name']
        f = kml.newfolder(name = row_name)
        ...
        pol = f.newpolygon(name='Polygon')
        pol.name= row_name
        pol.outerboundaryis=input_df.iloc[i]['geometry'].exterior.coords
        pol.description=description
        ...

    kml_name = f'aimo_label_{create_date}_{key}.kml'
    kml.save(f'{root_folder_path}/{kml_name}')

2. 읽기

simplekml은 문서 생성만 가능하다.
그래서 찾아보니 pykml이라는 것이 있어, 이걸로 읽어봤다.
문서 생성은 simplekml이, 범용성은 pykml이 좋아보인다.
pykml로 문서를 생성하려면 xml의 트리 구조와 문서의 기본 문법을 다 알아야 하기 때문이다.
pykml이 lxml에 기반해서 문서를 생성하면 simplekml은 이를 class로 감싸서 생성을 더 용이하게 만든 느낌..?
앞서 생성한 kml파일에 문제가 생겨서 이를 읽어서 수정할 일이 생겨서 읽었다. 다음과 같이 읽는다.

import os 
from pykml import parser

p = os.path.join(root_folder, k)
with open(p) as f:
# read root of doc
    doc = parser.parse(f)
    # read the folders under root 
    for folder in doc.getroot().getchildren()[0].getchildren() : 
    ...

3. 수정 및 반영

수정

파일 2개를 생성했는데 각 파일에 중복으로 들어간 정보가 있어서 조건에 따라 이를 제거하기로 했다.
폴더 단위로 겹치는 정보가 있었다.
트리 구조에서 정보를 제거하는 것과 같이, 해당 정보를 제거하기 위해서는 상위 요소로 올라가서 상위 요소에서 해당 정보를 제거하면 된다.
이 때 상위 요소를 parent, 해당 정보를 children이라 부른다.

for k in kml_list : 
    with open(os.path.join(root_folder,k)) as f:
        doc = parser.parse(f)
        for folder in tqdm(doc.getroot().getchildren()[0].getchildren()) : 
            if folder.name not in id_list :
                id_list.append(folder.name)
            else : 
                folder_parent = folder.getparent()
                folder_parent.remove(folder)
        doc_list.append(doc) 

반영

트리 구조를 살려서 저장해야 하기 때문에 lxml을 써서 트리를 string으로 변환한 후 저장한다.
etree.tostring(doc_list[i],encoding = "unicode", pretty_print=True)
에서 encoding="unicode"가 없으면 etree.tostring의 결과는 byte로 저장된다.

from lxml import etree
for i in range(len(doc_list)) : 
    with open(os.path.join(root_folder,kml_list[i]),'w') as f: 
        f.write(etree.tostring(doc_list[i],encoding = "unicode", pretty_print=True))

4. 결론

  • 나는 kml만 생성하면 돼! : simplekml
  • 나는 kml 읽고 쓰기 다 해야 해 : pykml + lxml

+ Recent posts