4
Copyright (C) 2006 Gabor Csardi <csardi@rmki.kfki.hu>
5
MTA RMKI, Konkoly-Thege Miklos st. 29-33, Budapest 1121, Hungary
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.
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.
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
26
#include "igraph_math.h"
28
#include <ctype.h> /* isspace */
29
#include <math.h> /* isnan */
32
#include <stdarg.h> /* va_start & co */
35
#include <libxml/encoding.h>
36
#include <libxml/parser.h>
39
xmlEntity blankEntityStruct = {
40
#ifndef XML_WITHOUT_CORBA
54
XML_EXTERNAL_GENERAL_PARSED_ENTITY,
61
xmlEntityPtr blankEntity = &blankEntityStruct;
63
/* TODO: proper error handling */
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;
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;
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;
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;
91
igraph_attribute_elemtype_t data_type;
96
void igraph_i_graphml_destroy_state(struct igraph_i_graphml_parser_state* state) {
99
if (state->destroyed) return;
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);
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); }
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);
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);
127
if (rec->id != 0) igraph_Free(rec->id);
128
if (rec->record.name != 0) igraph_Free(rec->record.name);
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);
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);
145
if (rec->id != 0) igraph_Free(rec->id);
146
if (rec->record.name != 0) igraph_Free(rec->record.name);
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);
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);
163
if (rec->id != 0) igraph_Free(rec->id);
164
if (rec->record.name != 0) igraph_Free(rec->record.name);
168
igraph_vector_ptr_destroy(&state->v_attrs);
169
igraph_vector_ptr_destroy(&state->e_attrs);
170
igraph_vector_ptr_destroy(&state->g_attrs);
172
IGRAPH_FINALLY_CLEAN(1);
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;
182
if (state->error_message == 0)
183
state->error_message=igraph_Calloc(4096, char);
187
vsnprintf(state->error_message, 4096, msg, ap);
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");
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;
204
state->unknown_depth=1;
205
} else state->unknown_depth++;
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;
215
state->edges_directed=0;
218
state->error_message=0;
221
ret=igraph_vector_ptr_init(&state->v_attrs, 0);
223
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
224
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
227
IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->v_attrs);
228
ret=igraph_vector_ptr_init(&state->e_attrs, 0);
230
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
231
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
234
IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->e_attrs);
235
ret=igraph_vector_ptr_init(&state->g_attrs, 0);
237
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
238
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
241
IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->g_attrs);
242
ret=igraph_vector_init(&state->edgelist, 0);
244
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
245
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
248
IGRAPH_FINALLY(igraph_vector_destroy, &state->edgelist);
249
ret=igraph_trie_init(&state->node_trie, 1);
251
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
252
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
255
IGRAPH_FINALLY(igraph_trie_destroy, &state->node_trie);
256
ret=igraph_strvector_init(&state->edgeids, 0);
258
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
259
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
262
IGRAPH_FINALLY(igraph_strvector_destroy, &state->edgeids);
263
ret=igraph_trie_init(&state->v_names, 0);
265
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
266
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
269
IGRAPH_FINALLY(igraph_trie_destroy, &state->v_names);
270
ret=igraph_trie_init(&state->e_names, 0);
272
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
273
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
276
IGRAPH_FINALLY(igraph_trie_destroy, &state->e_names);
277
ret=igraph_trie_init(&state->g_names, 0);
279
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
280
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
283
IGRAPH_FINALLY(igraph_trie_destroy, &state->g_names);
285
IGRAPH_FINALLY_CLEAN(9);
286
IGRAPH_FINALLY(igraph_i_graphml_destroy_state, state);
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;
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;
298
if (!state->successful) return;
300
if (state->index<0) {
302
igraph_vector_ptr_t vattr, eattr, gattr;
303
long int esize=igraph_vector_ptr_size(&state->e_attrs);
305
r=igraph_vector_ptr_init(&vattr,
306
igraph_vector_ptr_size(&state->v_attrs)+1);
308
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, r);
309
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
312
IGRAPH_FINALLY(igraph_vector_ptr_destroy, &vattr);
313
if (igraph_strvector_size(&state->edgeids) != 0) {
316
r=igraph_vector_ptr_init(&eattr, esize);
318
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, r);
319
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
322
IGRAPH_FINALLY(igraph_vector_ptr_destroy, &eattr);
323
r=igraph_vector_ptr_init(&gattr, igraph_vector_ptr_size(&state->g_attrs));
325
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, r);
326
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
329
IGRAPH_FINALLY(igraph_vector_ptr_destroy, &gattr);
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;
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;
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;
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, "");
359
VECTOR(vattr)[i]=rec;
361
if (!already_has_vertex_id) {
363
idrec.type=IGRAPH_ATTRIBUTE_STRING;
365
igraph_trie_getkeys(&state->node_trie, (const igraph_strvector_t **)tmp);
366
VECTOR(vattr)[i]=&idrec;
368
igraph_vector_ptr_pop_back(&vattr);
369
IGRAPH_WARNING("Could not add vertex ids, "
370
"there is already an 'id' vertex attribute");
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;
378
if (! strcmp(rec->name, idstr)) {
379
already_has_edge_id=1;
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;
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, "");
399
VECTOR(eattr)[i]=rec;
401
if (igraph_strvector_size(&state->edgeids) != 0) {
402
if (!already_has_edge_id) {
403
long int origsize=igraph_strvector_size(&state->edgeids);
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, "");
411
eidrec.value=&state->edgeids;
412
VECTOR(eattr)[(long int)igraph_vector_ptr_size(&eattr)-1]=&eidrec;
414
igraph_vector_ptr_pop_back(&eattr);
415
IGRAPH_WARNING("Could not add edge ids, "
416
"there is already an 'id' edge attribute");
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;
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, "");
439
VECTOR(gattr)[i]=rec;
442
igraph_empty_attrs(state->g, 0, state->edges_directed, &gattr);
443
igraph_add_vertices(state->g, igraph_trie_size(&state->node_trie),
445
igraph_add_edges(state->g, &state->edgelist, &eattr);
447
igraph_vector_ptr_destroy(&vattr);
448
igraph_vector_ptr_destroy(&eattr);
449
igraph_vector_ptr_destroy(&gattr);
450
IGRAPH_FINALLY_CLEAN(3);
453
igraph_i_graphml_destroy_state(state);
456
#define toXmlChar(a) (BAD_CAST(a))
457
#define fromXmlChar(a) ((char *)(a)) /* not the most elegant way... */
459
void igraph_i_graphml_add_attribute_key(const xmlChar** attrs,
460
struct igraph_i_graphml_parser_state *state) {
462
igraph_trie_t *trie=0;
463
igraph_vector_ptr_t *ptrvector=0;
466
igraph_i_graphml_attribute_record_t *rec=
467
igraph_Calloc(1, igraph_i_graphml_attribute_record_t);
469
if (!state->successful) return;
472
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__,
474
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
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));
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;
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");
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;
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");
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");
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");
544
ret=igraph_vector_ptr_push_back(ptrvector, rec);
546
igraph_error("Cannot read GraphML file", __FILE__, __LINE__, ret);
547
igraph_i_graphml_sax_handler_error(state, "Cannot read GraphML file");
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);
558
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__,
560
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
563
rec->record.value=vec;
564
igraph_vector_init(vec, 0);
566
case IGRAPH_ATTRIBUTE_STRING:
567
strvec=igraph_Calloc(1, igraph_strvector_t);
569
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__,
571
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
574
rec->record.value=strvec;
575
igraph_strvector_init(strvec, 0);
580
IGRAPH_FINALLY_CLEAN(1); /* rec */
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) {
587
for (it=(xmlChar**)attrs; *it; it+=2) {
588
if (xmlStrEqual(*it, toXmlChar("key"))) {
589
if (state->data_key) {
590
free(state->data_key);
592
state->data_key=xmlStrdup(*(it+1));
593
if (state->data_char) {
594
free(state->data_char);
597
state->data_type=type;
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;
608
if (!state->successful) return;
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);
614
state->data_char=igraph_Calloc(len+1, char);
616
if (state->data_char==0) {
617
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__,
619
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
622
memcpy(state->data_char+data_char_new_start, data, len*sizeof(xmlChar));
623
state->data_char[data_char_new_start+len]='\0';
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;
637
case IGRAPH_ATTRIBUTE_GRAPH:
638
trie=&state->g_names;
639
ptrvector=&state->g_attrs;
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 */
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 */
657
igraph_trie_check(trie, key, &recid);
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);
665
graphmlrec=VECTOR(*ptrvector)[recid];
666
rec=&graphmlrec->record;
669
igraph_vector_t *vec;
670
igraph_strvector_t *strvec;
673
case IGRAPH_ATTRIBUTE_NUMERIC:
674
vec=(igraph_vector_t *)rec->value;
675
s=igraph_vector_size(vec);
677
ret=igraph_vector_resize(vec, id+1);
679
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
680
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
683
for (i=s; i<id; i++) {
684
VECTOR(*vec)[i]=IGRAPH_NAN;
687
if (state->data_char)
688
sscanf(state->data_char, "%lf", &num);
691
VECTOR(*vec)[id]=num;
693
case IGRAPH_ATTRIBUTE_STRING:
694
strvec=(igraph_strvector_t *)rec->value;
695
s=igraph_strvector_size(strvec);
697
ret=igraph_strvector_resize(strvec, id+1);
699
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
700
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
704
igraph_strvector_set(strvec, i, "");
707
if (state->data_char)
708
ret=igraph_strvector_set(strvec, id, (char*)state->data_char);
710
ret=igraph_strvector_set(strvec, id, "");
712
igraph_error("Cannot parse GraphML file", __FILE__, __LINE__, ret);
713
igraph_i_graphml_sax_handler_error(state, "Cannot parse GraphML file");
721
if (state->data_char) igraph_Free(state->data_char);
724
void igraph_i_graphml_sax_handler_start_element(void *state0,
726
const xmlChar** attrs) {
727
struct igraph_i_graphml_parser_state *state=
728
(struct igraph_i_graphml_parser_state*)state0;
731
unsigned short int directed;
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;
740
igraph_i_graphml_handle_unknown_start_tag(state);
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;
759
} else if (xmlStrEqual(name, toXmlChar("key"))) {
760
igraph_i_graphml_add_attribute_key(attrs, state);
761
state->st=INSIDE_KEY;
763
igraph_i_graphml_handle_unknown_start_tag(state);
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);
773
/* If we are in the INSIDE_DEFAULT state, every further tag will be unknown */
774
igraph_i_graphml_handle_unknown_start_tag(state);
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);
785
if (xmlStrEqual(*it, toXmlChar("target"))) {
786
igraph_trie_get(&state->node_trie, fromXmlChar(*(it+1)), &id2);
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, "");
795
igraph_strvector_set(&state->edgeids, edges-1, fromXmlChar(*(it+1)));
798
if (id1>=0 && id2>=0) {
799
igraph_vector_push_back(&state->edgelist, id1);
800
igraph_vector_push_back(&state->edgelist, id2);
802
igraph_i_graphml_sax_handler_error(state, "Edge with missing source or target encountered");
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"))) {
810
igraph_trie_get(&state->node_trie, fromXmlChar(*it), &id1);
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;
820
igraph_i_graphml_handle_unknown_start_tag(state);
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;
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;
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;
857
state->st=INSIDE_GRAPHML;
861
state->st=INSIDE_GRAPHML;
865
state->st=INSIDE_KEY;
869
state->st=INSIDE_GRAPH;
873
state->st=INSIDE_GRAPH;
877
igraph_i_graphml_attribute_data_finish(state);
878
state->st=state->prev_state;
882
state->unknown_depth--;
883
if (!state->unknown_depth) state->st=state->prev_state;
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;
901
igraph_i_graphml_attribute_data_add(state, ch, len);
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,
919
igraph_i_graphml_sax_handler_chars,
921
igraph_i_graphml_sax_handler_error,
922
igraph_i_graphml_sax_handler_error,
923
igraph_i_graphml_sax_handler_error,
928
int igraph_i_xml_escape(char* src, char** dest) {
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;
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++) {
943
strcpy(d, "&"); d+=4; break;
945
strcpy(d, "<"); d+=3; break;
947
strcpy(d, ">"); d+=3; break;
949
strcpy(d, """); d+=5; break;
951
strcpy(d, "'"); d+=5; break;
962
* \function igraph_read_graph_graphml
963
* \brief Reads a graph from a GraphML file.
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
978
* \return Error code:
979
* \c IGRAPH_PARSEERROR: if there is a
980
* problem reading the file, or the file is syntactically
982
* \c IGRAPH_UNIMPLEMENTED: the GraphML functionality was disabled
985
int igraph_read_graph_graphml(igraph_t *graph, FILE *instream,
989
xmlParserCtxtPtr ctxt;
990
struct igraph_i_graphml_parser_state state;
995
IGRAPH_ERROR("Graph index must be non-negative", IGRAPH_EINVAL);
997
/* Create a progressive parser context */
999
state.index=index<0?0:index;
1000
res=fread(buffer, 1, 4096, instream);
1001
ctxt=xmlCreatePushParserCtxt(&igraph_i_graphml_sax_handler,
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); */
1011
IGRAPH_ERROR("Can't create progressive parser context", IGRAPH_PARSEERROR);
1013
/* Parse the file */
1014
while ((res=fread(buffer, 1, 4096, instream))>0) {
1015
xmlParseChunk(ctxt, buffer, res, 0);
1016
if (!state.successful) break;
1018
xmlParseChunk(ctxt, buffer, res, 1);
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);
1026
IGRAPH_ERROR("Malformed GraphML file", IGRAPH_PARSEERROR);
1029
IGRAPH_ERROR("Graph index was too large", IGRAPH_EINVAL);
1033
IGRAPH_ERROR("GraphML support is disabled", IGRAPH_UNIMPLEMENTED);
1039
* \function igraph_write_graph_graphml
1040
* \brief Writes the graph to a file in GraphML format
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.
1047
* \param graph The graph to write.
1048
* \param outstream The stream object to write to, it should be
1050
* \return Error code:
1051
* \c IGRAPH_EFILE if there is an error
1054
* Time complexity: O(|V|+|E|) otherwise. All
1055
* file operations are expected to have time complexity
1058
int igraph_write_graph_graphml(const igraph_t *graph, FILE *outstream) {
1060
igraph_integer_t l, vc;
1062
igraph_strvector_t gnames, vnames, enames;
1063
igraph_vector_t gtypes, vtypes, etypes;
1065
igraph_vector_t numv;
1066
igraph_strvector_t strv;
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);
1081
/* dump the <key> elements if any */
1083
IGRAPH_VECTOR_INIT_FINALLY(&numv, 1);
1084
IGRAPH_STRVECTOR_INIT_FINALLY(&strv, 1);
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(>ypes, 0);
1090
IGRAPH_VECTOR_INIT_FINALLY(&vtypes, 0);
1091
IGRAPH_VECTOR_INIT_FINALLY(&etypes, 0);
1092
igraph_i_attribute_get_info(graph,
1097
/* graph attributes */
1098
for (i=0; i<igraph_vector_size(>ypes); 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);
1109
igraph_Free(name_escaped);
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);
1124
igraph_Free(name_escaped);
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);
1139
igraph_Free(name_escaped);
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);
1145
/* Write the graph atributes before anything else */
1147
for (i=0; i<igraph_vector_size(>ypes); 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);
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);
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);
1182
if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
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);
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);
1214
ret=fprintf(outstream, " </node>\n");
1215
if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
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);
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);
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);
1261
ret=fprintf(outstream, " </edge>\n");
1262
if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
1263
IGRAPH_EIT_NEXT(it);
1265
igraph_eit_destroy(&it);
1266
IGRAPH_FINALLY_CLEAN(1);
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);
1273
igraph_strvector_destroy(&gnames);
1274
igraph_strvector_destroy(&vnames);
1275
igraph_strvector_destroy(&enames);
1276
igraph_vector_destroy(>ypes);
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);