2
* ptk-xml-tree.h - Over-simplified mini xml dom implementation
4
* Copyright 2008 PCMan <pcman.tw@gmail.com>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23
#include "ptk-xml-tree.h"
26
typedef struct _ParseInfo ParseInfo;
34
#define xml_node_new() g_slice_new0(XmlNode);
36
static void start_element( GMarkupParseContext *context,
37
const gchar *element_name,
38
const gchar **attribute_names,
39
const gchar **attribute_values,
43
ParseInfo* info = (ParseInfo*)user_data;
44
XmlNode *cur_node, *parent;
45
if( info->parse_stack->len > 0 ) {
46
parent = g_array_index( info->parse_stack,
48
info->parse_stack->len - 1 );
52
cur_node = xml_node_new();
53
cur_node->name = g_strdup( element_name );
54
cur_node->props = g_strdupv( (gchar**)attribute_names );
55
cur_node->vals = g_strdupv( (gchar**)attribute_values );
58
cur_node->parent = parent;
59
parent->children = g_slist_prepend( parent->children, cur_node );
61
/* push current node to the stack */
62
g_array_append_val( info->parse_stack, cur_node );
65
static void end_element( GMarkupParseContext *context,
66
const gchar *element_name,
70
ParseInfo* info = (ParseInfo*)user_data;
71
int i = info->parse_stack->len - 1;
72
XmlNode* cur_node = g_array_index( info->parse_stack,
77
GString* str = (GString*)cur_node->cdata;
78
cur_node->cdata = g_strdup( str->str );
79
g_string_free( str, TRUE );
82
if( cur_node->children )
83
cur_node->children = g_slist_reverse( cur_node->children );
85
/* begin tag is different from end tag, error! */
86
if( strcmp( cur_node->name, element_name ) )
88
g_markup_parse_context_end_parse( context, NULL );
92
/* pop current node from the stack */
93
g_array_remove_index( info->parse_stack, i );
96
static void cdata( GMarkupParseContext *context,
102
ParseInfo* info = (ParseInfo*)user_data;
104
XmlNode* cur_node = g_array_index( info->parse_stack,
106
info->parse_stack->len - 1 );
107
if( !cur_node->cdata )
109
str = g_string_sized_new(256);
110
cur_node->cdata = (char*)str;
113
str = (GString*)cur_node->cdata;
114
g_string_append_len( str, text, text_len );
117
static void parse_error( GMarkupParseContext *context,
118
GError *error, gpointer user_data )
120
ParseInfo* info = (ParseInfo*)user_data;
121
XmlNode* cur_node = g_array_index( info->parse_stack,
123
info->parse_stack->len - 1 );
124
if( cur_node->cdata )
126
GString* str = (GString*)cur_node->cdata;
127
g_string_free( str, TRUE );
128
cur_node->cdata = NULL;
130
g_markup_parse_context_end_parse( context, NULL );
133
static GMarkupParser parser =
142
XmlNode* xml_tree_load( const char* filename )
147
if ( g_file_get_contents( filename, &data, &data_len, NULL ) )
149
GMarkupParseContext * ctx;
151
info.tree = xml_node_new();
152
info.parse_stack = g_array_sized_new(FALSE, TRUE, sizeof(XmlNode*), 32);
153
g_array_append_val( info.parse_stack, info.tree );
154
ctx = g_markup_parse_context_new( &parser,
155
(GMarkupParseFlags)0,
157
if( !g_markup_parse_context_parse( ctx, data, data_len, NULL ) )
159
xml_tree_free( info.tree );
162
g_markup_parse_context_free( ctx );
163
g_array_free( info.parse_stack, TRUE );
169
void xml_node_free( XmlNode* node )
176
for( l = node->children; l; l = l->next )
178
child = (XmlNode*)l->data;
179
/* break the linkage between parent and child,
180
or subsequent recursive call to xml_node_free on
181
the child node will try to remove it from the parent again. */
182
child->parent = NULL;
183
xml_node_free( child );
185
g_slist_free( node->children );
188
/* delete the child node from its parent, ifneeded */
189
if( G_LIKELY( node->parent && node->parent->children) )
190
node->parent->children = g_slist_remove( node->parent->children, node );
192
g_free( node->name );
193
g_free( node->cdata );
194
g_strfreev( node->props );
195
g_strfreev( node->vals );
196
g_slice_free( XmlNode, node );
199
const char* xml_node_get_prop( XmlNode* node, const char* name )
202
for( prop = node->props, val = node->vals; *prop; ++prop, ++val )
204
if( *prop && 0 == strcmp(name, *prop) )