1 /* -*- Mode: c; c-basic-offset: 2 -*-
2  *
3  * raptor_serialize_rdfxml.c - RDF/XML serializer
4  *
5  * Copyright (C) 2004-2008, David Beckett http://www.dajobe.org/
6  * Copyright (C) 2004-2005, University of Bristol, UK http://www.bristol.ac.uk/
7  *
8  * This package is Free Software and part of Redland http://librdf.org/
9  *
10  * It is licensed under the following three licenses as alternatives:
11  *   1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
12  *   2. GNU General Public License (GPL) V2 or any newer version
13  *   3. Apache License, V2.0 or any newer version
14  *
15  * You may not use this file except in compliance with at least one of
16  * the above three licenses.
17  *
18  * See LICENSE.html or LICENSE.txt at the top of this package for the
19  * complete terms and further detail along with the license texts for
20  * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <raptor_config.h>
26 #endif
27 
28 #include <stdio.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <stdarg.h>
32 #ifdef HAVE_ERRNO_H
33 #include <errno.h>
34 #endif
35 #ifdef HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
38 
39 /* Raptor includes */
40 #include "raptor2.h"
41 #include "raptor_internal.h"
42 
43 
44 /*
45  * Raptor RDF/XML serializer object
46  */
47 typedef struct {
48   /* Namespace stack */
49   raptor_namespace_stack *nstack;
50 
51   /* the xml: namespace - this is destroyed when nstack above is deleted */
52   raptor_namespace *xml_nspace;
53 
54   /* the rdf: namespace - this is destroyed when nstack above is deleted */
55   raptor_namespace *rdf_nspace;
56 
57   /* the rdf:RDF element */
58   raptor_xml_element* rdf_RDF_element;
59 
60   /* where the xml is being written */
61   raptor_xml_writer *xml_writer;
62 
63   /* User declared namespaces */
64   raptor_sequence *namespaces;
65 
66   /* non zero if rdf:RDF has been written (and thus no new namespaces
67    * can be declared).
68    */
69   int written_header;
70 } raptor_rdfxml_serializer_context;
71 
72 
73 /* local prototypes */
74 
75 static void
76 raptor_rdfxml_serialize_terminate(raptor_serializer* serializer);
77 
78 /* create a new serializer */
79 static int
raptor_rdfxml_serialize_init(raptor_serializer * serializer,const char * name)80 raptor_rdfxml_serialize_init(raptor_serializer* serializer, const char *name)
81 {
82   raptor_rdfxml_serializer_context* context = (raptor_rdfxml_serializer_context*)serializer->context;
83 
84   context->nstack = raptor_new_namespaces(serializer->world, 1);
85   if(!context->nstack)
86     return 1;
87   context->xml_nspace = raptor_new_namespace(context->nstack,
88                                              (const unsigned char*)"xml",
89                                              (const unsigned char*)raptor_xml_namespace_uri,
90                                              0);
91 
92   context->rdf_nspace = raptor_new_namespace(context->nstack,
93                                              (const unsigned char*)"rdf",
94                                              (const unsigned char*)raptor_rdf_namespace_uri,
95                                              0);
96 
97   context->namespaces = raptor_new_sequence(NULL, NULL);
98 
99   if(!context->xml_nspace || !context->rdf_nspace || !context->namespaces) {
100     raptor_rdfxml_serialize_terminate(serializer);
101     return 1;
102   }
103 
104   /* Note: item 0 in the list is rdf:RDF's namespace */
105   if(raptor_sequence_push(context->namespaces, context->rdf_nspace)) {
106     raptor_rdfxml_serialize_terminate(serializer);
107     return 1;
108   }
109 
110   return 0;
111 }
112 
113 
114 /* destroy a serializer */
115 static void
raptor_rdfxml_serialize_terminate(raptor_serializer * serializer)116 raptor_rdfxml_serialize_terminate(raptor_serializer* serializer)
117 {
118   raptor_rdfxml_serializer_context* context = (raptor_rdfxml_serializer_context*)serializer->context;
119 
120   if(context->xml_writer) {
121     raptor_free_xml_writer(context->xml_writer);
122     context->xml_writer = NULL;
123   }
124 
125   if(context->rdf_RDF_element) {
126     raptor_free_xml_element(context->rdf_RDF_element);
127     context->rdf_RDF_element = NULL;
128   }
129 
130   if(context->rdf_nspace) {
131     raptor_free_namespace(context->rdf_nspace);
132     context->rdf_nspace = NULL;
133   }
134 
135   if(context->xml_nspace) {
136     raptor_free_namespace(context->xml_nspace);
137     context->xml_nspace = NULL;
138   }
139 
140   if(context->namespaces) {
141     int i;
142 
143     /* Note: item 0 in the list is rdf:RDF's namespace and freed above */
144     for(i = 1; i< raptor_sequence_size(context->namespaces); i++) {
145       raptor_namespace* ns = (raptor_namespace*)raptor_sequence_get_at(context->namespaces, i);
146       if(ns)
147         raptor_free_namespace(ns);
148     }
149     raptor_free_sequence(context->namespaces);
150     context->namespaces = NULL;
151   }
152 
153   if(context->nstack) {
154     raptor_free_namespaces(context->nstack);
155     context->nstack = NULL;
156   }
157 }
158 
159 
160 #define RDFXML_NAMESPACE_DEPTH 0
161 
162 /* add a namespace */
163 static int
raptor_rdfxml_serialize_declare_namespace_from_namespace(raptor_serializer * serializer,raptor_namespace * nspace)164 raptor_rdfxml_serialize_declare_namespace_from_namespace(raptor_serializer* serializer,
165                                                          raptor_namespace *nspace)
166 {
167   raptor_rdfxml_serializer_context* context = (raptor_rdfxml_serializer_context*)serializer->context;
168   int i;
169 
170   if(context->written_header)
171     return 1;
172 
173   for(i = 0; i< raptor_sequence_size(context->namespaces); i++) {
174     raptor_namespace* ns;
175     ns = (raptor_namespace*)raptor_sequence_get_at(context->namespaces, i);
176 
177     /* If prefix is already declared, ignore it */
178     if(!ns->prefix && !nspace->prefix)
179       return 1;
180 
181     if(ns->prefix && nspace->prefix &&
182        !strcmp((const char*)ns->prefix, (const char*)nspace->prefix))
183       return 1;
184 
185     if(ns->uri && nspace->uri &&
186        raptor_uri_equals(ns->uri, nspace->uri))
187       return 1;
188   }
189 
190   nspace = raptor_new_namespace_from_uri(context->nstack,
191                                          nspace->prefix, nspace->uri,
192                                          RDFXML_NAMESPACE_DEPTH);
193   if(!nspace)
194     return 1;
195 
196   raptor_sequence_push(context->namespaces, nspace);
197   return 0;
198 }
199 
200 
201 /* add a namespace */
202 static int
raptor_rdfxml_serialize_declare_namespace(raptor_serializer * serializer,raptor_uri * uri,const unsigned char * prefix)203 raptor_rdfxml_serialize_declare_namespace(raptor_serializer* serializer,
204                                           raptor_uri *uri,
205                                           const unsigned char *prefix)
206 {
207   raptor_rdfxml_serializer_context* context = (raptor_rdfxml_serializer_context*)serializer->context;
208   raptor_namespace *ns;
209   int rc;
210 
211   ns = raptor_new_namespace_from_uri(context->nstack, prefix, uri,
212                                      RDFXML_NAMESPACE_DEPTH);
213 
214   rc = raptor_rdfxml_serialize_declare_namespace_from_namespace(serializer,
215                                                                  ns);
216   raptor_free_namespace(ns);
217 
218   return rc;
219 }
220 
221 
222 /* start a serialize */
223 static int
raptor_rdfxml_serialize_start(raptor_serializer * serializer)224 raptor_rdfxml_serialize_start(raptor_serializer* serializer)
225 {
226   raptor_rdfxml_serializer_context* context = (raptor_rdfxml_serializer_context*)serializer->context;
227   raptor_xml_writer* xml_writer;
228   raptor_option option;
229 
230   if(context->xml_writer) {
231     raptor_free_xml_writer(context->xml_writer);
232     context->xml_writer = NULL;
233   }
234 
235   xml_writer = raptor_new_xml_writer(serializer->world, context->nstack,
236                                      serializer->iostream);
237   if(!xml_writer)
238     return 1;
239 
240   option = RAPTOR_OPTION_WRITER_XML_VERSION;
241   raptor_xml_writer_set_option(xml_writer, option, NULL,
242                                RAPTOR_OPTIONS_GET_NUMERIC(serializer, option));
243   option = RAPTOR_OPTION_WRITER_XML_DECLARATION;
244   raptor_xml_writer_set_option(xml_writer, option, NULL,
245                                RAPTOR_OPTIONS_GET_NUMERIC(serializer, option));
246 
247   context->xml_writer = xml_writer;
248   context->written_header = 0;
249 
250   return 0;
251 }
252 
253 
254 static int
raptor_rdfxml_ensure_writen_header(raptor_serializer * serializer,raptor_rdfxml_serializer_context * context)255 raptor_rdfxml_ensure_writen_header(raptor_serializer* serializer,
256                                    raptor_rdfxml_serializer_context* context)
257 {
258   raptor_xml_writer* xml_writer;
259   raptor_uri *base_uri;
260   int i;
261   raptor_qname **attrs = NULL;
262   int attrs_count = 0;
263   int rc = 1;
264 
265   if(context->written_header)
266     return 0;
267 
268   context->written_header = 1;
269 
270   xml_writer = context->xml_writer;
271 
272   base_uri = serializer->base_uri;
273   if(base_uri)
274     base_uri = raptor_uri_copy(base_uri);
275 
276   context->rdf_RDF_element = raptor_new_xml_element_from_namespace_local_name(context->rdf_nspace, (const unsigned char*)"RDF", NULL, base_uri);
277   if(!context->rdf_RDF_element)
278     goto tidy;
279 
280   /* NOTE: Starts it item 1 as item 0 is the element's namespace (rdf)
281    * and does not need to be declared
282    */
283   for(i = 1; i< raptor_sequence_size(context->namespaces); i++) {
284     raptor_namespace* ns = (raptor_namespace*)raptor_sequence_get_at(context->namespaces, i);
285     if(raptor_xml_element_declare_namespace(context->rdf_RDF_element, ns))
286       goto tidy;
287   }
288 
289   if(base_uri &&
290      RAPTOR_OPTIONS_GET_NUMERIC(serializer, RAPTOR_OPTION_WRITE_BASE_URI)) {
291     const unsigned char* base_uri_string;
292 
293     attrs = RAPTOR_CALLOC(raptor_qname **, 1, sizeof(raptor_qname*));
294     if(!attrs)
295       goto tidy;
296 
297     base_uri_string = raptor_uri_as_string(base_uri);
298     attrs[attrs_count] = raptor_new_qname_from_namespace_local_name(serializer->world, context->xml_nspace, (const unsigned char*)"base",  base_uri_string);
299     if(!attrs[attrs_count]) {
300       RAPTOR_FREE(qnamearray, attrs);
301       goto tidy;
302     }
303     attrs_count++;
304   }
305 
306   if(attrs_count)
307     raptor_xml_element_set_attributes(context->rdf_RDF_element, attrs,
308                                       attrs_count);
309   else
310     raptor_xml_element_set_attributes(context->rdf_RDF_element, NULL, 0);
311 
312 
313   raptor_xml_writer_start_element(xml_writer, context->rdf_RDF_element);
314   raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
315 
316   rc = 0;
317 
318   tidy:
319   if(base_uri)
320     raptor_free_uri(base_uri);
321 
322   return rc;
323 }
324 
325 
326 /* serialize a statement */
327 static int
raptor_rdfxml_serialize_statement(raptor_serializer * serializer,raptor_statement * statement)328 raptor_rdfxml_serialize_statement(raptor_serializer* serializer,
329                                   raptor_statement *statement)
330 {
331   raptor_rdfxml_serializer_context* context = (raptor_rdfxml_serializer_context*)serializer->context;
332   raptor_xml_writer* xml_writer = context->xml_writer;
333   unsigned char* uri_string = NULL; /* predicate URI */
334   unsigned char* name = NULL;  /* where to split predicate name */
335   unsigned char* subject_uri_string = NULL;
336   unsigned char* object_uri_string = NULL;
337   const unsigned char* nsprefix = (const unsigned char*)"ns0";
338   int rc = 1;
339   size_t len;
340   raptor_xml_element* rdf_Description_element = NULL;
341   raptor_uri* predicate_ns_uri = NULL;
342   raptor_namespace* predicate_ns = NULL;
343   int free_predicate_ns = 0;
344   raptor_xml_element* predicate_element = NULL;
345   raptor_qname **attrs = NULL;
346   int attrs_count = 0;
347   raptor_uri* base_uri = NULL;
348   raptor_term_type object_type;
349   int allocated = 1;
350   int object_is_parseTypeLiteral = 0;
351 
352   if(raptor_rdfxml_ensure_writen_header(serializer, context))
353     return 1;
354 
355   if(statement->predicate->type == RAPTOR_TERM_TYPE_URI) {
356     unsigned char *p;
357     size_t uri_len;
358     size_t name_len = 1;
359     unsigned char c;
360 
361     /* Do not use raptor_uri_as_counted_string() - we want a modifiable copy */
362     uri_string = raptor_uri_to_counted_string(statement->predicate->value.uri,
363                                               &uri_len);
364     if(!uri_string)
365       goto oom;
366 
367     p= uri_string;
368     name_len = uri_len;
369     /* FIXME: this loop could be made smarter */
370     while(name_len >0) {
371       if(raptor_xml_name_check(p, name_len, 10)) {
372         name = p;
373         break;
374       }
375       p++; name_len--;
376     }
377 
378     if(!name || (name == uri_string)) {
379       raptor_log_error_formatted(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
380                                  "Cannot split predicate URI %s into an XML qname - skipping statement", uri_string);
381       rc = 0; /* skip but do not return an error */
382       goto tidy;
383     }
384 
385     c = *name; *name = '\0';
386     predicate_ns_uri = raptor_new_uri(serializer->world, uri_string);
387     *name = c;
388     if(!predicate_ns_uri)
389       goto oom;
390 
391     predicate_ns = raptor_namespaces_find_namespace_by_uri(context->nstack,
392                                                            predicate_ns_uri);
393     if(!predicate_ns) {
394       predicate_ns = raptor_new_namespace_from_uri(context->nstack,
395                                                    nsprefix,
396                                                    predicate_ns_uri, 0);
397       if(!predicate_ns) {
398         raptor_free_uri(predicate_ns_uri);
399         goto oom;
400       }
401       free_predicate_ns = 1;
402     }
403     raptor_free_uri(predicate_ns_uri);
404   } else {
405     raptor_log_error_formatted(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
406                                "Cannot serialize a triple with subject node type %d\n",
407                                statement->predicate->type);
408     goto tidy;
409   }
410 
411   /* base uri */
412   if(serializer->base_uri)
413     base_uri = raptor_uri_copy(serializer->base_uri);
414 
415 
416   rdf_Description_element = raptor_new_xml_element_from_namespace_local_name(context->rdf_nspace,
417                                                                              (unsigned const char*)"Description",
418                                                                              NULL, base_uri);
419   if(!rdf_Description_element)
420     goto oom;
421 
422   attrs = RAPTOR_CALLOC(raptor_qname**, 3, sizeof(raptor_qname*));
423   if(!attrs)
424     goto oom;
425   attrs_count = 0;
426 
427   /* subject */
428   switch(statement->subject->type) {
429     case RAPTOR_TERM_TYPE_BLANK:
430       attrs[attrs_count] = raptor_new_qname_from_namespace_local_name(serializer->world, context->rdf_nspace, (const unsigned char*)"nodeID",
431                                                                       statement->subject->value.blank.string);
432       if(!attrs[attrs_count])
433         goto oom;
434       attrs_count++;
435       break;
436 
437     case RAPTOR_TERM_TYPE_URI:
438       allocated = 1;
439       if(RAPTOR_OPTIONS_GET_NUMERIC(serializer, RAPTOR_OPTION_RELATIVE_URIS)) {
440         subject_uri_string = raptor_uri_to_relative_uri_string(serializer->base_uri,
441                                                                statement->subject->value.uri);
442         if(!subject_uri_string)
443           goto oom;
444       } else {
445         subject_uri_string = raptor_uri_as_string(statement->subject->value.uri);
446         allocated = 0;
447       }
448 
449       attrs[attrs_count] = raptor_new_qname_from_namespace_local_name(serializer->world, context->rdf_nspace, (const unsigned char*)"about",  subject_uri_string);
450       if(!attrs[attrs_count]) {
451         if(allocated)
452           RAPTOR_FREE(char*, subject_uri_string);
453         goto oom;
454       }
455       attrs_count++;
456 
457       if(allocated)
458         RAPTOR_FREE(char*, subject_uri_string);
459 
460       break;
461 
462     case RAPTOR_TERM_TYPE_LITERAL:
463       raptor_log_error(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL, "Cannot serialize a triple with a literal subject\n");
464       break;
465 
466     case RAPTOR_TERM_TYPE_UNKNOWN:
467     default:
468       raptor_log_error_formatted(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
469                                  "Cannot serialize a triple with subject node type %d",
470                                  statement->subject->type);
471   }
472 
473   if(attrs_count) {
474     raptor_xml_element_set_attributes(rdf_Description_element, attrs, attrs_count);
475     attrs = NULL; /* attrs ownership transferred to element */
476   }
477 
478   raptor_xml_writer_cdata_counted(xml_writer, (const unsigned char*)"  ", 2);
479   raptor_xml_writer_start_element(xml_writer, rdf_Description_element);
480   raptor_xml_writer_cdata_counted(xml_writer, (const unsigned char*)"\n", 1);
481 
482 
483   /* predicate */
484   predicate_element = raptor_new_xml_element_from_namespace_local_name(predicate_ns, name, NULL, base_uri);
485   if(!predicate_element)
486     goto oom;
487 
488   /* object */
489   attrs = RAPTOR_CALLOC(raptor_qname**, 3, sizeof(raptor_qname*));
490   if(!attrs)
491     goto oom;
492   attrs_count = 0;
493 
494   object_type = statement->object->type;
495   switch(object_type) {
496     case RAPTOR_TERM_TYPE_LITERAL:
497       object_is_parseTypeLiteral = 0;
498       if(statement->object->value.literal.datatype &&
499          raptor_uri_equals(statement->object->value.literal.datatype,
500                            RAPTOR_RDF_XMLLiteral_URI(serializer->world)))
501         object_is_parseTypeLiteral = 1;
502 
503       if(statement->object->value.literal.language) {
504         attrs[attrs_count] = raptor_new_qname(context->nstack,
505                                               (unsigned char*)"xml:lang",
506                                               statement->object->value.literal.language);
507         if(!attrs[attrs_count])
508           goto oom;
509         attrs_count++;
510       }
511       len = statement->object->value.literal.string_len;
512 
513       if(object_is_parseTypeLiteral) {
514         attrs[attrs_count] = raptor_new_qname_from_namespace_local_name(serializer->world, context->rdf_nspace, (const unsigned char*)"parseType", (const unsigned char*)"Literal");
515         if(!attrs[attrs_count])
516           goto oom;
517         attrs_count++;
518 
519         raptor_xml_element_set_attributes(predicate_element, attrs, attrs_count);
520         attrs = NULL; /* attrs ownership transferred to element */
521 
522         raptor_xml_writer_cdata_counted(xml_writer, (const unsigned char*)"    ", 4);
523         raptor_xml_writer_start_element(xml_writer, predicate_element);
524 
525         /* Print without escaping XML */
526         if(len)
527           raptor_xml_writer_raw_counted(xml_writer,
528                                         (const unsigned char*)statement->object->value.literal.string,
529                                         RAPTOR_BAD_CAST(unsigned int, len));
530       } else {
531         if(statement->object->value.literal.datatype) {
532           attrs[attrs_count] = raptor_new_qname_from_namespace_local_name(serializer->world, context->rdf_nspace, (const unsigned char*)"datatype", raptor_uri_as_string(statement->object->value.literal.datatype));
533           if(!attrs[attrs_count])
534             goto oom;
535           attrs_count++;
536         }
537         raptor_xml_element_set_attributes(predicate_element, attrs, attrs_count);
538         attrs = NULL; /* attrs ownership transferred to element */
539 
540         raptor_xml_writer_cdata_counted(xml_writer,
541                                         (const unsigned char*)"    ", 4);
542         raptor_xml_writer_start_element(xml_writer, predicate_element);
543 
544         if(len)
545           raptor_xml_writer_cdata_counted(xml_writer,
546                                           statement->object->value.literal.string,
547                                           RAPTOR_BAD_CAST(unsigned int, len));
548       }
549 
550       raptor_xml_writer_end_element(xml_writer, predicate_element);
551       raptor_free_xml_element(predicate_element);
552       predicate_element = NULL;
553       raptor_xml_writer_cdata_counted(xml_writer, (const unsigned char*)"\n", 1);
554 
555       break;
556 
557     case RAPTOR_TERM_TYPE_BLANK:
558       attrs[attrs_count] = raptor_new_qname_from_namespace_local_name(serializer->world, context->rdf_nspace, (const unsigned char*)"nodeID", statement->object->value.blank.string);
559       if(!attrs[attrs_count])
560         goto oom;
561       attrs_count++;
562 
563       raptor_xml_element_set_attributes(predicate_element, attrs, attrs_count);
564       attrs = NULL; /* attrs ownership transferred to element */
565 
566       raptor_xml_writer_cdata_counted(xml_writer,
567                                       (const unsigned char*)"    ", 4);
568       raptor_xml_writer_empty_element(xml_writer, predicate_element);
569       raptor_xml_writer_cdata_counted(xml_writer, (const unsigned char*)"\n", 1);
570       break;
571 
572     case RAPTOR_TERM_TYPE_URI:
573       /* must be URI */
574       if(RAPTOR_OPTIONS_GET_NUMERIC(serializer, RAPTOR_OPTION_RELATIVE_URIS)) {
575         object_uri_string = raptor_uri_to_relative_uri_string(serializer->base_uri,
576                                                               statement->object->value.uri);
577       } else {
578         object_uri_string = raptor_uri_to_string(statement->object->value.uri);
579       }
580       if(!object_uri_string)
581         goto oom;
582 
583       attrs[attrs_count] = raptor_new_qname_from_namespace_local_name(serializer->world, context->rdf_nspace, (const unsigned char*)"resource", object_uri_string);
584       RAPTOR_FREE(char*, object_uri_string);
585 
586       if(!attrs[attrs_count])
587         goto oom;
588 
589       attrs_count++;
590       raptor_xml_element_set_attributes(predicate_element, attrs, attrs_count);
591       attrs = NULL; /* attrs ownership transferred to element */
592 
593       raptor_xml_writer_cdata_counted(xml_writer,
594                                       (const unsigned char*)"    ", 4);
595       raptor_xml_writer_empty_element(xml_writer, predicate_element);
596       raptor_xml_writer_cdata_counted(xml_writer, (const unsigned char*)"\n", 1);
597       break;
598 
599     case RAPTOR_TERM_TYPE_UNKNOWN:
600     default:
601       raptor_log_error_formatted(serializer->world, RAPTOR_LOG_LEVEL_ERROR, NULL,
602                                  "Cannot serialize a triple with object node type %d",
603                                  object_type);
604   }
605 
606   raptor_xml_writer_cdata_counted(xml_writer,
607                                   (const unsigned char*)"  ", 2);
608 
609   rc = 0; /* success */
610   goto tidy;
611 
612   oom:
613   raptor_log_error(serializer->world, RAPTOR_LOG_LEVEL_FATAL, NULL,
614                    "Out of memory");
615 
616   tidy:
617 
618   if(attrs)
619     RAPTOR_FREE(qnamearray, attrs);
620 
621   if(predicate_element)
622     raptor_free_xml_element(predicate_element);
623 
624   if(rdf_Description_element) {
625     raptor_xml_writer_end_element(xml_writer, rdf_Description_element);
626     raptor_xml_writer_cdata_counted(xml_writer, (const unsigned char*)"\n", 1);
627     raptor_free_xml_element(rdf_Description_element);
628   }
629 
630   if(base_uri)
631     raptor_free_uri(base_uri);
632 
633   if(free_predicate_ns)
634     raptor_free_namespace(predicate_ns);
635 
636   if(uri_string)
637     RAPTOR_FREE(char*, uri_string);
638 
639   return rc;
640 }
641 
642 
643 /* end a serialize */
644 static int
raptor_rdfxml_serialize_end(raptor_serializer * serializer)645 raptor_rdfxml_serialize_end(raptor_serializer* serializer)
646 {
647   raptor_rdfxml_serializer_context* context = (raptor_rdfxml_serializer_context*)serializer->context;
648   raptor_xml_writer* xml_writer = context->xml_writer;
649 
650   if(xml_writer) {
651     /* Make sure an empty RDF/XML document is written when 0 triples
652      * were seen
653      */
654 
655     /* ignore ret value */
656     raptor_rdfxml_ensure_writen_header(serializer, context);
657 
658     if(context->rdf_RDF_element) {
659       raptor_xml_writer_end_element(xml_writer, context->rdf_RDF_element);
660       raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"\n", 1);
661     }
662 
663     raptor_xml_writer_flush(xml_writer);
664   }
665 
666   if(context->rdf_RDF_element) {
667     raptor_free_xml_element(context->rdf_RDF_element);
668     context->rdf_RDF_element = NULL;
669   }
670 
671   return 0;
672 }
673 
674 
675 /* finish the serializer factory */
676 static void
raptor_rdfxml_serialize_finish_factory(raptor_serializer_factory * factory)677 raptor_rdfxml_serialize_finish_factory(raptor_serializer_factory* factory)
678 {
679 
680 }
681 
682 static const char* const rdfxml_names[2] = { "rdfxml", NULL};
683 
684 static const char* const rdfxml_uri_strings[3] = {
685   "http://www.w3.org/ns/formats/RDF_XML",
686   "http://www.w3.org/TR/rdf-syntax-grammar",
687   NULL
688 };
689 
690 #define RDFXML_TYPES_COUNT 2
691 static const raptor_type_q rdfxml_types[RDFXML_TYPES_COUNT + 1] = {
692   { "application/rdf+xml", 19, 10},
693   { "text/rdf", 8, 6},
694   { NULL, 0, 0}
695 };
696 
697 static int
raptor_rdfxml_serializer_register_factory(raptor_serializer_factory * factory)698 raptor_rdfxml_serializer_register_factory(raptor_serializer_factory *factory)
699 {
700   factory->desc.names = rdfxml_names;
701   factory->desc.mime_types = rdfxml_types;
702 
703   factory->desc.label = "RDF/XML";
704   factory->desc.uri_strings = rdfxml_uri_strings,
705 
706   factory->context_length     = sizeof(raptor_rdfxml_serializer_context);
707 
708   factory->init                = raptor_rdfxml_serialize_init;
709   factory->terminate           = raptor_rdfxml_serialize_terminate;
710   factory->declare_namespace   = raptor_rdfxml_serialize_declare_namespace;
711   factory->declare_namespace_from_namespace   = raptor_rdfxml_serialize_declare_namespace_from_namespace;
712   factory->serialize_start     = raptor_rdfxml_serialize_start;
713   factory->serialize_statement = raptor_rdfxml_serialize_statement;
714   factory->serialize_end       = raptor_rdfxml_serialize_end;
715   factory->finish_factory      = raptor_rdfxml_serialize_finish_factory;
716 
717   return 0;
718 }
719 
720 
721 
722 int
raptor_init_serializer_rdfxml(raptor_world * world)723 raptor_init_serializer_rdfxml(raptor_world* world)
724 {
725   return !raptor_serializer_register_factory(world,
726                                              &raptor_rdfxml_serializer_register_factory);
727 }
728 
729 
730