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

expat

홈페이지: http://expat.sourceforge.net/

xml 파서 라이브러리.

Expat is an XML parser library written in C

int main()
{
  char buf[convenient size];
  int len;   /* len is the number of bytes in the current bufferful of data */
  int done;
  int depth = 0;  /* nothing magic about this; the sample program tracks depth to know how far to indent. */
                  /* depth is thus going to be the user data for this parser. */

  XML_Parser parser = XML_ParserCreate(NULL);
  XML_SetUserData(parser, &depth);
  XML_SetElementHandler(parser, startElement, endElement);
  do {
    get a piece of input into the buffer
    done = whether this bufferful is the last bufferful
    if (!XML_Parse(parser, buf, len, done)) {
      handle parse error
      return 1;
    }
  } while (!done);
  XML_ParserFree(parser);
  return 0;
}

다운로드: 2.01