scew라이브러리의 element를 패스로 표현하기

SCEW 라이브러리는 C에서 사용가능한 expat 래퍼 XML 라이브러리이다.

SCEW 라이브러리를 이용하면 expat 보다 더 상위레벨에서 좀더 쉽게 XML 데이타를 취급할 수 있다.

하지만 좀더 쉽게 접근하기 위한 패스를 제공하기 위해 아래와 같이 함수를 작성해 봤다.

아래와 같은 xml 이 있다고 할때.. c 노드를 패스로 표현하면 “/a/b/c” 로 표현된다.

<a>
    <b>
        <c>
        </c>
    </b>
</a>

나는 여기서 “/a/b/c” 표현으로 c 노드의 element를 얻고 싶다.

아래는 scew 를 이용하여 get_node_path 를 구현한 함수이며, 이를 이용한 데모이다.

아래의 코드는 mingw, linux 에서 테스트 되었다.

/*
	XML simple read example

	inhak.min@gmail.com
*/

#include <scew/scew.h>
#include <stdio.h>

char *get_attribute(scew_element *node, char *name)
{
	if (node != NULL)
	{
		scew_list *list = scew_element_attributes (node);
		while (list != NULL)
		{
			scew_attribute *attribute = scew_list_data (list);
			if ( !strcmp(scew_attribute_name (attribute), name) )
				return (char *)scew_attribute_value (attribute);

			list = scew_list_next (list);
		}
	}
}

char *get_node_path(scew_element *node)
{
	static char result_path[9072];

	scew_element *parent = node;

	sprintf(result_path, "");
	
	while(parent)
	{
		char *name = (char *)scew_element_name(parent);

		char tmp[9072];
		sprintf(tmp, "%s", result_path);

		sprintf(result_path, "%s", "/");
		sprintf(result_path, "%s%s", result_path, name);
		sprintf(result_path, "%s%s", result_path, tmp);

		parent = scew_element_parent(parent);
	}

	return result_path;
}

int get_node_depth(scew_element *node)
{
	int depth=0;
	scew_element *parent = node;

	while(parent)
	{
		++depth;
		parent = scew_element_parent(parent);
	}

	return depth;
}

scew_list* find_nodes (scew_element *node, char *find_path)
{
	static scew_list *result_list=NULL;

	char *path = get_node_path(node);
	if ( !strcmp(find_path, path) || !(strcmp(find_path, "*")) )
	{
		if(result_list==NULL)
			result_list = scew_list_create(node);
		else
			scew_list_append(result_list, node);
	}

	scew_list *children_list = scew_element_children (node);
	while (children_list != NULL)
	{
		scew_element *child = scew_list_data (children_list);
		result_list = find_nodes (child, find_path);
		children_list = scew_list_next (children_list);
	}

	return result_list;
}

static void
print_attributes (scew_element *node)
{
	if (node != NULL)
	{
		scew_list *list = scew_element_attributes (node);
		while (list != NULL)
		{
			scew_attribute *attribute = scew_list_data (list);
			printf (("%s=\"%s\""),
				scew_attribute_name (attribute),
				scew_attribute_value (attribute));
			list = scew_list_next (list);
		}
	}
}

// 실제 사용 방법
void demo(scew_tree *xml)
{
	scew_list *node_list=NULL;

	char *path = "/ctml/speciesData/species/thermo/NASA/floatArray";
	//char *path = "*";
	node_list = find_nodes (scew_tree_root (xml), path);

	printf(">> Found nodes: %d\n\n", scew_list_size(node_list));

	// 리스트를 검색해서 contents 를 뽑아낸다.
	while (node_list != NULL)
	{
		scew_element *node = scew_list_data (node_list);

		printf("[%d] %s\n", get_node_depth(node), get_node_path(node));

		// contents 를 출력한다.
		char *contents = (char *)scew_element_contents (node);
		printf("contents: %s\n\n", contents);
		
		// attribute 를 출력한다.
		printf("attributes: ");
		print_attributes (node);

		printf("\n-------------------\n");

		// 다음 노드를 얻는다.
		node_list = scew_list_next (node_list);
	}

	scew_list_free(node_list);
}

int
main (int argc, char *argv[])
{
	scew_reader *reader = NULL;
	scew_parser *parser = NULL;
	scew_tree *xml = NULL;

	if (argc < 2)
	{
		printf ("Usage: %s file.xml\n", argv[0]);
		return -1;
	}

	/* Creates an SCEW parser. This is the first function to call. */
	parser = scew_parser_create ();

	scew_parser_ignore_whitespaces (parser, SCEW_TRUE);

	/* Loads an XML file. */
	reader = scew_reader_file_create (argv[1]);

	xml = scew_parser_load (parser, reader);

	demo(xml);

	/* Remember to free xml (scew_parser_free does not free it). */
	scew_tree_free (xml);

	/* Frees the SCEW parser and reader. */
	scew_reader_free (reader);
	scew_parser_free (parser);

	return 0;
}

SCEW – Simple C Expat Wrapper

홈페이지: http://www.nongnu.org/scew/

c에서 사용가능한 expat 래퍼 라이브러리.
xml 노드에 쉽게 접근하고, 변경하고, xml 파일로 쓸수 있는 기능도 제공한다.

그외 scew_list 링크드 리스트같은 유틸리티 함수도 제공된다.

The aim of SCEW is to provide an easy interface around the XML Expat parser, as well as a simple interface for creating new XML documents. It provides functions to load and access XML elements without the need to create Expat event handling routines every time you want to load a new XML document.

These are the main SCEW features:
– Uses a DOM-like object model for new or parsed XML documents.
– Supports loading concatenated XML documents.
– Can copy and compare full XML documents, elements or attributes.
– Writes XML documents to multiple outputs.
– Allows adding new I/O sources easily.
– UTF-8, ISO-8859-1 and US-ASCII encodings (and UTF-16 in Windows).

다운로드: 1.1.3