1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * raptor_xml_writer.c - Raptor XML Writer for SAX2 events API
4 *
5 * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
6 * Copyright (C) 2003-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
25
26 #ifdef HAVE_CONFIG_H
27 #include <raptor_config.h>
28 #endif
29
30 #ifdef WIN32
31 #include <win32_raptor_config.h>
32 #endif
33
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <stdarg.h>
39 #ifdef HAVE_ERRNO_H
40 #include <errno.h>
41 #endif
42 #ifdef HAVE_STDLIB_H
43 #include <stdlib.h>
44 #endif
45
46 /* Raptor includes */
47 #include "raptor.h"
48 #include "raptor_internal.h"
49
50 #ifndef STANDALONE
51
52
53 typedef enum {
54 XML_WRITER_AUTO_INDENT = 1,
55 XML_WRITER_AUTO_EMPTY = 2
56 } raptor_xml_writer_flags;
57
58
59 #define XML_WRITER_AUTO_INDENT(xml_writer) ((xml_writer->flags & XML_WRITER_AUTO_INDENT) != 0)
60 #define XML_WRITER_AUTO_EMPTY(xml_writer) ((xml_writer->flags & XML_WRITER_AUTO_EMPTY) != 0)
61
62 #define XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer) \
63 if ((xml_writer->flags & XML_WRITER_AUTO_EMPTY) && \
64 xml_writer->current_element && \
65 !(xml_writer->current_element->content_cdata_seen || \
66 xml_writer->current_element->content_element_seen)) { \
67 raptor_iostream_write_byte(xml_writer->iostr, '>'); \
68 }
69
70
71 /* Define this for far too much output */
72 #undef RAPTOR_DEBUG_CDATA
73
74
75 struct raptor_xml_writer_s {
76 int canonicalize;
77
78 int depth;
79
80 int my_nstack;
81 raptor_namespace_stack *nstack;
82 int nstack_depth;
83
84 const raptor_uri_handler *uri_handler;
85 void *uri_context;
86
87 raptor_simple_message_handler error_handler;
88 void *error_data;
89
90 raptor_xml_element* current_element;
91
92 /* outputting to this iostream */
93 raptor_iostream *iostr;
94
95 /* XML Writer flags - bits defined in enum raptor_xml_writer_flags */
96 int flags;
97
98 /* indentation per level if formatting */
99 int indent;
100
101 /* XML 1.0 (10) or XML 1.1 (11) */
102 int xml_version;
103
104 /* Write XML 1.0 or 1.1 declaration (default 1) */
105 int xml_declaration;
106
107 /* Has writing the XML declaration writing been checked? */
108 int xml_declaration_checked;
109
110 /* An extra newline is wanted */
111 int pending_newline;
112 };
113
114
115 /* 16 spaces */
116 #define SPACES_BUFFER_SIZE sizeof(spaces_buffer)
117 static const unsigned char spaces_buffer[] = {
118 ' ', ' ', ' ', ' ',
119 ' ', ' ', ' ', ' ',
120 ' ', ' ', ' ', ' ',
121 ' ', ' ', ' ', ' '
122 };
123
124
125
126 /* helper functions */
127
128 /* Handle printing a pending newline OR newline with indenting */
129 static int
raptor_xml_writer_indent(raptor_xml_writer * xml_writer)130 raptor_xml_writer_indent(raptor_xml_writer *xml_writer)
131 {
132 int num_spaces;
133
134 if(!XML_WRITER_AUTO_INDENT(xml_writer)) {
135 if(xml_writer->pending_newline) {
136 raptor_iostream_write_byte(xml_writer->iostr, '\n');
137 xml_writer->pending_newline=0;
138
139 if(xml_writer->current_element)
140 xml_writer->current_element->content_cdata_seen=1;
141 }
142 return 0;
143 }
144
145 num_spaces = xml_writer->depth * xml_writer->indent;
146
147 /* Do not write an extra newline at the start of the document
148 * (after the XML declaration or XMP processing instruction has
149 * been writtten)
150 */
151 if(xml_writer->xml_declaration_checked == 1)
152 xml_writer->xml_declaration_checked++;
153 else {
154 raptor_iostream_write_byte(xml_writer->iostr, '\n');
155 xml_writer->pending_newline=0;
156 }
157
158 while (num_spaces > 0) {
159
160 int count = (num_spaces > (int)SPACES_BUFFER_SIZE) ? (int)SPACES_BUFFER_SIZE : num_spaces;
161
162 raptor_iostream_write_counted_string(xml_writer->iostr, spaces_buffer, count);
163
164 num_spaces -= count;
165 }
166
167 if(xml_writer->current_element)
168 xml_writer->current_element->content_cdata_seen=1;
169
170 return 0;
171 }
172
173
174 struct nsd {
175 const raptor_namespace *nspace;
176 unsigned char *declaration;
177 size_t length;
178 };
179
180
181 /*
182 * FIXME: This is duplicate code taken from raptor_sax2.c:
183 * struct nsd
184 * raptor_xml_writer_nsd_compare (from raptor_nsd_compare)
185 */
186
187 static int
raptor_xml_writer_nsd_compare(const void * a,const void * b)188 raptor_xml_writer_nsd_compare(const void *a, const void *b)
189 {
190 struct nsd* nsd_a=(struct nsd*)a;
191 struct nsd* nsd_b=(struct nsd*)b;
192 return strcmp((const char*)nsd_a->declaration, (const char*)nsd_b->declaration);
193 }
194
195
196 static int
raptor_xml_writer_start_element_common(raptor_xml_writer * xml_writer,raptor_xml_element * element,int auto_empty)197 raptor_xml_writer_start_element_common(raptor_xml_writer* xml_writer,
198 raptor_xml_element* element,
199 int auto_empty)
200 {
201 raptor_iostream* iostr=xml_writer->iostr;
202 raptor_namespace_stack *nstack=xml_writer->nstack;
203 raptor_simple_message_handler error_handler=xml_writer->error_handler;
204 void *error_data=xml_writer->error_data;
205 int depth=xml_writer->depth;
206 int auto_indent=XML_WRITER_AUTO_INDENT(xml_writer);
207 int xml_version=xml_writer->xml_version;
208 struct nsd *nspace_declarations=NULL;
209 size_t nspace_declarations_count=0;
210 unsigned int i;
211
212 /* max is 1 per element and 1 for each attribute + size of declared */
213 if(nstack) {
214 int nspace_max_count=element->attribute_count+1;
215 if(element->declared_nspaces)
216 nspace_max_count += raptor_sequence_size(element->declared_nspaces);
217
218 nspace_declarations=(struct nsd*)RAPTOR_CALLOC(nsdarray, nspace_max_count, sizeof(struct nsd));
219 if(!nspace_declarations)
220 return 1;
221 }
222
223 if(element->name->nspace) {
224 if(nstack && !raptor_namespaces_namespace_in_scope(nstack, element->name->nspace)) {
225 nspace_declarations[0].declaration=
226 raptor_namespaces_format(element->name->nspace,
227 &nspace_declarations[0].length);
228 if(!nspace_declarations[0].declaration)
229 goto error;
230 nspace_declarations[0].nspace=element->name->nspace;
231 nspace_declarations_count++;
232 }
233 }
234
235 if (element->attributes) {
236 for(i=0; i < element->attribute_count; i++) {
237 /* qname */
238 if(element->attributes[i]->nspace) {
239 if(nstack &&
240 !raptor_namespaces_namespace_in_scope(nstack, element->attributes[i]->nspace) && element->attributes[i]->nspace != element->name->nspace) {
241 /* not in scope and not same as element (so already going to be declared)*/
242 unsigned int j;
243 int declare_me=1;
244
245 /* check it wasn't an earlier declaration too */
246 for (j=0; j < nspace_declarations_count; j++)
247 if(nspace_declarations[j].nspace == element->attributes[j]->nspace) {
248 declare_me=0;
249 break;
250 }
251
252 if(declare_me) {
253 nspace_declarations[nspace_declarations_count].declaration=
254 raptor_namespaces_format(element->attributes[i]->nspace,
255 &nspace_declarations[nspace_declarations_count].length);
256 if(!nspace_declarations[nspace_declarations_count].declaration)
257 goto error;
258 nspace_declarations[nspace_declarations_count].nspace=element->attributes[i]->nspace;
259 nspace_declarations_count++;
260 }
261 }
262 }
263 }
264 }
265
266 if(nstack && element->declared_nspaces &&
267 raptor_sequence_size(element->declared_nspaces) > 0) {
268 for(i=0; i< (unsigned int)raptor_sequence_size(element->declared_nspaces); i++) {
269 raptor_namespace* nspace=(raptor_namespace*)raptor_sequence_get_at(element->declared_nspaces, i);
270 unsigned int j;
271 int declare_me=1;
272
273 /* check it wasn't an earlier declaration too */
274 for (j=0; j < nspace_declarations_count; j++)
275 if(nspace_declarations[j].nspace == nspace) {
276 declare_me=0;
277 break;
278 }
279
280 if(declare_me) {
281 nspace_declarations[nspace_declarations_count].declaration=
282 raptor_namespaces_format(nspace,
283 &nspace_declarations[nspace_declarations_count].length);
284 if(!nspace_declarations[nspace_declarations_count].declaration)
285 goto error;
286 nspace_declarations[nspace_declarations_count].nspace=nspace;
287 nspace_declarations_count++;
288 }
289
290 }
291 }
292
293 raptor_iostream_write_byte(iostr, '<');
294
295 if(element->name->nspace && element->name->nspace->prefix_length > 0) {
296 raptor_iostream_write_counted_string(iostr,
297 (const char*)element->name->nspace->prefix,
298 element->name->nspace->prefix_length);
299 raptor_iostream_write_byte(iostr, ':');
300 }
301 raptor_iostream_write_counted_string(iostr,
302 (const char*)element->name->local_name,
303 element->name->local_name_length);
304
305 /* declare namespaces */
306 if(nspace_declarations_count) {
307 /* sort them into the canonical order */
308 qsort((void*)nspace_declarations,
309 nspace_declarations_count, sizeof(struct nsd),
310 raptor_xml_writer_nsd_compare);
311 /* add them */
312 for (i=0; i < nspace_declarations_count; i++) {
313 if(auto_indent && nspace_declarations_count > 1) {
314 /* indent xmlns namespace attributes */
315 raptor_xml_writer_newline(xml_writer);
316 xml_writer->depth++;
317 raptor_xml_writer_indent(xml_writer);
318 xml_writer->depth--;
319 }
320 raptor_iostream_write_byte(iostr, ' ');
321 raptor_iostream_write_counted_string(iostr,
322 (const char*)nspace_declarations[i].declaration,
323 nspace_declarations[i].length);
324 RAPTOR_FREE(cstring, nspace_declarations[i].declaration);
325 nspace_declarations[i].declaration=NULL;
326
327 if(raptor_namespace_copy(nstack,
328 (raptor_namespace*)nspace_declarations[i].nspace,
329 depth))
330 goto error;
331 }
332 }
333
334
335 if(element->attributes) {
336 for(i=0; i < element->attribute_count; i++) {
337 raptor_iostream_write_byte(iostr, ' ');
338
339 if(element->attributes[i]->nspace &&
340 element->attributes[i]->nspace->prefix_length > 0) {
341 raptor_iostream_write_counted_string(iostr,
342 (char*)element->attributes[i]->nspace->prefix,
343 element->attributes[i]->nspace->prefix_length);
344 raptor_iostream_write_byte(iostr, ':');
345 }
346
347 raptor_iostream_write_counted_string(iostr,
348 (const char*)element->attributes[i]->local_name,
349 element->attributes[i]->local_name_length);
350
351 raptor_iostream_write_counted_string(iostr, "=\"", 2);
352
353 raptor_iostream_write_xml_any_escaped_string(iostr,
354 element->attributes[i]->value,
355 element->attributes[i]->value_length,
356 '"',
357 xml_version,
358 error_handler, error_data);
359 raptor_iostream_write_byte(iostr, '"');
360 }
361 }
362
363 if (!auto_empty)
364 raptor_iostream_write_byte(iostr, '>');
365
366 if(nstack)
367 RAPTOR_FREE(stringarray, nspace_declarations);
368
369 return 0;
370
371 /* Clean up nspace_declarations on error */
372 error:
373
374 for (i=0; i < nspace_declarations_count; i++) {
375 if(nspace_declarations[i].declaration)
376 RAPTOR_FREE(cstring, nspace_declarations[i].declaration);
377 }
378
379 if(nspace_declarations)
380 RAPTOR_FREE(stringarray, nspace_declarations);
381
382 return 1;
383 }
384
385
386 static int
raptor_xml_writer_end_element_common(raptor_xml_writer * xml_writer,raptor_xml_element * element,int is_empty)387 raptor_xml_writer_end_element_common(raptor_xml_writer* xml_writer,
388 raptor_xml_element *element,
389 int is_empty)
390 {
391 raptor_iostream* iostr=xml_writer->iostr;
392
393 if (is_empty)
394 raptor_iostream_write_byte(iostr, '/');
395 else {
396
397 raptor_iostream_write_byte(iostr, '<');
398
399 raptor_iostream_write_byte(iostr, '/');
400
401 if(element->name->nspace && element->name->nspace->prefix_length > 0) {
402 raptor_iostream_write_counted_string(iostr,
403 (const char*)element->name->nspace->prefix,
404 element->name->nspace->prefix_length);
405 raptor_iostream_write_byte(iostr, ':');
406 }
407 raptor_iostream_write_counted_string(iostr,
408 (const char*)element->name->local_name,
409 element->name->local_name_length);
410 }
411
412 raptor_iostream_write_byte(iostr, '>');
413
414 return 0;
415
416 }
417
418
419 #ifndef RAPTOR_DISABLE_V1
420 /**
421 * raptor_new_xml_writer:
422 * @nstack: Namespace stack for the writer to start with (or NULL)
423 * @uri_handler: URI handler function (ignored)
424 * @uri_context: URI handler context data (ignored)
425 * @iostr: I/O stream to write to
426 * @error_handler: error handler function
427 * @error_data: error handler data
428 * @canonicalize: unused
429 *
430 * Constructor - Create a new XML Writer writing XML to a raptor_iostream
431 *
432 * @uri_handler and @uri_context parameters are ignored but are retained
433 * in the API for backwards compatibility. Internally the same uri handler
434 * as returned by raptor_uri_get_handler() will be used.
435 *
436 * raptor_init() MUST have been called before calling this function.
437 * Use raptor_new_xml_writer_v2() if using raptor_world APIs.
438 *
439 * Return value: a new #raptor_xml_writer object or NULL on failure
440 **/
441 raptor_xml_writer*
raptor_new_xml_writer(raptor_namespace_stack * nstack,const raptor_uri_handler * uri_handler,void * uri_context,raptor_iostream * iostr,raptor_simple_message_handler error_handler,void * error_data,int canonicalize)442 raptor_new_xml_writer(raptor_namespace_stack *nstack,
443 const raptor_uri_handler *uri_handler,
444 void *uri_context,
445 raptor_iostream* iostr,
446 raptor_simple_message_handler error_handler,
447 void *error_data,
448 int canonicalize)
449 {
450 return raptor_new_xml_writer_v2(raptor_world_instance(),
451 nstack,
452 iostr,
453 error_handler,
454 error_data,
455 canonicalize);
456 }
457 #endif
458
459
460 /**
461 * raptor_new_xml_writer_v2:
462 * @world: raptor_world object
463 * @nstack: Namespace stack for the writer to start with (or NULL)
464 * @iostr: I/O stream to write to
465 * @error_handler: error handler function
466 * @error_data: error handler data
467 * @canonicalize: unused
468 *
469 * Constructor - Create a new XML Writer writing XML to a raptor_iostream
470 *
471 * Return value: a new #raptor_xml_writer object or NULL on failure
472 **/
473 raptor_xml_writer*
raptor_new_xml_writer_v2(raptor_world * world,raptor_namespace_stack * nstack,raptor_iostream * iostr,raptor_simple_message_handler error_handler,void * error_data,int canonicalize)474 raptor_new_xml_writer_v2(raptor_world* world,
475 raptor_namespace_stack *nstack,
476 raptor_iostream* iostr,
477 raptor_simple_message_handler error_handler,
478 void *error_data,
479 int canonicalize)
480 {
481 raptor_xml_writer* xml_writer;
482
483 xml_writer=(raptor_xml_writer*)RAPTOR_CALLOC(raptor_xml_writer, 1, sizeof(raptor_xml_writer)+1);
484 if(!xml_writer)
485 return NULL;
486
487 xml_writer->nstack_depth=0;
488
489 xml_writer->error_handler=error_handler;
490 xml_writer->error_data=error_data;
491
492 xml_writer->nstack=nstack;
493 if(!xml_writer->nstack) {
494 xml_writer->nstack=nstack=raptor_new_namespaces_v2(world,
495 error_handler, error_data,
496 1);
497 xml_writer->my_nstack=1;
498 }
499
500 xml_writer->iostr=iostr;
501
502 xml_writer->flags = 0;
503 xml_writer->indent = 2;
504
505 xml_writer->xml_version = 10;
506
507 /* Write XML declaration */
508 xml_writer->xml_declaration=1;
509
510 return xml_writer;
511 }
512
513
514 /**
515 * raptor_free_xml_writer:
516 * @xml_writer: XML writer object
517 *
518 * Destructor - Free XML Writer
519 *
520 **/
521 void
raptor_free_xml_writer(raptor_xml_writer * xml_writer)522 raptor_free_xml_writer(raptor_xml_writer* xml_writer)
523 {
524 RAPTOR_ASSERT_OBJECT_POINTER_RETURN(xml_writer, raptor_xml_writer);
525
526 if(xml_writer->nstack && xml_writer->my_nstack)
527 raptor_free_namespaces(xml_writer->nstack);
528
529 RAPTOR_FREE(raptor_xml_writer, xml_writer);
530 }
531
532
533 static void
raptor_xml_writer_write_xml_declaration(raptor_xml_writer * xml_writer)534 raptor_xml_writer_write_xml_declaration(raptor_xml_writer* xml_writer)
535 {
536 if(!xml_writer->xml_declaration_checked) {
537 /* check that it should be written once only */
538 xml_writer->xml_declaration_checked=1;
539
540 if(xml_writer->xml_declaration) {
541 raptor_iostream_write_string(xml_writer->iostr,
542 (const unsigned char*)"<?xml version=\"");
543 raptor_iostream_write_counted_string(xml_writer->iostr,
544 (xml_writer->xml_version == 10) ?
545 (const unsigned char*)"1.0" :
546 (const unsigned char*)"1.1",
547 3);
548 raptor_iostream_write_string(xml_writer->iostr,
549 (const unsigned char*)"\" encoding=\"utf-8\"?>\n");
550 }
551 }
552
553 }
554
555
556 /**
557 * raptor_xml_writer_empty_element:
558 * @xml_writer: XML writer object
559 * @element: XML element object
560 *
561 * Write an empty XML element to the XML writer.
562 *
563 * Closes any previous empty element if XML writer feature AUTO_EMPTY
564 * is enabled.
565 **/
566 void
raptor_xml_writer_empty_element(raptor_xml_writer * xml_writer,raptor_xml_element * element)567 raptor_xml_writer_empty_element(raptor_xml_writer* xml_writer,
568 raptor_xml_element *element)
569 {
570 raptor_xml_writer_write_xml_declaration(xml_writer);
571
572 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
573
574 if(xml_writer->pending_newline || XML_WRITER_AUTO_INDENT(xml_writer))
575 raptor_xml_writer_indent(xml_writer);
576
577 raptor_xml_writer_start_element_common(xml_writer, element, 1);
578
579 raptor_xml_writer_end_element_common(xml_writer, element, 1);
580
581 raptor_namespaces_end_for_depth(xml_writer->nstack, xml_writer->depth);
582 }
583
584
585 /**
586 * raptor_xml_writer_start_element:
587 * @xml_writer: XML writer object
588 * @element: XML element object
589 *
590 * Write a start XML element to the XML writer.
591 *
592 * Closes any previous empty element if XML writer feature AUTO_EMPTY
593 * is enabled.
594 *
595 * Indents the start element if XML writer feature AUTO_INDENT is enabled.
596 **/
597 void
raptor_xml_writer_start_element(raptor_xml_writer * xml_writer,raptor_xml_element * element)598 raptor_xml_writer_start_element(raptor_xml_writer* xml_writer,
599 raptor_xml_element *element)
600 {
601 raptor_xml_writer_write_xml_declaration(xml_writer);
602
603 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
604
605 if(xml_writer->pending_newline || XML_WRITER_AUTO_INDENT(xml_writer))
606 raptor_xml_writer_indent(xml_writer);
607
608 raptor_xml_writer_start_element_common(xml_writer, element,
609 XML_WRITER_AUTO_EMPTY(xml_writer));
610
611 xml_writer->depth++;
612
613 /* SJS Note: This "if" clause is necessary because raptor_rdfxml.c
614 * uses xml_writer for parseType="literal" and passes in elements
615 * whose parent field is already set. The first time this function
616 * is called, it sets element->parent to 0, causing the warn-07.rdf
617 * test to fail. Subsequent calls to this function set
618 * element->parent to its existing value.
619 */
620 if(xml_writer->current_element)
621 element->parent = xml_writer->current_element;
622
623 xml_writer->current_element=element;
624 if(element && element->parent)
625 element->parent->content_element_seen=1;
626 }
627
628
629 /**
630 * raptor_xml_writer_end_element:
631 * @xml_writer: XML writer object
632 * @element: XML element object
633 *
634 * Write an end XML element to the XML writer.
635 *
636 * Indents the end element if XML writer feature AUTO_INDENT is enabled.
637 **/
638 void
raptor_xml_writer_end_element(raptor_xml_writer * xml_writer,raptor_xml_element * element)639 raptor_xml_writer_end_element(raptor_xml_writer* xml_writer,
640 raptor_xml_element* element)
641 {
642 int is_empty;
643
644 xml_writer->depth--;
645
646 if(xml_writer->pending_newline ||
647 (XML_WRITER_AUTO_INDENT(xml_writer) && element->content_element_seen))
648 raptor_xml_writer_indent(xml_writer);
649
650 is_empty = XML_WRITER_AUTO_EMPTY(xml_writer) ?
651 !(element->content_cdata_seen || element->content_element_seen) : 0;
652
653 raptor_xml_writer_end_element_common(xml_writer, element, is_empty);
654
655 raptor_namespaces_end_for_depth(xml_writer->nstack, xml_writer->depth);
656
657 if(xml_writer->current_element)
658 xml_writer->current_element = xml_writer->current_element->parent;
659 }
660
661
662 /**
663 * raptor_xml_writer_newline:
664 * @xml_writer: XML writer object
665 *
666 * Write a newline to the XML writer.
667 *
668 * Indents the next line if XML writer feature AUTO_INDENT is enabled.
669 **/
670 void
raptor_xml_writer_newline(raptor_xml_writer * xml_writer)671 raptor_xml_writer_newline(raptor_xml_writer* xml_writer)
672 {
673 xml_writer->pending_newline=1;
674 }
675
676
677 /**
678 * raptor_xml_writer_cdata:
679 * @xml_writer: XML writer object
680 * @s: string to XML escape and write
681 *
682 * Write CDATA XML-escaped to the XML writer.
683 *
684 * Closes any previous empty element if XML writer feature AUTO_EMPTY
685 * is enabled.
686 *
687 **/
688 void
raptor_xml_writer_cdata(raptor_xml_writer * xml_writer,const unsigned char * s)689 raptor_xml_writer_cdata(raptor_xml_writer* xml_writer,
690 const unsigned char *s)
691 {
692 raptor_xml_writer_write_xml_declaration(xml_writer);
693
694 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
695
696 raptor_iostream_write_xml_any_escaped_string(xml_writer->iostr,
697 s, strlen((const char*)s),
698 '\0',
699 xml_writer->xml_version,
700 xml_writer->error_handler,
701 xml_writer->error_data);
702
703 if(xml_writer->current_element)
704 xml_writer->current_element->content_cdata_seen=1;
705 }
706
707
708 /**
709 * raptor_xml_writer_cdata_counted:
710 * @xml_writer: XML writer object
711 * @s: string to XML escape and write
712 * @len: length of string
713 *
714 * Write counted CDATA XML-escaped to the XML writer.
715 *
716 * Closes any previous empty element if XML writer feature AUTO_EMPTY
717 * is enabled.
718 *
719 **/
720 void
raptor_xml_writer_cdata_counted(raptor_xml_writer * xml_writer,const unsigned char * s,unsigned int len)721 raptor_xml_writer_cdata_counted(raptor_xml_writer* xml_writer,
722 const unsigned char *s, unsigned int len)
723 {
724 raptor_xml_writer_write_xml_declaration(xml_writer);
725
726 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
727
728 raptor_iostream_write_xml_any_escaped_string(xml_writer->iostr,
729 s, len,
730 '\0',
731 xml_writer->xml_version,
732 xml_writer->error_handler,
733 xml_writer->error_data);
734
735 if(xml_writer->current_element)
736 xml_writer->current_element->content_cdata_seen=1;
737 }
738
739
740 /**
741 * raptor_xml_writer_raw:
742 * @xml_writer: XML writer object
743 * @s: string to write
744 *
745 * Write a string raw to the XML writer.
746 *
747 * Closes any previous empty element if XML writer feature AUTO_EMPTY
748 * is enabled.
749 *
750 **/
751 void
raptor_xml_writer_raw(raptor_xml_writer * xml_writer,const unsigned char * s)752 raptor_xml_writer_raw(raptor_xml_writer* xml_writer,
753 const unsigned char *s)
754 {
755 raptor_xml_writer_write_xml_declaration(xml_writer);
756
757 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
758
759 raptor_iostream_write_string(xml_writer->iostr, s);
760
761 if(xml_writer->current_element)
762 xml_writer->current_element->content_cdata_seen=1;
763 }
764
765
766 /**
767 * raptor_xml_writer_raw_counted:
768 * @xml_writer: XML writer object
769 * @s: string to write
770 * @len: length of string
771 *
772 * Write a counted string raw to the XML writer.
773 *
774 * Closes any previous empty element if XML writer feature AUTO_EMPTY
775 * is enabled.
776 *
777 **/
778 void
raptor_xml_writer_raw_counted(raptor_xml_writer * xml_writer,const unsigned char * s,unsigned int len)779 raptor_xml_writer_raw_counted(raptor_xml_writer* xml_writer,
780 const unsigned char *s, unsigned int len)
781 {
782 raptor_xml_writer_write_xml_declaration(xml_writer);
783
784 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
785
786 raptor_iostream_write_counted_string(xml_writer->iostr, s, len);
787
788 if(xml_writer->current_element)
789 xml_writer->current_element->content_cdata_seen=1;
790 }
791
792
793 /**
794 * raptor_xml_writer_comment:
795 * @xml_writer: XML writer object
796 * @s: comment string to write
797 *
798 * Write an XML comment to the XML writer.
799 *
800 * Closes any previous empty element if XML writer feature AUTO_EMPTY
801 * is enabled.
802 *
803 **/
804 void
raptor_xml_writer_comment(raptor_xml_writer * xml_writer,const unsigned char * s)805 raptor_xml_writer_comment(raptor_xml_writer* xml_writer,
806 const unsigned char *s)
807 {
808 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
809
810 raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"<!-- ", 5);
811 raptor_xml_writer_cdata(xml_writer, s);
812 raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" -->", 4);
813 }
814
815
816 /**
817 * raptor_xml_writer_comment_counted:
818 * @xml_writer: XML writer object
819 * @s: comment string to write
820 * @len: length of string
821 *
822 * Write a counted XML comment to the XML writer.
823 *
824 * Closes any previous empty element if XML writer feature AUTO_EMPTY
825 * is enabled.
826 *
827 **/
828 void
raptor_xml_writer_comment_counted(raptor_xml_writer * xml_writer,const unsigned char * s,unsigned int len)829 raptor_xml_writer_comment_counted(raptor_xml_writer* xml_writer,
830 const unsigned char *s, unsigned int len)
831 {
832 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
833
834 raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"<!-- ", 5);
835 raptor_xml_writer_cdata_counted(xml_writer, s, len);
836 raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" -->", 4);
837 }
838
839
840 #ifndef RAPTOR_DISABLE_V1
841 /**
842 * raptor_xml_writer_features_enumerate:
843 * @feature: feature enumeration (0+)
844 * @name: pointer to store feature short name (or NULL)
845 * @uri: pointer to store feature URI (or NULL)
846 * @label: pointer to feature label (or NULL)
847 *
848 * Get list of xml_writer features.
849 *
850 * If uri is not NULL, a pointer to a new raptor_uri is returned
851 * that must be freed by the caller with raptor_free_uri().
852 *
853 * raptor_init() MUST have been called before calling this function.
854 * Use raptor_xml_writer_features_enumerate_v2() if using raptor_world APIs.
855 *
856 * Return value: 0 on success, <0 on failure, >0 if feature is unknown
857 **/
858 int
raptor_xml_writer_features_enumerate(const raptor_feature feature,const char ** name,raptor_uri ** uri,const char ** label)859 raptor_xml_writer_features_enumerate(const raptor_feature feature,
860 const char **name,
861 raptor_uri **uri, const char **label)
862 {
863 return raptor_xml_writer_features_enumerate_v2(raptor_world_instance(),
864 feature, name, uri, label);
865 }
866 #endif
867
868
869 /**
870 * raptor_xml_writer_features_enumerate_v2:
871 * @world: raptor_world object
872 * @feature: feature enumeration (0+)
873 * @name: pointer to store feature short name (or NULL)
874 * @uri: pointer to store feature URI (or NULL)
875 * @label: pointer to feature label (or NULL)
876 *
877 * Get list of xml_writer features.
878 *
879 * If uri is not NULL, a pointer to a new raptor_uri is returned
880 * that must be freed by the caller with raptor_free_uri_v2().
881 *
882 * Return value: 0 on success, <0 on failure, >0 if feature is unknown
883 **/
884 int
raptor_xml_writer_features_enumerate_v2(raptor_world * world,const raptor_feature feature,const char ** name,raptor_uri ** uri,const char ** label)885 raptor_xml_writer_features_enumerate_v2(raptor_world* world,
886 const raptor_feature feature,
887 const char **name,
888 raptor_uri **uri, const char **label)
889 {
890 return raptor_features_enumerate_common(world, feature, name, uri, label, 8);
891 }
892
893
894 /**
895 * raptor_xml_writer_flush:
896 * @xml_writer: XML writer object
897 *
898 * Finish the XML writer.
899 *
900 **/
901 void
raptor_xml_writer_flush(raptor_xml_writer * xml_writer)902 raptor_xml_writer_flush(raptor_xml_writer* xml_writer)
903 {
904 if(xml_writer->pending_newline) {
905 raptor_iostream_write_byte(xml_writer->iostr, '\n');
906 xml_writer->pending_newline=0;
907 }
908 }
909
910
911 /**
912 * raptor_xml_writer_set_feature:
913 * @xml_writer: #raptor_xml_writer xml_writer object
914 * @feature: feature to set from enumerated #raptor_feature values
915 * @value: integer feature value (0 or larger)
916 *
917 * Set xml_writer features with integer values.
918 *
919 * The allowed features are available via raptor_features_enumerate().
920 *
921 * Return value: non 0 on failure or if the feature is unknown
922 **/
923 int
raptor_xml_writer_set_feature(raptor_xml_writer * xml_writer,raptor_feature feature,int value)924 raptor_xml_writer_set_feature(raptor_xml_writer *xml_writer,
925 raptor_feature feature, int value)
926 {
927 if(value < 0)
928 return -1;
929
930 switch(feature) {
931 case RAPTOR_FEATURE_WRITER_AUTO_INDENT:
932 if (value)
933 xml_writer->flags |= XML_WRITER_AUTO_INDENT;
934 else
935 xml_writer->flags &= ~XML_WRITER_AUTO_INDENT;
936 break;
937
938 case RAPTOR_FEATURE_WRITER_AUTO_EMPTY:
939 if (value)
940 xml_writer->flags |= XML_WRITER_AUTO_EMPTY;
941 else
942 xml_writer->flags &= ~XML_WRITER_AUTO_EMPTY;
943 break;
944
945 case RAPTOR_FEATURE_WRITER_INDENT_WIDTH:
946 xml_writer->indent = value;
947 break;
948
949 case RAPTOR_FEATURE_WRITER_XML_VERSION:
950 if(value == 10 || value == 11)
951 xml_writer->xml_version = value;
952 break;
953
954 case RAPTOR_FEATURE_WRITER_XML_DECLARATION:
955 xml_writer->xml_declaration = value;
956 break;
957
958 /* parser features */
959 case RAPTOR_FEATURE_SCANNING:
960 case RAPTOR_FEATURE_ASSUME_IS_RDF:
961 case RAPTOR_FEATURE_ALLOW_NON_NS_ATTRIBUTES:
962 case RAPTOR_FEATURE_ALLOW_OTHER_PARSETYPES:
963 case RAPTOR_FEATURE_ALLOW_BAGID:
964 case RAPTOR_FEATURE_ALLOW_RDF_TYPE_RDF_LIST:
965 case RAPTOR_FEATURE_NORMALIZE_LANGUAGE:
966 case RAPTOR_FEATURE_NON_NFC_FATAL:
967 case RAPTOR_FEATURE_WARN_OTHER_PARSETYPES:
968 case RAPTOR_FEATURE_CHECK_RDF_ID:
969 case RAPTOR_FEATURE_HTML_TAG_SOUP:
970 case RAPTOR_FEATURE_MICROFORMATS:
971 case RAPTOR_FEATURE_HTML_LINK:
972 case RAPTOR_FEATURE_WWW_TIMEOUT:
973
974 /* Shared */
975 case RAPTOR_FEATURE_NO_NET:
976 case RAPTOR_FEATURE_LOAD_EXTERNAL_ENTITIES:
977
978 /* XML writer features */
979 case RAPTOR_FEATURE_RELATIVE_URIS:
980 case RAPTOR_FEATURE_START_URI:
981
982 /* DOT serializer features */
983 case RAPTOR_FEATURE_RESOURCE_BORDER:
984 case RAPTOR_FEATURE_LITERAL_BORDER:
985 case RAPTOR_FEATURE_BNODE_BORDER:
986 case RAPTOR_FEATURE_RESOURCE_FILL:
987 case RAPTOR_FEATURE_LITERAL_FILL:
988 case RAPTOR_FEATURE_BNODE_FILL:
989
990 /* JSON serializer features */
991 case RAPTOR_FEATURE_JSON_CALLBACK:
992 case RAPTOR_FEATURE_JSON_EXTRA_DATA:
993 case RAPTOR_FEATURE_RSS_TRIPLES:
994 case RAPTOR_FEATURE_ATOM_ENTRY_URI:
995 case RAPTOR_FEATURE_PREFIX_ELEMENTS:
996
997 /* Turtle serializer feature */
998 case RAPTOR_FEATURE_WRITE_BASE_URI:
999
1000 /* WWW feature */
1001 case RAPTOR_FEATURE_WWW_HTTP_CACHE_CONTROL:
1002 case RAPTOR_FEATURE_WWW_HTTP_USER_AGENT:
1003
1004 default:
1005 return -1;
1006 break;
1007 }
1008
1009 return 0;
1010 }
1011
1012
1013 /**
1014 * raptor_xml_writer_set_feature_string:
1015 * @xml_writer: #raptor_xml_writer xml_writer object
1016 * @feature: feature to set from enumerated #raptor_feature values
1017 * @value: feature value
1018 *
1019 * Set xml_writer features with string values.
1020 *
1021 * The allowed features are available via raptor_xml_writer_features_enumerate().
1022 * If the feature type is integer, the value is interpreted as an integer.
1023 *
1024 * Return value: non 0 on failure or if the feature is unknown
1025 **/
1026 int
raptor_xml_writer_set_feature_string(raptor_xml_writer * xml_writer,raptor_feature feature,const unsigned char * value)1027 raptor_xml_writer_set_feature_string(raptor_xml_writer *xml_writer,
1028 raptor_feature feature,
1029 const unsigned char *value)
1030 {
1031 int value_is_string=(raptor_feature_value_type(feature) == 1);
1032 if(!value_is_string)
1033 return raptor_xml_writer_set_feature(xml_writer, feature,
1034 atoi((const char*)value));
1035 else
1036 return -1;
1037 }
1038
1039
1040 /**
1041 * raptor_xml_writer_get_feature:
1042 * @xml_writer: #raptor_xml_writer xml writer object
1043 * @feature: feature to get value
1044 *
1045 * Get various xml_writer features.
1046 *
1047 * The allowed features are available via raptor_features_enumerate().
1048 *
1049 * Note: no feature value is negative
1050 *
1051 * Return value: feature value or < 0 for an illegal feature
1052 **/
1053 int
raptor_xml_writer_get_feature(raptor_xml_writer * xml_writer,raptor_feature feature)1054 raptor_xml_writer_get_feature(raptor_xml_writer *xml_writer,
1055 raptor_feature feature)
1056 {
1057 int result= -1;
1058
1059 switch(feature) {
1060 case RAPTOR_FEATURE_WRITER_AUTO_INDENT:
1061 result=XML_WRITER_AUTO_INDENT(xml_writer);
1062 break;
1063
1064 case RAPTOR_FEATURE_WRITER_AUTO_EMPTY:
1065 result=XML_WRITER_AUTO_EMPTY(xml_writer);
1066 break;
1067
1068 case RAPTOR_FEATURE_WRITER_INDENT_WIDTH:
1069 result=xml_writer->indent;
1070 break;
1071
1072 case RAPTOR_FEATURE_WRITER_XML_VERSION:
1073 result=xml_writer->xml_version;
1074 break;
1075
1076 case RAPTOR_FEATURE_WRITER_XML_DECLARATION:
1077 result=xml_writer->xml_declaration;
1078 break;
1079
1080 /* parser features */
1081 case RAPTOR_FEATURE_SCANNING:
1082 case RAPTOR_FEATURE_ASSUME_IS_RDF:
1083 case RAPTOR_FEATURE_ALLOW_NON_NS_ATTRIBUTES:
1084 case RAPTOR_FEATURE_ALLOW_OTHER_PARSETYPES:
1085 case RAPTOR_FEATURE_ALLOW_BAGID:
1086 case RAPTOR_FEATURE_ALLOW_RDF_TYPE_RDF_LIST:
1087 case RAPTOR_FEATURE_NORMALIZE_LANGUAGE:
1088 case RAPTOR_FEATURE_NON_NFC_FATAL:
1089 case RAPTOR_FEATURE_WARN_OTHER_PARSETYPES:
1090 case RAPTOR_FEATURE_CHECK_RDF_ID:
1091 case RAPTOR_FEATURE_HTML_TAG_SOUP:
1092 case RAPTOR_FEATURE_MICROFORMATS:
1093 case RAPTOR_FEATURE_HTML_LINK:
1094 case RAPTOR_FEATURE_WWW_TIMEOUT:
1095
1096 /* Shared */
1097 case RAPTOR_FEATURE_NO_NET:
1098 case RAPTOR_FEATURE_LOAD_EXTERNAL_ENTITIES:
1099
1100 /* XML writer features */
1101 case RAPTOR_FEATURE_RELATIVE_URIS:
1102 case RAPTOR_FEATURE_START_URI:
1103
1104 /* DOT serializer features */
1105 case RAPTOR_FEATURE_RESOURCE_BORDER:
1106 case RAPTOR_FEATURE_LITERAL_BORDER:
1107 case RAPTOR_FEATURE_BNODE_BORDER:
1108 case RAPTOR_FEATURE_RESOURCE_FILL:
1109 case RAPTOR_FEATURE_LITERAL_FILL:
1110 case RAPTOR_FEATURE_BNODE_FILL:
1111
1112 /* JSON serializer features */
1113 case RAPTOR_FEATURE_JSON_CALLBACK:
1114 case RAPTOR_FEATURE_JSON_EXTRA_DATA:
1115 case RAPTOR_FEATURE_RSS_TRIPLES:
1116 case RAPTOR_FEATURE_ATOM_ENTRY_URI:
1117 case RAPTOR_FEATURE_PREFIX_ELEMENTS:
1118
1119 /* Turtle serializer feature */
1120 case RAPTOR_FEATURE_WRITE_BASE_URI:
1121
1122 /* WWW feature */
1123 case RAPTOR_FEATURE_WWW_HTTP_CACHE_CONTROL:
1124 case RAPTOR_FEATURE_WWW_HTTP_USER_AGENT:
1125
1126 default:
1127 break;
1128 }
1129
1130 return result;
1131 }
1132
1133
1134 /**
1135 * raptor_xml_writer_get_feature_string:
1136 * @xml_writer: #raptor_xml_writer xml writer object
1137 * @feature: feature to get value
1138 *
1139 * Get xml_writer features with string values.
1140 *
1141 * The allowed features are available via raptor_features_enumerate().
1142 *
1143 * Return value: feature value or NULL for an illegal feature or no value
1144 **/
1145 const unsigned char *
raptor_xml_writer_get_feature_string(raptor_xml_writer * xml_writer,raptor_feature feature)1146 raptor_xml_writer_get_feature_string(raptor_xml_writer *xml_writer,
1147 raptor_feature feature)
1148 {
1149 return NULL;
1150 }
1151
1152
1153 /**
1154 * raptor_xml_writer_get_depth:
1155 * @xml_writer: #raptor_xml_writer xml writer object
1156 *
1157 * Get the current XML Writer element depth
1158 *
1159 * Return value: element stack depth
1160 */
1161 int
raptor_xml_writer_get_depth(raptor_xml_writer * xml_writer)1162 raptor_xml_writer_get_depth(raptor_xml_writer *xml_writer)
1163 {
1164 return xml_writer->depth;
1165 }
1166
1167
1168 #endif
1169
1170
1171
1172 #ifdef STANDALONE
1173
1174 /* one more prototype */
1175 int main(int argc, char *argv[]);
1176
1177
1178 const unsigned char *base_uri_string=(const unsigned char*)"http://example.org/base#";
1179
1180 #define OUT_BYTES_COUNT 135
1181
1182 int
main(int argc,char * argv[])1183 main(int argc, char *argv[])
1184 {
1185 raptor_world *world;
1186 const char *program=raptor_basename(argv[0]);
1187 raptor_iostream *iostr;
1188 raptor_namespace_stack *nstack;
1189 raptor_namespace* foo_ns;
1190 raptor_xml_writer* xml_writer;
1191 raptor_uri* base_uri;
1192 raptor_qname* el_name;
1193 raptor_xml_element *element;
1194 unsigned long offset;
1195 raptor_qname **attrs;
1196 raptor_uri* base_uri_copy=NULL;
1197
1198 /* for raptor_new_iostream_to_string */
1199 void *string=NULL;
1200 size_t string_len=0;
1201
1202 world = raptor_new_world();
1203 if(!world || raptor_world_open(world))
1204 exit(1);
1205
1206 iostr=raptor_new_iostream_to_string(&string, &string_len, NULL);
1207 if(!iostr) {
1208 fprintf(stderr, "%s: Failed to create iostream to string\n", program);
1209 exit(1);
1210 }
1211
1212 nstack=raptor_new_namespaces_v2(world,
1213 NULL, NULL, /* errors */
1214 1);
1215
1216 xml_writer=raptor_new_xml_writer_v2(world,
1217 nstack,
1218 iostr,
1219 NULL, NULL, /* errors */
1220 1);
1221 if(!xml_writer) {
1222 fprintf(stderr, "%s: Failed to create xml_writer to iostream\n", program);
1223 exit(1);
1224 }
1225
1226 base_uri=raptor_new_uri_v2(world, base_uri_string);
1227
1228 foo_ns=raptor_new_namespace(nstack,
1229 (const unsigned char*)"foo",
1230 (const unsigned char*)"http://example.org/foo-ns#",
1231 0);
1232
1233
1234 el_name=raptor_new_qname_from_namespace_local_name_v2(world,
1235 foo_ns,
1236 (const unsigned char*)"bar",
1237 NULL);
1238 base_uri_copy=base_uri ? raptor_uri_copy_v2(world, base_uri) : NULL;
1239 element=raptor_new_xml_element(el_name,
1240 NULL, /* language */
1241 base_uri_copy);
1242
1243 raptor_xml_writer_start_element(xml_writer, element);
1244 raptor_xml_writer_cdata_counted(xml_writer, (const unsigned char*)"hello\n", 6);
1245 raptor_xml_writer_comment_counted(xml_writer, (const unsigned char*)"comment", 7);
1246 raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n");
1247 raptor_xml_writer_end_element(xml_writer, element);
1248
1249 raptor_free_xml_element(element);
1250
1251 raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n");
1252
1253 el_name=raptor_new_qname(nstack,
1254 (const unsigned char*)"blah",
1255 NULL, /* no attribute value - element */
1256 NULL, NULL); /* errors */
1257 base_uri_copy=base_uri ? raptor_uri_copy_v2(world, base_uri) : NULL;
1258 element=raptor_new_xml_element(el_name,
1259 NULL, /* language */
1260 base_uri_copy);
1261
1262 attrs=(raptor_qname **)RAPTOR_CALLOC(qnamearray, 1, sizeof(raptor_qname*));
1263 attrs[0]=raptor_new_qname(nstack,
1264 (const unsigned char*)"a",
1265 (const unsigned char*)"b", /* attribute value */
1266 NULL, NULL); /* errors */
1267 raptor_xml_element_set_attributes(element, attrs, 1);
1268
1269 raptor_xml_writer_empty_element(xml_writer, element);
1270
1271 raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n");
1272
1273 raptor_free_xml_writer(xml_writer);
1274
1275 raptor_free_xml_element(element);
1276
1277 raptor_free_namespace(foo_ns);
1278
1279 raptor_free_namespaces(nstack);
1280
1281 raptor_free_uri_v2(world, base_uri);
1282
1283
1284 offset=raptor_iostream_tell(iostr);
1285
1286 #if RAPTOR_DEBUG > 1
1287 fprintf(stderr, "%s: Freeing iostream\n", program);
1288 #endif
1289 raptor_free_iostream(iostr);
1290
1291 if(offset != OUT_BYTES_COUNT) {
1292 fprintf(stderr, "%s: I/O stream wrote %d bytes, expected %d\n", program,
1293 (int)offset, (int)OUT_BYTES_COUNT);
1294 fputs("[[", stderr);
1295 (void)fwrite(string, 1, string_len, stderr);
1296 fputs("]]\n", stderr);
1297 return 1;
1298 }
1299
1300 if(!string) {
1301 fprintf(stderr, "%s: I/O stream failed to create a string\n", program);
1302 return 1;
1303 }
1304 string_len=strlen((const char*)string);
1305 if(string_len != offset) {
1306 fprintf(stderr, "%s: I/O stream created a string length %d, expected %d\n", program, (int)string_len, (int)offset);
1307 return 1;
1308 }
1309
1310 #if RAPTOR_DEBUG > 1
1311 fprintf(stderr, "%s: Made XML string of %d bytes\n", program, (int)string_len);
1312 fputs("[[", stderr);
1313 (void)fwrite(string, 1, string_len, stderr);
1314 fputs("]]\n", stderr);
1315 #endif
1316
1317 raptor_free_memory(string);
1318
1319 raptor_free_world(world);
1320
1321 /* keep gcc -Wall happy */
1322 return(0);
1323 }
1324
1325 #endif
1326