~ubuntu-branches/ubuntu/lucid/igraph/lucid

« back to all changes in this revision

Viewing changes to src/foreign-graphml.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathieu Malaterre
  • Date: 2009-11-16 18:12:42 UTC
  • Revision ID: james.westby@ubuntu.com-20091116181242-mzv9p5fz9uj57xd1
Tags: upstream-0.5.3
ImportĀ upstreamĀ versionĀ 0.5.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C -*-  */
 
2
/* 
 
3
   IGraph R package.
 
4
   Copyright (C) 2006 Gabor Csardi <csardi@rmki.kfki.hu>
 
5
   MTA RMKI, Konkoly-Thege Miklos st. 29-33, Budapest 1121, Hungary
 
6
   
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 2 of the License, or
 
10
   (at your option) any later version.
 
11
   
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
   
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program; if not, write to the Free Software
 
19
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
 
20
   02110-1301 USA
 
21
 
 
22
*/
 
23
 
 
24
#include "igraph.h"
 
25
#include "config.h"
 
26
#include "igraph_math.h"
 
27
 
 
28
#include <ctype.h>              /* isspace */
 
29
#include <math.h>               /* isnan */
 
30
#include <string.h>
 
31
#include "memory.h"
 
32
#include <stdarg.h>             /* va_start & co */
 
33
 
 
34
#if HAVE_LIBXML == 1
 
35
#include <libxml/encoding.h>
 
36
#include <libxml/parser.h>
 
37
 
 
38
 
 
39
xmlEntity blankEntityStruct = {
 
40
#ifndef XML_WITHOUT_CORBA
 
41
  0,
 
42
#endif
 
43
  XML_ENTITY_DECL,
 
44
  0,
 
45
  0,
 
46
  0,
 
47
  0,
 
48
  0,
 
49
  0,
 
50
  0,
 
51
  0,
 
52
  0,
 
53
  0,
 
54
  XML_EXTERNAL_GENERAL_PARSED_ENTITY,
 
55
  0,
 
56
  0,
 
57
  0,
 
58
  0
 
59
};
 
60
 
 
61
xmlEntityPtr blankEntity = &blankEntityStruct;
 
62
 
 
63
/* TODO: proper error handling */
 
64
 
 
65
typedef struct igraph_i_graphml_attribute_record_t {
 
66
  const char *id;               /* GraphML id */
 
67
  enum { I_GRAPHML_BOOLEAN, I_GRAPHML_INTEGER, I_GRAPHML_LONG,
 
68
         I_GRAPHML_FLOAT, I_GRAPHML_DOUBLE, I_GRAPHML_STRING,
 
69
         I_GRAPHML_UNKNOWN_TYPE } type; /* GraphML type */
 
70
  igraph_i_attribute_record_t record;
 
71
} igraph_i_graphml_attribute_record_t;
 
72
 
 
73
struct igraph_i_graphml_parser_state {
 
74
  enum { START, INSIDE_GRAPHML, INSIDE_GRAPH, INSIDE_NODE, INSIDE_EDGE,
 
75
      INSIDE_KEY, INSIDE_DEFAULT, INSIDE_DATA, FINISH, UNKNOWN, ERROR } st;
 
76
  igraph_t *g;
 
77
  igraph_trie_t node_trie;
 
78
  igraph_strvector_t edgeids;
 
79
  igraph_vector_t edgelist;
 
80
  unsigned int prev_state;
 
81
  unsigned int unknown_depth;
 
82
  int index;
 
83
  igraph_bool_t successful, edges_directed, destroyed;
 
84
  igraph_trie_t v_names;
 
85
  igraph_vector_ptr_t v_attrs;
 
86
  igraph_trie_t e_names;
 
87
  igraph_vector_ptr_t e_attrs;
 
88
  igraph_trie_t g_names;
 
89
  igraph_vector_ptr_t g_attrs;
 
90
  xmlChar *data_key;
 
91
  igraph_attribute_elemtype_t data_type;
 
92
  char *error_message;
 
93
  char *data_char;
 
94
};
 
95
 
 
96
void igraph_i_graphml_destroy_state(struct igraph_i_graphml_parser_state* state) {
 
97
  long int i;
 
98
 
 
99
  if (state->destroyed) return;
 
100
  state->destroyed=1;
 
101
 
 
102
  /* this is the easy part */
 
103
  igraph_trie_destroy(&state->node_trie);
 
104
  igraph_strvector_destroy(&state->edgeids);
 
105
  igraph_trie_destroy(&state->v_names);
 
106
  igraph_trie_destroy(&state->e_names);
 
107
  igraph_trie_destroy(&state->g_names);
 
108
  igraph_vector_destroy(&state->edgelist);
 
109
   
 
110
  if (state->error_message) { free(state->error_message); }
 
111
  if (state->data_key) { free(state->data_key); }
 
112
  if (state->data_char) { free(state->data_char); }
 
113
  
 
114
  for (i=0; i<igraph_vector_ptr_size(&state->v_attrs); i++) {
 
115
    igraph_i_graphml_attribute_record_t *rec=VECTOR(state->v_attrs)[i];
 
116
    if (rec->record.type==IGRAPH_ATTRIBUTE_NUMERIC) {
 
117
      if (rec->record.value != 0) {
 
118
        igraph_vector_destroy((igraph_vector_t*)rec->record.value);
 
119
        igraph_Free(rec->record.value);
 
120
      }
 
121
    } else if (rec->record.type==IGRAPH_ATTRIBUTE_STRING) {
 
122
      if (rec->record.value != 0) {
 
123
        igraph_strvector_destroy((igraph_strvector_t*)rec->record.value);
 
124
        igraph_Free(rec->record.value);
 
125
      }
 
126
    }
 
127
    if (rec->id != 0) igraph_Free(rec->id);
 
128
    if (rec->record.name != 0) igraph_Free(rec->record.name);
 
129
    igraph_Free(rec);
 
130
  }      
 
131
 
 
132
  for (i=0; i<igraph_vector_ptr_size(&state->e_attrs); i++) {
 
133
    igraph_i_graphml_attribute_record_t *rec=VECTOR(state->e_attrs)[i];
 
134
    if (rec->record.type==IGRAPH_ATTRIBUTE_NUMERIC) {
 
135
      if (rec->record.value != 0) {
 
136
        igraph_vector_destroy((igraph_vector_t*)rec->record.value);
 
137
        igraph_Free(rec->record.value);
 
138
      }
 
139
    } else if (rec->record.type==IGRAPH_ATTRIBUTE_STRING) {
 
140
      if (rec->record.value != 0) {
 
141
        igraph_strvector_destroy((igraph_strvector_t*)rec->record.value);
 
142
        igraph_Free(rec->record.value);
 
143
      }
 
144
    }
 
145
    if (rec->id != 0) igraph_Free(rec->id);
 
146
    if (rec->record.name != 0) igraph_Free(rec->record.name);
 
147
    igraph_Free(rec);
 
148
  }
 
149
 
 
150
  for (i=0; i<igraph_vector_ptr_size(&state->g_attrs); i++) {
 
151
    igraph_i_graphml_attribute_record_t *rec=VECTOR(state->g_attrs)[i];
 
152
    if (rec->record.type==IGRAPH_ATTRIBUTE_NUMERIC) {
 
153
      if (rec->record.value != 0) {
 
154
        igraph_vector_destroy((igraph_vector_t*)rec->record.value);
 
155
        igraph_Free(rec->record.value);
 
156
      }
 
157
    } else if (rec->record.type==IGRAPH_ATTRIBUTE_STRING) {
 
158
      if (rec->record.value != 0) {
 
159
        igraph_strvector_destroy((igraph_strvector_t*)rec->record.value);
 
160
        igraph_Free(rec->record.value);
 
161
      }
 
162
    }
 
163
    if (rec->id != 0) igraph_Free(rec->id);
 
164
    if (rec->record.name != 0) igraph_Free(rec->record.name);
 
165
    igraph_Free(rec);
 
166
  }
 
167
 
 
168
  igraph_vector_ptr_destroy(&state->v_attrs);
 
169
  igraph_vector_ptr_destroy(&state->e_attrs);
 
170
  igraph_vector_ptr_destroy(&state->g_attrs);
 
171
  
 
172
  IGRAPH_FINALLY_CLEAN(1);
 
173
}
 
174
 
 
175
void igraph_i_graphml_sax_handler_error(void *state0, const char* msg, ...) {
 
176
  struct igraph_i_graphml_parser_state *state=
 
177
    (struct igraph_i_graphml_parser_state*)state0;
 
178
  va_list ap;
 
179
  
 
180
  va_start(ap, msg);
 
181
  
 
182
  if (state->error_message == 0)
 
183
    state->error_message=igraph_Calloc(4096, char);
 
184
   
 
185
  state->successful=0;
 
186
  state->st=ERROR;
 
187
  vsnprintf(state->error_message, 4096, msg, ap);
 
188
   
 
189
  va_end(ap);
 
190
}
 
191
 
 
192
xmlEntityPtr igraph_i_graphml_sax_handler_get_entity(void *state0,
 
193
                                                     const xmlChar* name) {
 
194
  xmlEntityPtr predef = xmlGetPredefinedEntity(name);
 
195
  if (predef != NULL) return predef;
 
196
  IGRAPH_WARNING("unknown XML entity found\n");
 
197
  return blankEntity;
 
198
}
 
199
 
 
200
void igraph_i_graphml_handle_unknown_start_tag(struct igraph_i_graphml_parser_state *state) {
 
201
  if (state->st != UNKNOWN) {
 
202
    state->prev_state=state->st;
 
203
    state->st=UNKNOWN;
 
204
    state->unknown_depth=1;
 
205
  } else state->unknown_depth++;
 
206
}
 
207
 
 
208
void igraph_i_graphml_sax_handler_start_document(void *state0) {
 
209
  struct igraph_i_graphml_parser_state *state=
 
210
    (struct igraph_i_graphml_parser_state*)state0;
 
211
  int ret;
 
212
  
 
213
  state->st=START;
 
214
  state->successful=1;
 
215
  state->edges_directed=0;
 
216
  state->destroyed=0;
 
217
  state->data_key=0;
 
218
  state->error_message=0;
 
219
  state->data_char=0;
 
220
  
 
221
  ret=igraph_vector_ptr_init(&state->v_attrs, 0);
 
222
  if (ret) {
 
223
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
 
224
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
225
    return;
 
226
  }
 
227
  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->v_attrs);
 
228
  ret=igraph_vector_ptr_init(&state->e_attrs, 0);
 
229
  if (ret) {
 
230
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
 
231
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
232
    return;
 
233
  }
 
234
  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->e_attrs);
 
235
  ret=igraph_vector_ptr_init(&state->g_attrs, 0);
 
236
  if (ret) {
 
237
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
 
238
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
239
    return;
 
240
  }
 
241
  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->g_attrs);
 
242
  ret=igraph_vector_init(&state->edgelist, 0);
 
243
  if (ret) {
 
244
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
 
245
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
246
    return;
 
247
  }
 
248
  IGRAPH_FINALLY(igraph_vector_destroy, &state->edgelist);
 
249
  ret=igraph_trie_init(&state->node_trie, 1);
 
250
  if (ret) {
 
251
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
 
252
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
253
    return;
 
254
  }
 
255
  IGRAPH_FINALLY(igraph_trie_destroy, &state->node_trie);
 
256
  ret=igraph_strvector_init(&state->edgeids, 0);
 
257
  if (ret) {
 
258
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
 
259
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
260
    return;
 
261
  }
 
262
  IGRAPH_FINALLY(igraph_strvector_destroy, &state->edgeids);
 
263
  ret=igraph_trie_init(&state->v_names, 0);
 
264
  if (ret) {
 
265
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
 
266
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
267
    return;
 
268
  }
 
269
  IGRAPH_FINALLY(igraph_trie_destroy, &state->v_names);
 
270
  ret=igraph_trie_init(&state->e_names, 0);
 
271
  if (ret) {
 
272
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
 
273
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
274
    return;
 
275
  }
 
276
  IGRAPH_FINALLY(igraph_trie_destroy, &state->e_names);
 
277
  ret=igraph_trie_init(&state->g_names, 0);
 
278
  if (ret) {
 
279
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
 
280
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
281
    return;
 
282
  }
 
283
  IGRAPH_FINALLY(igraph_trie_destroy, &state->g_names);
 
284
  
 
285
  IGRAPH_FINALLY_CLEAN(9);
 
286
  IGRAPH_FINALLY(igraph_i_graphml_destroy_state, state);
 
287
}
 
288
 
 
289
void igraph_i_graphml_sax_handler_end_document(void *state0) {
 
290
  struct igraph_i_graphml_parser_state *state=
 
291
    (struct igraph_i_graphml_parser_state*)state0;
 
292
  long i, l;
 
293
  int r;
 
294
  igraph_i_attribute_record_t idrec, eidrec;
 
295
  const char *idstr="id";
 
296
  igraph_bool_t already_has_vertex_id=0, already_has_edge_id=0;
 
297
 
 
298
  if (!state->successful) return;
 
299
 
 
300
  if (state->index<0) {
 
301
 
 
302
    igraph_vector_ptr_t vattr, eattr, gattr;
 
303
    long int esize=igraph_vector_ptr_size(&state->e_attrs);
 
304
    const void **tmp;
 
305
    r=igraph_vector_ptr_init(&vattr, 
 
306
                             igraph_vector_ptr_size(&state->v_attrs)+1);
 
307
    if (r) {
 
308
      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, r);
 
309
      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
310
      return;
 
311
    }
 
312
    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &vattr);
 
313
    if (igraph_strvector_size(&state->edgeids) != 0) {
 
314
      esize++;      
 
315
    }
 
316
    r=igraph_vector_ptr_init(&eattr, esize);
 
317
    if (r) {
 
318
      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, r);
 
319
      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
320
      return;
 
321
    }
 
322
    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &eattr);
 
323
    r=igraph_vector_ptr_init(&gattr, igraph_vector_ptr_size(&state->g_attrs));
 
324
    if (r) {
 
325
      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, r);
 
326
      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
327
      return;
 
328
    }
 
329
    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &gattr);
 
330
 
 
331
    for (i=0; i<igraph_vector_ptr_size(&state->v_attrs); i++) {
 
332
      igraph_i_graphml_attribute_record_t *graphmlrec=
 
333
        VECTOR(state->v_attrs)[i];
 
334
      igraph_i_attribute_record_t *rec=&graphmlrec->record;
 
335
 
 
336
      /* Check that the name of the vertex attribute is not 'id'.
 
337
         If it is then we cannot the complimentary 'id' attribute. */
 
338
      if (! strcmp(rec->name, idstr)) {
 
339
        already_has_vertex_id=1;
 
340
      }
 
341
 
 
342
      if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
 
343
        igraph_vector_t *vec=(igraph_vector_t*)rec->value;
 
344
        long int origsize=igraph_vector_size(vec);
 
345
        long int nodes=igraph_trie_size(&state->node_trie);
 
346
        igraph_vector_resize(vec, nodes);
 
347
        for (l=origsize; l<nodes; l++) {
 
348
          VECTOR(*vec)[l]=IGRAPH_NAN;
 
349
        }
 
350
      } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
 
351
        igraph_strvector_t *strvec=(igraph_strvector_t*)rec->value;
 
352
        long int origsize=igraph_strvector_size(strvec);
 
353
        long int nodes=igraph_trie_size(&state->node_trie);
 
354
        igraph_strvector_resize(strvec, nodes);
 
355
        for (l=origsize; l<nodes; l++) {
 
356
          igraph_strvector_set(strvec, l, "");
 
357
        }
 
358
      }
 
359
      VECTOR(vattr)[i]=rec;
 
360
    }
 
361
    if (!already_has_vertex_id) {
 
362
      idrec.name=idstr;
 
363
      idrec.type=IGRAPH_ATTRIBUTE_STRING;
 
364
      tmp=&idrec.value;
 
365
      igraph_trie_getkeys(&state->node_trie, (const igraph_strvector_t **)tmp);
 
366
      VECTOR(vattr)[i]=&idrec;
 
367
    } else {
 
368
      igraph_vector_ptr_pop_back(&vattr);
 
369
      IGRAPH_WARNING("Could not add vertex ids, "
 
370
                     "there is already an 'id' vertex attribute");
 
371
    }
 
372
 
 
373
    for (i=0; i<igraph_vector_ptr_size(&state->e_attrs); i++) {
 
374
      igraph_i_graphml_attribute_record_t *graphmlrec=
 
375
        VECTOR(state->e_attrs)[i];
 
376
      igraph_i_attribute_record_t *rec=&graphmlrec->record;
 
377
 
 
378
      if (! strcmp(rec->name, idstr)) {
 
379
        already_has_edge_id=1;
 
380
      }
 
381
 
 
382
      if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
 
383
        igraph_vector_t *vec=(igraph_vector_t*)rec->value;
 
384
        long int origsize=igraph_vector_size(vec);
 
385
        long int edges=igraph_vector_size(&state->edgelist)/2;
 
386
        igraph_vector_resize(vec, edges);
 
387
        for (l=origsize; l<edges; l++) {
 
388
          VECTOR(*vec)[l]=IGRAPH_NAN;
 
389
        }
 
390
      } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
 
391
        igraph_strvector_t *strvec=(igraph_strvector_t*)rec->value;
 
392
        long int origsize=igraph_strvector_size(strvec);
 
393
        long int edges=igraph_vector_size(&state->edgelist)/2;
 
394
        igraph_strvector_resize(strvec, edges);
 
395
        for (l=origsize; l<edges; l++) {
 
396
          igraph_strvector_set(strvec, l, "");
 
397
        }
 
398
      }
 
399
      VECTOR(eattr)[i]=rec;
 
400
    }
 
401
    if (igraph_strvector_size(&state->edgeids) != 0) {
 
402
      if (!already_has_edge_id) {
 
403
        long int origsize=igraph_strvector_size(&state->edgeids);
 
404
        eidrec.name=idstr;
 
405
        eidrec.type=IGRAPH_ATTRIBUTE_STRING;
 
406
        igraph_strvector_resize(&state->edgeids, 
 
407
                                igraph_vector_size(&state->edgelist)/2);
 
408
        for (; origsize < igraph_strvector_size(&state->edgeids); origsize++) {
 
409
          igraph_strvector_set(&state->edgeids, origsize, "");
 
410
        }
 
411
        eidrec.value=&state->edgeids;
 
412
        VECTOR(eattr)[(long int)igraph_vector_ptr_size(&eattr)-1]=&eidrec;
 
413
      } else {
 
414
        igraph_vector_ptr_pop_back(&eattr);
 
415
        IGRAPH_WARNING("Could not add edge ids, "
 
416
                       "there is already an 'id' edge attribute");
 
417
      }
 
418
    }
 
419
 
 
420
    for (i=0; i<igraph_vector_ptr_size(&state->g_attrs); i++) {
 
421
      igraph_i_graphml_attribute_record_t *graphmlrec=
 
422
        VECTOR(state->g_attrs)[i];
 
423
      igraph_i_attribute_record_t *rec=&graphmlrec->record;
 
424
      if (rec->type == IGRAPH_ATTRIBUTE_NUMERIC) {
 
425
        igraph_vector_t *vec=(igraph_vector_t*)rec->value;
 
426
        long int origsize=igraph_vector_size(vec);
 
427
        igraph_vector_resize(vec, 1);
 
428
        for (l=origsize; l<1; l++) {
 
429
          VECTOR(*vec)[l]=IGRAPH_NAN;
 
430
        }
 
431
      } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
 
432
        igraph_strvector_t *strvec=(igraph_strvector_t*)rec->value;
 
433
        long int origsize=igraph_strvector_size(strvec);
 
434
        igraph_strvector_resize(strvec, 1);
 
435
        for (l=origsize; l<1; l++) {
 
436
          igraph_strvector_set(strvec, l, "");
 
437
        }
 
438
      }
 
439
      VECTOR(gattr)[i]=rec;
 
440
    }
 
441
    
 
442
    igraph_empty_attrs(state->g, 0, state->edges_directed, &gattr);
 
443
    igraph_add_vertices(state->g, igraph_trie_size(&state->node_trie),
 
444
                        &vattr);
 
445
    igraph_add_edges(state->g, &state->edgelist, &eattr);
 
446
 
 
447
    igraph_vector_ptr_destroy(&vattr);
 
448
    igraph_vector_ptr_destroy(&eattr);
 
449
    igraph_vector_ptr_destroy(&gattr);
 
450
    IGRAPH_FINALLY_CLEAN(3);     
 
451
  }
 
452
 
 
453
  igraph_i_graphml_destroy_state(state);
 
454
}
 
455
 
 
456
#define toXmlChar(a)   (BAD_CAST(a))
 
457
#define fromXmlChar(a) ((char *)(a)) /* not the most elegant way... */
 
458
 
 
459
void igraph_i_graphml_add_attribute_key(const xmlChar** attrs, 
 
460
                                        struct igraph_i_graphml_parser_state *state) {
 
461
  xmlChar **it;
 
462
  igraph_trie_t *trie=0;
 
463
  igraph_vector_ptr_t *ptrvector=0;
 
464
  long int id;
 
465
  int ret;
 
466
  igraph_i_graphml_attribute_record_t *rec=
 
467
    igraph_Calloc(1, igraph_i_graphml_attribute_record_t);
 
468
 
 
469
  if (!state->successful) return;
 
470
   
 
471
   if (rec==0) { 
 
472
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, 
 
473
                 IGRAPH_ENOMEM);
 
474
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
475
    return;
 
476
  }
 
477
  IGRAPH_FINALLY(igraph_free, rec);
 
478
  for (it=(xmlChar**)attrs; *it; it+=2) {
 
479
    if (xmlStrEqual(*it, toXmlChar("id"))) {
 
480
      const char *id=(const char*)(*(it+1));
 
481
      rec->id=strdup(id);
 
482
    } else if (xmlStrEqual(*it, toXmlChar("attr.name"))) {
 
483
      const char *name=fromXmlChar(*(it+1));
 
484
      rec->record.name=strdup(name);
 
485
    } else if (xmlStrEqual(*it, toXmlChar("attr.type"))) {
 
486
      if (xmlStrEqual(*(it+1), (xmlChar*)"boolean")) { 
 
487
        rec->type=I_GRAPHML_BOOLEAN;
 
488
        rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;          
 
489
      } else if (xmlStrEqual(*(it+1), toXmlChar("string"))) {
 
490
        rec->type=I_GRAPHML_STRING;
 
491
        rec->record.type=IGRAPH_ATTRIBUTE_STRING;
 
492
      } else if (xmlStrEqual(*(it+1), toXmlChar("float"))) { 
 
493
        rec->type=I_GRAPHML_FLOAT;
 
494
        rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
 
495
      } else if (xmlStrEqual(*(it+1), toXmlChar("double"))) { 
 
496
        rec->type=I_GRAPHML_DOUBLE;
 
497
        rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
 
498
      } else if (xmlStrEqual(*(it+1), toXmlChar("int"))) {
 
499
        rec->type=I_GRAPHML_INTEGER;
 
500
        rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
 
501
      } else if (xmlStrEqual(*(it+1), toXmlChar("long"))) {
 
502
        rec->type=I_GRAPHML_LONG;
 
503
        rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
 
504
      } else {
 
505
        igraph_error("Cannot parse GraphML file, unknown attribute type", 
 
506
                     __FILE__, __LINE__, IGRAPH_PARSEERROR);
 
507
        igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file, unknown attribute type");
 
508
        return;
 
509
      }
 
510
    } else if (xmlStrEqual(*it, toXmlChar("for"))) {
 
511
      /* graph, vertex or edge attribute? */
 
512
      if (xmlStrEqual(*(it+1), toXmlChar("graph"))) { 
 
513
        trie=&state->g_names;
 
514
        ptrvector=&state->g_attrs;
 
515
      } else if (xmlStrEqual(*(it+1), toXmlChar("node"))) {
 
516
        trie=&state->v_names;
 
517
        ptrvector=&state->v_attrs;
 
518
      } else if (xmlStrEqual(*(it+1), toXmlChar("edge"))) {
 
519
        trie=&state->e_names;
 
520
        ptrvector=&state->e_attrs;
 
521
      } else {
 
522
        igraph_error("Cannot parse GraphML file, unknown attribute type",
 
523
                     __FILE__, __LINE__, IGRAPH_PARSEERROR);
 
524
        igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file, unknown attribute type");
 
525
        return;
 
526
      }
 
527
    }
 
528
  }
 
529
 
 
530
  if (trie == 0 && state->successful) {
 
531
    igraph_error("Cannot parse GraphML file, missing 'for' attribute", __FILE__, __LINE__, IGRAPH_PARSEERROR);
 
532
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file, missing 'for' attribute");
 
533
    return;
 
534
  }
 
535
        
 
536
  /* add to trie, attribues */
 
537
  igraph_trie_get(trie, rec->id, &id);
 
538
  if (id != igraph_trie_size(trie)-1) {
 
539
    igraph_error("Cannot parse GraphML file, duplicate attribute", 
 
540
                 __FILE__, __LINE__, IGRAPH_PARSEERROR);
 
541
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file, duplicate attribute");
 
542
    return;
 
543
  }
 
544
  ret=igraph_vector_ptr_push_back(ptrvector, rec);
 
545
  if (ret) {
 
546
    igraph_error("Cannot read GraphML file", __FILE__, __LINE__, ret);
 
547
    igraph_i_graphml_sax_handler_error(state, "Cannot read GraphML file");
 
548
    return;
 
549
  }
 
550
 
 
551
  /* create the attribute values */
 
552
  switch (rec->record.type) {
 
553
    igraph_vector_t *vec;
 
554
    igraph_strvector_t *strvec;
 
555
  case IGRAPH_ATTRIBUTE_NUMERIC:
 
556
    vec=igraph_Calloc(1, igraph_vector_t);
 
557
    if (vec==0) {
 
558
      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__,
 
559
                   IGRAPH_ENOMEM);
 
560
      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
561
      return;
 
562
    }
 
563
    rec->record.value=vec;
 
564
    igraph_vector_init(vec, 0);    
 
565
    break;
 
566
  case IGRAPH_ATTRIBUTE_STRING:
 
567
    strvec=igraph_Calloc(1, igraph_strvector_t);
 
568
    if (strvec==0) {
 
569
      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, 
 
570
                   IGRAPH_ENOMEM);
 
571
      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
572
      return;
 
573
    }
 
574
    rec->record.value=strvec;
 
575
    igraph_strvector_init(strvec, 0);
 
576
    break;
 
577
  default: break;
 
578
  }
 
579
 
 
580
  IGRAPH_FINALLY_CLEAN(1);      /* rec */
 
581
}
 
582
 
 
583
void igraph_i_graphml_attribute_data_setup(struct igraph_i_graphml_parser_state *state,
 
584
                                           const xmlChar **attrs,
 
585
                                           igraph_attribute_elemtype_t type) {
 
586
  xmlChar **it;
 
587
  for (it=(xmlChar**)attrs; *it; it+=2) {
 
588
    if (xmlStrEqual(*it, toXmlChar("key"))) {
 
589
      if (state->data_key) {
 
590
        free(state->data_key);
 
591
      }
 
592
      state->data_key=xmlStrdup(*(it+1));
 
593
      if (state->data_char) {
 
594
        free(state->data_char);
 
595
      }
 
596
      state->data_char=0;
 
597
      state->data_type=type;
 
598
    } else {
 
599
      /* ignore */
 
600
    }
 
601
  }
 
602
}
 
603
 
 
604
void igraph_i_graphml_attribute_data_add(struct igraph_i_graphml_parser_state *state,
 
605
                                         const xmlChar *data, int len) {
 
606
  long int data_char_new_start=0;
 
607
 
 
608
  if (!state->successful) return;
 
609
 
 
610
  if (state->data_char) {
 
611
    data_char_new_start=strlen(state->data_char);
 
612
    state->data_char=igraph_Realloc(state->data_char, data_char_new_start+len+1, char);
 
613
  } else {
 
614
    state->data_char=igraph_Calloc(len+1, char);
 
615
  }
 
616
  if (state->data_char==0) {
 
617
    igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, 
 
618
                 IGRAPH_ENOMEM);
 
619
    igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
620
    return;
 
621
  }
 
622
  memcpy(state->data_char+data_char_new_start, data, len*sizeof(xmlChar));
 
623
  state->data_char[data_char_new_start+len]='\0';
 
624
}
 
625
 
 
626
void igraph_i_graphml_attribute_data_finish(struct igraph_i_graphml_parser_state *state) {
 
627
  const char *key=fromXmlChar(state->data_key);
 
628
  igraph_attribute_elemtype_t type=state->data_type;
 
629
  igraph_trie_t *trie=0;
 
630
  igraph_vector_ptr_t *ptrvector=0;
 
631
  igraph_i_graphml_attribute_record_t *graphmlrec;
 
632
  igraph_i_attribute_record_t *rec;
 
633
  long int recid, id=0;
 
634
  int ret;
 
635
  
 
636
  switch (type) {
 
637
  case IGRAPH_ATTRIBUTE_GRAPH:
 
638
    trie=&state->g_names;
 
639
    ptrvector=&state->g_attrs;
 
640
    id=0;
 
641
    break;
 
642
  case IGRAPH_ATTRIBUTE_VERTEX:
 
643
    trie=&state->v_names;
 
644
    ptrvector=&state->v_attrs;
 
645
    id=igraph_trie_size(&state->node_trie)-1; /* hack */
 
646
    break;
 
647
  case IGRAPH_ATTRIBUTE_EDGE:
 
648
    trie=&state->e_names;
 
649
    ptrvector=&state->e_attrs;
 
650
    id=igraph_vector_size(&state->edgelist)/2-1; /* hack */
 
651
    break;
 
652
  default:
 
653
    /* impossible */
 
654
    break;
 
655
  }
 
656
  
 
657
  igraph_trie_check(trie, key, &recid);
 
658
  if (recid < 0) {
 
659
    /* no such attribute key, issue a warning */
 
660
    IGRAPH_WARNING("unknown attribute key in GraphML file, ignoring attribute");
 
661
    igraph_Free(state->data_char);
 
662
    return;
 
663
  }
 
664
   
 
665
  graphmlrec=VECTOR(*ptrvector)[recid];
 
666
  rec=&graphmlrec->record;
 
667
 
 
668
  switch (rec->type) {
 
669
    igraph_vector_t *vec;
 
670
    igraph_strvector_t *strvec;
 
671
    igraph_real_t num;
 
672
    long int s, i;
 
673
  case IGRAPH_ATTRIBUTE_NUMERIC:
 
674
    vec=(igraph_vector_t *)rec->value;
 
675
    s=igraph_vector_size(vec);
 
676
    if (id >= s) {
 
677
      ret=igraph_vector_resize(vec, id+1);
 
678
      if (ret) {
 
679
        igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
 
680
        igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
681
        return;
 
682
      }
 
683
      for (i=s; i<id; i++) {
 
684
        VECTOR(*vec)[i]=IGRAPH_NAN;
 
685
      }
 
686
    }
 
687
    if (state->data_char)
 
688
      sscanf(state->data_char, "%lf", &num);
 
689
    else
 
690
      num=0;
 
691
    VECTOR(*vec)[id]=num;
 
692
    break;
 
693
  case IGRAPH_ATTRIBUTE_STRING:
 
694
    strvec=(igraph_strvector_t *)rec->value;
 
695
    s=igraph_strvector_size(strvec);
 
696
    if (id >= s) {
 
697
      ret=igraph_strvector_resize(strvec, id+1);
 
698
      if (ret) {
 
699
        igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
 
700
        igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
701
        return;
 
702
      }
 
703
      for (i=s;i<id;i++) {
 
704
        igraph_strvector_set(strvec, i, "");
 
705
      }
 
706
    }
 
707
    if (state->data_char)
 
708
      ret=igraph_strvector_set(strvec, id, (char*)state->data_char);
 
709
    else
 
710
      ret=igraph_strvector_set(strvec, id, "");
 
711
    if (ret) {
 
712
      igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
 
713
      igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
 
714
      return;
 
715
    }
 
716
    break;
 
717
  default:
 
718
    break;
 
719
  }
 
720
 
 
721
  if (state->data_char) igraph_Free(state->data_char);
 
722
}
 
723
 
 
724
void igraph_i_graphml_sax_handler_start_element(void *state0,
 
725
                                                const xmlChar* name,
 
726
                                                const xmlChar** attrs) {
 
727
  struct igraph_i_graphml_parser_state *state=
 
728
    (struct igraph_i_graphml_parser_state*)state0;
 
729
  xmlChar** it;
 
730
  long int id1, id2;
 
731
  unsigned short int directed;
 
732
 
 
733
  switch (state->st) {
 
734
  case START:
 
735
    /* If we are in the START state and received a graphml tag,
 
736
     * change to INSIDE_GRAPHML state. Otherwise, change to UNKNOWN. */
 
737
    if (xmlStrEqual(name, toXmlChar("graphml")))
 
738
      state->st=INSIDE_GRAPHML;
 
739
    else
 
740
      igraph_i_graphml_handle_unknown_start_tag(state);
 
741
    break;
 
742
    
 
743
  case INSIDE_GRAPHML:
 
744
    /* If we are in the INSIDE_GRAPHML state and received a graph tag,
 
745
     * change to INSIDE_GRAPH state if the state->index counter reached
 
746
     * zero (this is to handle multiple graphs in the same file).
 
747
     * Otherwise, change to UNKNOWN. */
 
748
    if (xmlStrEqual(name, toXmlChar("graph"))) {
 
749
      if (state->index==0) {
 
750
        state->st=INSIDE_GRAPH;
 
751
        for (it=(xmlChar**)attrs; *it; it+=2) {
 
752
          if (xmlStrEqual(*it, toXmlChar("edgedefault"))) {
 
753
            if (xmlStrEqual(*(it+1), toXmlChar("directed"))) state->edges_directed=1;
 
754
            else if (xmlStrEqual(*(it+1), toXmlChar("undirected"))) state->edges_directed=0;
 
755
          }
 
756
        }
 
757
      }
 
758
      state->index--;
 
759
    } else if (xmlStrEqual(name, toXmlChar("key"))) {
 
760
      igraph_i_graphml_add_attribute_key(attrs, state);
 
761
      state->st=INSIDE_KEY;
 
762
    } else
 
763
      igraph_i_graphml_handle_unknown_start_tag(state);
 
764
    break;
 
765
 
 
766
  case INSIDE_KEY:
 
767
    /* If we are in the INSIDE_KEY state, check for default tag */
 
768
    if (xmlStrEqual(name, toXmlChar("default"))) state->st=INSIDE_DEFAULT;
 
769
    else igraph_i_graphml_handle_unknown_start_tag(state);
 
770
    break;
 
771
 
 
772
  case INSIDE_DEFAULT:
 
773
    /* If we are in the INSIDE_DEFAULT state, every further tag will be unknown */
 
774
    igraph_i_graphml_handle_unknown_start_tag(state);
 
775
    break;
 
776
    
 
777
  case INSIDE_GRAPH:
 
778
    /* If we are in the INSIDE_GRAPH state, check for node and edge tags */
 
779
    if (xmlStrEqual(name, toXmlChar("edge"))) {
 
780
      id1=-1; id2=-1; directed=state->edges_directed;
 
781
      for (it=(xmlChar**)attrs; *it; it+=2) {
 
782
        if (xmlStrEqual(*it, toXmlChar("source"))) {
 
783
          igraph_trie_get(&state->node_trie, fromXmlChar(*(it+1)), &id1);
 
784
        }
 
785
        if (xmlStrEqual(*it, toXmlChar("target"))) {
 
786
          igraph_trie_get(&state->node_trie, fromXmlChar(*(it+1)), &id2);
 
787
        }
 
788
        if (xmlStrEqual(*it, toXmlChar("id"))) {
 
789
          long int edges=igraph_vector_size(&state->edgelist)/2+1;
 
790
          long int origsize=igraph_strvector_size(&state->edgeids);
 
791
          igraph_strvector_resize(&state->edgeids, edges);
 
792
          for (;origsize < edges-1; origsize++) {
 
793
            igraph_strvector_set(&state->edgeids, origsize, "");
 
794
          }
 
795
          igraph_strvector_set(&state->edgeids, edges-1, fromXmlChar(*(it+1)));
 
796
        }
 
797
      }
 
798
      if (id1>=0 && id2>=0) {
 
799
        igraph_vector_push_back(&state->edgelist, id1);
 
800
        igraph_vector_push_back(&state->edgelist, id2);
 
801
      } else {
 
802
        igraph_i_graphml_sax_handler_error(state, "Edge with missing source or target encountered");
 
803
        return;
 
804
      }
 
805
      state->st=INSIDE_EDGE;
 
806
    } else if (xmlStrEqual(name, toXmlChar("node"))) {
 
807
      for (it=(xmlChar**)attrs; *it; it+=2) {
 
808
        if (xmlStrEqual(*it, toXmlChar("id"))) {
 
809
          it++;
 
810
          igraph_trie_get(&state->node_trie, fromXmlChar(*it), &id1);
 
811
          break;
 
812
        }
 
813
      }
 
814
      state->st=INSIDE_NODE;
 
815
    } else if (xmlStrEqual(name, toXmlChar("data"))) {
 
816
      igraph_i_graphml_attribute_data_setup(state, attrs, IGRAPH_ATTRIBUTE_GRAPH);
 
817
      state->prev_state=state->st;
 
818
      state->st=INSIDE_DATA;
 
819
    } else
 
820
      igraph_i_graphml_handle_unknown_start_tag(state);
 
821
    break;
 
822
    
 
823
  case INSIDE_NODE:
 
824
    if (xmlStrEqual(name, toXmlChar("data"))) {
 
825
      igraph_i_graphml_attribute_data_setup(state, attrs,
 
826
                                            IGRAPH_ATTRIBUTE_VERTEX);
 
827
      state->prev_state=state->st;
 
828
      state->st=INSIDE_DATA;
 
829
    }
 
830
    break;
 
831
    
 
832
  case INSIDE_EDGE:
 
833
    if (xmlStrEqual(name, toXmlChar("data"))) {
 
834
      igraph_i_graphml_attribute_data_setup(state, attrs, 
 
835
                                            IGRAPH_ATTRIBUTE_EDGE);
 
836
      state->prev_state=state->st;
 
837
      state->st=INSIDE_DATA;
 
838
    }
 
839
    break;
 
840
    
 
841
  default:
 
842
    break;
 
843
  }
 
844
}
 
845
 
 
846
void igraph_i_graphml_sax_handler_end_element(void *state0,
 
847
                                                const xmlChar* name) {
 
848
  struct igraph_i_graphml_parser_state *state=
 
849
    (struct igraph_i_graphml_parser_state*)state0;
 
850
  
 
851
  switch (state->st) {
 
852
  case INSIDE_GRAPHML:
 
853
    state->st=FINISH;
 
854
    break;
 
855
    
 
856
  case INSIDE_GRAPH:
 
857
    state->st=INSIDE_GRAPHML;
 
858
    break;
 
859
    
 
860
  case INSIDE_KEY:
 
861
    state->st=INSIDE_GRAPHML;
 
862
    break;
 
863
 
 
864
  case INSIDE_DEFAULT:
 
865
    state->st=INSIDE_KEY;
 
866
    break;
 
867
    
 
868
  case INSIDE_NODE:
 
869
    state->st=INSIDE_GRAPH;
 
870
    break;
 
871
    
 
872
  case INSIDE_EDGE:
 
873
    state->st=INSIDE_GRAPH;
 
874
    break;
 
875
 
 
876
  case INSIDE_DATA:
 
877
    igraph_i_graphml_attribute_data_finish(state);
 
878
    state->st=state->prev_state;
 
879
    break;
 
880
    
 
881
  case UNKNOWN:
 
882
    state->unknown_depth--;
 
883
    if (!state->unknown_depth) state->st=state->prev_state;
 
884
    break;
 
885
    
 
886
  default:
 
887
    break;
 
888
  }
 
889
}
 
890
 
 
891
void igraph_i_graphml_sax_handler_chars(void* state0, const xmlChar* ch, int len) {
 
892
  struct igraph_i_graphml_parser_state *state=
 
893
    (struct igraph_i_graphml_parser_state*)state0;
 
894
  
 
895
  switch (state->st) {
 
896
  case INSIDE_KEY:
 
897
  case INSIDE_DEFAULT:
 
898
    break;
 
899
    
 
900
  case INSIDE_DATA:
 
901
    igraph_i_graphml_attribute_data_add(state, ch, len);
 
902
    break;
 
903
    
 
904
  default:
 
905
    /* just ignore it */
 
906
    break;
 
907
  }
 
908
}
 
909
 
 
910
static xmlSAXHandler igraph_i_graphml_sax_handler={
 
911
  NULL, NULL, NULL, NULL, NULL,
 
912
    igraph_i_graphml_sax_handler_get_entity,
 
913
    NULL, NULL, NULL, NULL, NULL, NULL,
 
914
    igraph_i_graphml_sax_handler_start_document,
 
915
    igraph_i_graphml_sax_handler_end_document,
 
916
    igraph_i_graphml_sax_handler_start_element,
 
917
    igraph_i_graphml_sax_handler_end_element,
 
918
    NULL,
 
919
    igraph_i_graphml_sax_handler_chars,
 
920
    NULL, NULL, NULL,
 
921
    igraph_i_graphml_sax_handler_error,
 
922
    igraph_i_graphml_sax_handler_error,
 
923
    igraph_i_graphml_sax_handler_error,
 
924
};
 
925
 
 
926
#endif
 
927
 
 
928
int igraph_i_xml_escape(char* src, char** dest) {
 
929
  long int destlen=0;
 
930
  char *s, *d;
 
931
  for (s=src; *s; s++, destlen++) {
 
932
    if (*s == '&') destlen += 4;
 
933
    else if (*s == '<') destlen += 3;
 
934
    else if (*s == '>') destlen += 3;
 
935
    else if (*s == '"') destlen += 5;
 
936
    else if (*s == '\'') destlen += 5;
 
937
  }
 
938
  *dest=igraph_Calloc(destlen+1, char);
 
939
  if (!*dest) IGRAPH_ERROR("Not enough memory", IGRAPH_ENOMEM);
 
940
  for (s=src, d=*dest; *s; s++, d++) {
 
941
    switch (*s) {
 
942
    case '&':
 
943
      strcpy(d, "&amp;"); d+=4; break;
 
944
    case '<':
 
945
      strcpy(d, "&lt;"); d+=3; break;
 
946
    case '>':
 
947
      strcpy(d, "&gt;"); d+=3; break;
 
948
    case '"':
 
949
      strcpy(d, "&quot;"); d+=5; break;
 
950
    case '\'':
 
951
      strcpy(d, "&apos;"); d+=5; break;
 
952
    default:
 
953
      *d = *s;
 
954
    }
 
955
  }
 
956
  *d=0;
 
957
  return 0;
 
958
}
 
959
 
 
960
/**
 
961
 * \ingroup loadsave
 
962
 * \function igraph_read_graph_graphml
 
963
 * \brief Reads a graph from a GraphML file.
 
964
 * 
 
965
 * </para><para>
 
966
 * GraphML is an XML-based file format for representing various types of
 
967
 * graphs. Currently only the most basic import functionality is implemented
 
968
 * in igraph: it can read GraphML files without nested graphs and hyperedges.
 
969
 * Attributes of the graph are loaded only if an attribute interface
 
970
 * is attached, ie. if you use igraph from R or Python.
 
971
 * \param graph Pointer to an uninitialized graph object.
 
972
 * \param instream A stream, it should be readable.
 
973
 * \param index If the GraphML file contains more than one graph, the one
 
974
 *              specified by this index will be loaded. Indices start from
 
975
 *              zero, so supply zero here if your GraphML file contains only
 
976
 *              a single graph.
 
977
 * 
 
978
 * \return Error code:
 
979
 *         \c IGRAPH_PARSEERROR: if there is a
 
980
 *         problem reading the file, or the file is syntactically
 
981
 *         incorrect.
 
982
 *         \c IGRAPH_UNIMPLEMENTED: the GraphML functionality was disabled
 
983
 *         at compile-time
 
984
 */
 
985
int igraph_read_graph_graphml(igraph_t *graph, FILE *instream,
 
986
                              int index) {
 
987
 
 
988
#if HAVE_LIBXML == 1
 
989
  xmlParserCtxtPtr ctxt;
 
990
  struct igraph_i_graphml_parser_state state;
 
991
  int res;
 
992
  char buffer[4096];
 
993
 
 
994
  if (index<0)
 
995
    IGRAPH_ERROR("Graph index must be non-negative", IGRAPH_EINVAL);
 
996
  
 
997
  /* Create a progressive parser context */
 
998
  state.g=graph;
 
999
  state.index=index<0?0:index;
 
1000
  res=fread(buffer, 1, 4096, instream);
 
1001
  ctxt=xmlCreatePushParserCtxt(&igraph_i_graphml_sax_handler,
 
1002
                               &state,
 
1003
                               buffer,
 
1004
                               res,
 
1005
                               NULL);
 
1006
/*   ctxt=xmlCreateIOParserCtxt(&igraph_i_graphml_sax_handler, &state, */
 
1007
/*                           igraph_i_libxml2_read_callback, */
 
1008
/*                           igraph_i_libxml2_close_callback, */
 
1009
/*                           instream, XML_CHAR_ENCODING_NONE); */
 
1010
  if (ctxt==NULL)
 
1011
    IGRAPH_ERROR("Can't create progressive parser context", IGRAPH_PARSEERROR);
 
1012
 
 
1013
  /* Parse the file */
 
1014
  while ((res=fread(buffer, 1, 4096, instream))>0) {
 
1015
    xmlParseChunk(ctxt, buffer, res, 0);
 
1016
    if (!state.successful) break;
 
1017
  }
 
1018
  xmlParseChunk(ctxt, buffer, res, 1);
 
1019
  
 
1020
  /* Free the context */
 
1021
  xmlFreeParserCtxt(ctxt);
 
1022
  if (!state.successful) {
 
1023
    if (state.error_message != 0)
 
1024
      IGRAPH_ERROR(state.error_message, IGRAPH_PARSEERROR);
 
1025
    else
 
1026
      IGRAPH_ERROR("Malformed GraphML file", IGRAPH_PARSEERROR);
 
1027
  }
 
1028
  if (state.index>=0)
 
1029
    IGRAPH_ERROR("Graph index was too large", IGRAPH_EINVAL);
 
1030
  
 
1031
  return 0;
 
1032
#else
 
1033
  IGRAPH_ERROR("GraphML support is disabled", IGRAPH_UNIMPLEMENTED);
 
1034
#endif
 
1035
}
 
1036
 
 
1037
/**
 
1038
 * \ingroup loadsave
 
1039
 * \function igraph_write_graph_graphml
 
1040
 * \brief Writes the graph to a file in GraphML format
 
1041
 *
 
1042
 * </para><para>
 
1043
 * GraphML is an XML-based file format for representing various types of
 
1044
 * graphs. See the GraphML Primer (http://graphml.graphdrawing.org/primer/graphml-primer.html)
 
1045
 * for detailed format description.
 
1046
 * 
 
1047
 * \param graph The graph to write. 
 
1048
 * \param outstream The stream object to write to, it should be
 
1049
 *        writable.
 
1050
 * \return Error code:
 
1051
 *         \c IGRAPH_EFILE if there is an error
 
1052
 *         writing the file. 
 
1053
 *
 
1054
 * Time complexity: O(|V|+|E|) otherwise. All
 
1055
 * file operations are expected to have time complexity 
 
1056
 * O(1). 
 
1057
 */
 
1058
int igraph_write_graph_graphml(const igraph_t *graph, FILE *outstream) {
 
1059
  int ret;
 
1060
  igraph_integer_t l, vc;
 
1061
  igraph_eit_t it;
 
1062
  igraph_strvector_t gnames, vnames, enames;
 
1063
  igraph_vector_t gtypes, vtypes, etypes;
 
1064
  long int i;
 
1065
  igraph_vector_t numv;
 
1066
  igraph_strvector_t strv;
 
1067
  
 
1068
  ret=fprintf(outstream, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
 
1069
  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1070
  ret=fprintf(outstream, "<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\"\n");
 
1071
  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1072
  ret=fprintf(outstream, "         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
 
1073
  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1074
  ret=fprintf(outstream, "         xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns\n");
 
1075
  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1076
  ret=fprintf(outstream, "         http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">\n");
 
1077
  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1078
  ret=fprintf(outstream, "<!-- Created by igraph -->\n");
 
1079
  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1080
 
 
1081
  /* dump the <key> elements if any */
 
1082
 
 
1083
  IGRAPH_VECTOR_INIT_FINALLY(&numv, 1);
 
1084
  IGRAPH_STRVECTOR_INIT_FINALLY(&strv, 1);
 
1085
  
 
1086
  IGRAPH_STRVECTOR_INIT_FINALLY(&gnames, 0);
 
1087
  IGRAPH_STRVECTOR_INIT_FINALLY(&vnames, 0);
 
1088
  IGRAPH_STRVECTOR_INIT_FINALLY(&enames, 0);
 
1089
  IGRAPH_VECTOR_INIT_FINALLY(&gtypes, 0);
 
1090
  IGRAPH_VECTOR_INIT_FINALLY(&vtypes, 0);
 
1091
  IGRAPH_VECTOR_INIT_FINALLY(&etypes, 0);
 
1092
  igraph_i_attribute_get_info(graph,
 
1093
                              &gnames, &gtypes,
 
1094
                              &vnames, &vtypes,
 
1095
                              &enames, &etypes);
 
1096
  
 
1097
  /* graph attributes */
 
1098
  for (i=0; i<igraph_vector_size(&gtypes); i++) {
 
1099
    char *name, *name_escaped;
 
1100
    igraph_strvector_get(&gnames, i, &name);
 
1101
    IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
 
1102
    if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
 
1103
      ret=fprintf(outstream, "  <key id=\"%s\" for=\"graph\" attr.name=\"%s\" attr.type=\"string\"/>\n", name_escaped, name_escaped);
 
1104
      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);      
 
1105
    } else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
 
1106
      ret=fprintf(outstream, "  <key id=\"%s\" for=\"graph\" attr.name=\"%s\" attr.type=\"double\"/>\n", name_escaped, name_escaped);
 
1107
      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);            
 
1108
    }
 
1109
    igraph_Free(name_escaped);
 
1110
  }
 
1111
 
 
1112
  /* vertex attributes */
 
1113
  for (i=0; i<igraph_vector_size(&vtypes); i++) {
 
1114
    char *name, *name_escaped;
 
1115
    igraph_strvector_get(&vnames, i, &name);
 
1116
    IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
 
1117
    if (VECTOR(vtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
 
1118
      ret=fprintf(outstream, "  <key id=\"%s\" for=\"node\" attr.name=\"%s\" attr.type=\"string\"/>\n", name_escaped, name_escaped);
 
1119
      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);      
 
1120
    } else if (VECTOR(vtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
 
1121
      ret=fprintf(outstream, "  <key id=\"%s\" for=\"node\" attr.name=\"%s\" attr.type=\"double\"/>\n", name_escaped, name_escaped);
 
1122
      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);            
 
1123
    }
 
1124
    igraph_Free(name_escaped);
 
1125
  }
 
1126
 
 
1127
  /* edge attributes */
 
1128
  for (i=0; i<igraph_vector_size(&etypes); i++) {
 
1129
    char *name, *name_escaped;
 
1130
    igraph_strvector_get(&enames, i, &name);
 
1131
    IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
 
1132
    if (VECTOR(etypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
 
1133
      ret=fprintf(outstream, "  <key id=\"%s\" for=\"edge\" attr.name=\"%s\" attr.type=\"string\"/>\n", name_escaped, name_escaped);
 
1134
      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1135
    } else if (VECTOR(etypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
 
1136
      ret=fprintf(outstream, "  <key id=\"%s\" for=\"edge\" attr.name=\"%s\" attr.type=\"double\"/>\n", name_escaped, name_escaped);
 
1137
      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1138
    }
 
1139
    igraph_Free(name_escaped);
 
1140
  }
 
1141
 
 
1142
  ret=fprintf(outstream, "  <graph id=\"G\" edgedefault=\"%s\">\n", (igraph_is_directed(graph)?"directed":"undirected"));
 
1143
  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1144
 
 
1145
  /* Write the graph atributes before anything else */
 
1146
  
 
1147
  for (i=0; i<igraph_vector_size(&gtypes); i++) {
 
1148
    char *name, *name_escaped;
 
1149
    if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
 
1150
      igraph_strvector_get(&gnames, i, &name);
 
1151
      igraph_i_attribute_get_numeric_graph_attr(graph, name, &numv);
 
1152
      if (!isnan(VECTOR(numv)[0])) {
 
1153
        IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
 
1154
        ret=fprintf(outstream, "    <data key=\"%s\">%g</data>\n",
 
1155
                    name_escaped, VECTOR(numv)[0]);
 
1156
        igraph_Free(name_escaped);
 
1157
        if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1158
      }
 
1159
    } else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
 
1160
      char *s, *s_escaped;
 
1161
      igraph_strvector_get(&gnames, i, &name);
 
1162
      IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
 
1163
      ret=fprintf(outstream, "    <data key=\"%s\">", name_escaped);
 
1164
      igraph_Free(name_escaped);
 
1165
      igraph_i_attribute_get_string_graph_attr(graph, name, &strv);
 
1166
      igraph_strvector_get(&strv, 0, &s);
 
1167
      IGRAPH_CHECK(igraph_i_xml_escape(s, &s_escaped));
 
1168
      ret=fprintf(outstream, "%s", s_escaped);
 
1169
      igraph_Free(s_escaped);
 
1170
      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1171
      ret=fprintf(outstream, "</data>\n");
 
1172
      if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1173
    }
 
1174
  }
 
1175
    
 
1176
  /* Let's dump the nodes first */
 
1177
  vc=igraph_vcount(graph);
 
1178
  for (l=0; l<vc; l++) {
 
1179
    char *name, *name_escaped;
 
1180
    ret=fprintf(outstream, "    <node id=\"n%ld\">\n", (long)l);
 
1181
 
 
1182
    if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1183
    
 
1184
    for (i=0; i<igraph_vector_size(&vtypes); i++) {
 
1185
      if (VECTOR(vtypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
 
1186
        igraph_strvector_get(&vnames, i, &name);
 
1187
        igraph_i_attribute_get_numeric_vertex_attr(graph, name,
 
1188
                                                   igraph_vss_1(l), &numv);
 
1189
        if (!isnan(VECTOR(numv)[0])) {
 
1190
          IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
 
1191
          ret=fprintf(outstream, "      <data key=\"%s\">%g</data>\n",
 
1192
                      name_escaped, VECTOR(numv)[0]);
 
1193
          igraph_Free(name_escaped);
 
1194
          if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1195
        }
 
1196
      } else if (VECTOR(vtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
 
1197
        char *s, *s_escaped;
 
1198
        igraph_strvector_get(&vnames, i, &name);
 
1199
        IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
 
1200
        ret=fprintf(outstream, "      <data key=\"%s\">", name_escaped);
 
1201
        igraph_Free(name_escaped);
 
1202
        igraph_i_attribute_get_string_vertex_attr(graph, name,
 
1203
                                                  igraph_vss_1(l), &strv);
 
1204
        igraph_strvector_get(&strv, 0, &s);
 
1205
        IGRAPH_CHECK(igraph_i_xml_escape(s, &s_escaped));
 
1206
        ret=fprintf(outstream, "%s", s_escaped);
 
1207
        igraph_Free(s_escaped);
 
1208
        if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1209
        ret=fprintf(outstream, "</data>\n");
 
1210
        if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1211
      }
 
1212
    }
 
1213
 
 
1214
    ret=fprintf(outstream, "    </node>\n");
 
1215
    if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);    
 
1216
  }
 
1217
  
 
1218
  /* Now the edges */
 
1219
  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &it));
 
1220
  IGRAPH_FINALLY(igraph_eit_destroy, &it);
 
1221
  while (!IGRAPH_EIT_END(it)) {
 
1222
    igraph_integer_t from, to;
 
1223
    char *name, *name_escaped;
 
1224
    long int edge=IGRAPH_EIT_GET(it);
 
1225
    igraph_edge(graph, edge, &from, &to);
 
1226
    ret=fprintf(outstream, "    <edge source=\"n%ld\" target=\"n%ld\">\n", 
 
1227
                (long int)from, (long int)to);
 
1228
    if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1229
 
 
1230
    for (i=0; i<igraph_vector_size(&etypes); i++) {
 
1231
      if (VECTOR(etypes)[i] == IGRAPH_ATTRIBUTE_NUMERIC) {
 
1232
        igraph_strvector_get(&enames, i, &name);
 
1233
        igraph_i_attribute_get_numeric_edge_attr(graph, name,
 
1234
                                                 igraph_ess_1(edge), &numv);
 
1235
        if (!isnan(VECTOR(numv)[0])) {
 
1236
          IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
 
1237
          ret=fprintf(outstream, "      <data key=\"%s\">%g</data>\n",
 
1238
                      name_escaped, VECTOR(numv)[0]);
 
1239
          igraph_Free(name_escaped);
 
1240
          if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1241
        }
 
1242
        if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);      
 
1243
      } else if (VECTOR(etypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
 
1244
        char *s, *s_escaped;
 
1245
        igraph_strvector_get(&enames, i, &name);
 
1246
        IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
 
1247
        ret=fprintf(outstream, "      <data key=\"%s\">", name_escaped);
 
1248
        igraph_Free(name_escaped);
 
1249
        igraph_i_attribute_get_string_edge_attr(graph, name,
 
1250
                                                igraph_ess_1(edge), &strv);
 
1251
        igraph_strvector_get(&strv, 0, &s);
 
1252
        IGRAPH_CHECK(igraph_i_xml_escape(s, &s_escaped));
 
1253
        ret=fprintf(outstream, "%s", s_escaped);
 
1254
        igraph_Free(s_escaped);
 
1255
        if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1256
        ret=fprintf(outstream, "</data>\n");
 
1257
        if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1258
      }
 
1259
    }
 
1260
 
 
1261
    ret=fprintf(outstream, "    </edge>\n");
 
1262
    if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1263
    IGRAPH_EIT_NEXT(it);
 
1264
  }
 
1265
  igraph_eit_destroy(&it);
 
1266
  IGRAPH_FINALLY_CLEAN(1);
 
1267
  
 
1268
  ret=fprintf(outstream, "  </graph>\n");
 
1269
  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1270
  fprintf(outstream, "</graphml>\n");
 
1271
  if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
 
1272
  
 
1273
  igraph_strvector_destroy(&gnames);
 
1274
  igraph_strvector_destroy(&vnames);
 
1275
  igraph_strvector_destroy(&enames);
 
1276
  igraph_vector_destroy(&gtypes);
 
1277
  igraph_vector_destroy(&vtypes);
 
1278
  igraph_vector_destroy(&etypes);
 
1279
  igraph_vector_destroy(&numv);
 
1280
  igraph_strvector_destroy(&strv);
 
1281
  IGRAPH_FINALLY_CLEAN(8);
 
1282
 
 
1283
  return 0;
 
1284
}