본문 바로가기

카테고리 없음

[python]xml, yaml 다뤄보기

프로그램 내에서 사용되는 패러미터를 설정하는 xml 파일이 있다. 
각 개발자는 로컬에서 개발할 때 설정값을 xml 에 직접 선언해놓고 쓰는데 싸이트 배포를 위해 빌드 시에는 가변성 유지를 위해 설정값을 별도의 파일로 관리하고 있는 중. 
이를 위해 빌드용 환경 파일을 수작업으로 관리해왔는데 이걸 좀 개선해서 개발자가 패러미터를 추가/삭제 등을 했을 때 자동으로 반영하기 위해 빌드용 환경 파일을 동적으로 생성해주는 프로그램을 하나 짜보았다. 
개발자 환경 파일과 패러미터 관리 파일을 비교하여 개발자 환경 파일과 차이 나는 경우 패러미터 관리 파일에 변경분을 반영하고 그걸 다시 반영한 빌드용 환경 파일 생성.

- 싸이트 배포 빌드용 환경 파일
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<sb-conf xmlns:xi="http://www.w3.org/2001/XInclude" ...>
	<operator-parameters>
		<operator-parameter name="HESSIAN_IP" value="${HESSIAN_IP}" />
		<operator-parameter name="HESSIAN_PORT" value="12150" /

		<operator-parameter name="FUSE_INBOUND_QUEUE" value="${FUSE_INBOUND_QUEUE}" />
		<operator-parameter name="FUSE_OTBOUND_QUEUE" value="${FUSE_OTBOUND_QUEUE}" />
		...
	</operator-parameters>
</sb-conf>
- 개발자 환경 파일
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<sb-conf xmlns:xi="http://www.w3.org/2001/XInclude" ...>
	<operator-parameters>
		<operator-parameter name="HESSIAN_IP" value="127.0.0.1" />
		<operator-parameter name="HESSIAN_PORT" value="7310" /

		<operator-parameter name="FUSE_INBOUND_QUEUE" value="test_in" />
		<operator-parameter name="FUSE_OTBOUND_QUEUE" value="test_out" />
		...
	</operator-parameters>
</sb-conf>
- 패러미터값 관리 파일(yaml 포맷)
FUSE_INBOUND_QUEUE: ${FUSE_INBOUND_QUEUE}
FUSE_OTBOUND_QUEUE: ${FUSE_OTBOUND_QUEUE}
HESSIAN_IP: ${HESSIAN_IP}
HESSIAN_PORT: '12150'

구현 전체 소스 중 주 함수들.

def get_op(subtree):
    return { attrib.get('name') : attrib.get('value') for attrib in subtree }


def get_variables(var_file):
    with open(var_file) as data_file:
        return yaml.safe_load(data_file)

def add_variables(var_file, add_vars):
    with open(var_file, 'r') as data_file:
        cur_yaml = yaml.safe_load(data_file)
        cur_yaml.update(add_vars)

    if cur_yaml:
        with open(var_file,'w') as yamlfile:
            yaml.safe_dump(cur_yaml, yamlfile)        

def del_variables(var_file, del_vars):
    with open(var_file, 'r') as data_file:
        cur_yaml = yaml.safe_load(data_file)
        for key in del_vars:
            del cur_yaml[key]

    if cur_yaml:
        with open(var_file,'w') as yamlfile:
            yaml.safe_dump(cur_yaml, yamlfile)        

def gen_sbconf(var_file, common_sbconf, build_conf, site, src_type):
    tree = ET.parse(common_sbconf)
    root = tree.getroot()
    basic_op = get_op(root.find("operator-parameters"))

    variables = get_variables(var_file)
    not_variable = {k: basic_op[k] for k in set(basic_op) - set(variables)}
    if len(not_variable) > 0:
        print(var_file, "- Regist New Variables : {0}".format(not_variable).replace("'", '"'))
        add_variables(var_file, not_variable)

    not_variable1 = {k: variables[k] for k in set(variables) - set(basic_op)}
    if len(not_variable1) > 0:
        print(var_file, "- Remove Variables :", not_variable1.keys())
        del_variables(var_file, not_variable1.keys())


    print("gen_sbd_common.py generate", build_conf)

    for key, val in variables.items():
        base = op.find(".//*[@name='" + key + "']")
        if base is None:
            continue
        base.set("value", val)

    # print(ET.dump(tree))
    ET.ElementTree(root).write(build_conf, encoding="utf-8", xml_declaration=True)

작업 덕분에 python 에서 yaml, xml 다루는 몇 가지 방법 익혀볼 수 있었네요.

  • xml 읽기, xml 파일 생성.
  • yaml 파일 읽기, yaml 엘리먼트 추가, 삭제하기. 
  • 그리고 두 dictionary 타입 값들의 차이 구하기.