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-2010, 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 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <stdarg.h>
34 #ifdef HAVE_ERRNO_H
35 #include <errno.h>
36 #endif
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
40
41 /* Raptor includes */
42 #include "raptor2.h"
43 #include "raptor_internal.h"
44
45 #ifndef STANDALONE
46
47
48 #define XML_WRITER_AUTO_INDENT(xml_writer) RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, RAPTOR_OPTION_WRITER_AUTO_INDENT)
49 #define XML_WRITER_AUTO_EMPTY(xml_writer) RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, RAPTOR_OPTION_WRITER_AUTO_EMPTY)
50 #define XML_WRITER_INDENT(xml_writer) RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, RAPTOR_OPTION_WRITER_INDENT_WIDTH)
51 #define XML_WRITER_XML_VERSION(xml_writer) RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, RAPTOR_OPTION_WRITER_XML_VERSION)
52
53
54 #define XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer) \
55 if((XML_WRITER_AUTO_EMPTY(xml_writer)) && \
56 xml_writer->current_element && \
57 !(xml_writer->current_element->content_cdata_seen || \
58 xml_writer->current_element->content_element_seen)) { \
59 raptor_iostream_write_byte('>', xml_writer->iostr); \
60 }
61
62
63 /* Define this for far too much output */
64 #undef RAPTOR_DEBUG_CDATA
65
66
67 struct raptor_xml_writer_s {
68 raptor_world *world;
69
70 int canonicalize;
71
72 int depth;
73
74 int my_nstack;
75 raptor_namespace_stack *nstack;
76 int nstack_depth;
77
78 raptor_xml_element* current_element;
79
80 /* outputting to this iostream */
81 raptor_iostream *iostr;
82
83 /* Has writing the XML declaration writing been checked? */
84 int xml_declaration_checked;
85
86 /* An extra newline is wanted */
87 int pending_newline;
88
89 /* Options (per-object) */
90 raptor_object_options options;
91 };
92
93
94 /* 16 spaces */
95 #define SPACES_BUFFER_SIZE sizeof(spaces_buffer)
96 static const unsigned char spaces_buffer[] = {
97 ' ', ' ', ' ', ' ',
98 ' ', ' ', ' ', ' ',
99 ' ', ' ', ' ', ' ',
100 ' ', ' ', ' ', ' '
101 };
102
103
104
105 /* helper functions */
106
107 /* Handle printing a pending newline OR newline with indenting */
108 static int
raptor_xml_writer_indent(raptor_xml_writer * xml_writer)109 raptor_xml_writer_indent(raptor_xml_writer *xml_writer)
110 {
111 int num_spaces;
112
113 if(!XML_WRITER_AUTO_INDENT(xml_writer)) {
114 if(xml_writer->pending_newline) {
115 raptor_iostream_write_byte('\n', xml_writer->iostr);
116 xml_writer->pending_newline = 0;
117
118 if(xml_writer->current_element)
119 xml_writer->current_element->content_cdata_seen = 1;
120 }
121 return 0;
122 }
123
124 num_spaces = xml_writer->depth * XML_WRITER_INDENT(xml_writer);
125
126 /* Do not write an extra newline at the start of the document
127 * (after the XML declaration or XMP processing instruction has
128 * been writtten)
129 */
130 if(xml_writer->xml_declaration_checked == 1)
131 xml_writer->xml_declaration_checked++;
132 else {
133 raptor_iostream_write_byte('\n', xml_writer->iostr);
134 xml_writer->pending_newline = 0;
135 }
136
137 while(num_spaces > 0) {
138
139 int count = (num_spaces > RAPTOR_GOOD_CAST(int, SPACES_BUFFER_SIZE)) ?
140 RAPTOR_GOOD_CAST(int, SPACES_BUFFER_SIZE) : num_spaces;
141
142 raptor_iostream_counted_string_write(spaces_buffer, count,
143 xml_writer->iostr);
144
145 num_spaces -= count;
146 }
147
148 if(xml_writer->current_element)
149 xml_writer->current_element->content_cdata_seen = 1;
150
151 return 0;
152 }
153
154
155 struct nsd {
156 const raptor_namespace *nspace;
157 unsigned char *declaration;
158 size_t length;
159 };
160
161
162 static int
raptor_xml_writer_nsd_compare(const void * a,const void * b)163 raptor_xml_writer_nsd_compare(const void *a, const void *b)
164 {
165 struct nsd* nsd_a = (struct nsd*)a;
166 struct nsd* nsd_b = (struct nsd*)b;
167 return strcmp((const char*)nsd_a->declaration, (const char*)nsd_b->declaration);
168 }
169
170
171 static int
raptor_xml_writer_start_element_common(raptor_xml_writer * xml_writer,raptor_xml_element * element,int auto_empty)172 raptor_xml_writer_start_element_common(raptor_xml_writer* xml_writer,
173 raptor_xml_element* element,
174 int auto_empty)
175 {
176 raptor_iostream* iostr = xml_writer->iostr;
177 raptor_namespace_stack *nstack = xml_writer->nstack;
178 int depth = xml_writer->depth;
179 int auto_indent = XML_WRITER_AUTO_INDENT(xml_writer);
180 struct nsd *nspace_declarations = NULL;
181 size_t nspace_declarations_count = 0;
182 unsigned int i;
183
184 if(nstack) {
185 int nspace_max_count = element->attribute_count * 2; /* attr and value */
186 if(element->name->nspace)
187 nspace_max_count++;
188 if(element->declared_nspaces)
189 nspace_max_count += raptor_sequence_size(element->declared_nspaces);
190 if(element->xml_language)
191 nspace_max_count++;
192
193 nspace_declarations = RAPTOR_CALLOC(struct nsd*, nspace_max_count,
194 sizeof(struct nsd));
195 if(!nspace_declarations)
196 return 1;
197 }
198
199 if(element->name->nspace) {
200 if(nstack && !raptor_namespaces_namespace_in_scope(nstack, element->name->nspace)) {
201 nspace_declarations[0].declaration=
202 raptor_namespace_format_as_xml(element->name->nspace,
203 &nspace_declarations[0].length);
204 if(!nspace_declarations[0].declaration)
205 goto error;
206 nspace_declarations[0].nspace = element->name->nspace;
207 nspace_declarations_count++;
208 }
209 }
210
211 if(nstack && element->attributes) {
212 for(i = 0; i < element->attribute_count; i++) {
213 /* qname */
214 if(element->attributes[i]->nspace) {
215 /* Check if we need a namespace declaration attribute */
216 if(nstack &&
217 !raptor_namespaces_namespace_in_scope(nstack, element->attributes[i]->nspace) && element->attributes[i]->nspace != element->name->nspace) {
218 /* not in scope and not same as element (so already going to be declared)*/
219 unsigned int j;
220 int declare_me = 1;
221
222 /* check it wasn't an earlier declaration too */
223 for(j = 0; j < nspace_declarations_count; j++)
224 if(nspace_declarations[j].nspace == element->attributes[i]->nspace) {
225 declare_me = 0;
226 break;
227 }
228
229 if(declare_me) {
230 nspace_declarations[nspace_declarations_count].declaration=
231 raptor_namespace_format_as_xml(element->attributes[i]->nspace,
232 &nspace_declarations[nspace_declarations_count].length);
233 if(!nspace_declarations[nspace_declarations_count].declaration)
234 goto error;
235 nspace_declarations[nspace_declarations_count].nspace = element->attributes[i]->nspace;
236 nspace_declarations_count++;
237 }
238 }
239 }
240
241 /* Add the attribute's value */
242 nspace_declarations[nspace_declarations_count].declaration=
243 raptor_qname_format_as_xml(element->attributes[i],
244 &nspace_declarations[nspace_declarations_count].length);
245 if(!nspace_declarations[nspace_declarations_count].declaration)
246 goto error;
247 nspace_declarations[nspace_declarations_count].nspace = NULL;
248 nspace_declarations_count++;
249
250 }
251 }
252
253 if(nstack && element->declared_nspaces &&
254 raptor_sequence_size(element->declared_nspaces) > 0) {
255 for(i = 0; i< (unsigned int)raptor_sequence_size(element->declared_nspaces); i++) {
256 raptor_namespace* nspace = (raptor_namespace*)raptor_sequence_get_at(element->declared_nspaces, i);
257 unsigned int j;
258 int declare_me = 1;
259
260 /* check it wasn't an earlier declaration too */
261 for(j = 0; j < nspace_declarations_count; j++)
262 if(nspace_declarations[j].nspace == nspace) {
263 declare_me = 0;
264 break;
265 }
266
267 if(declare_me) {
268 nspace_declarations[nspace_declarations_count].declaration=
269 raptor_namespace_format_as_xml(nspace,
270 &nspace_declarations[nspace_declarations_count].length);
271 if(!nspace_declarations[nspace_declarations_count].declaration)
272 goto error;
273 nspace_declarations[nspace_declarations_count].nspace = nspace;
274 nspace_declarations_count++;
275 }
276
277 }
278 }
279
280 if(nstack && element->xml_language) {
281 size_t lang_len = strlen(RAPTOR_GOOD_CAST(char*, element->xml_language));
282 #define XML_LANG_PREFIX_LEN 10
283 size_t buf_length = XML_LANG_PREFIX_LEN + lang_len + 1;
284 unsigned char* buffer = RAPTOR_MALLOC(unsigned char*, buf_length + 1);
285 const char quote = '\"';
286 unsigned char* p;
287
288 memcpy(buffer, "xml:lang=\"", XML_LANG_PREFIX_LEN);
289 p = buffer + XML_LANG_PREFIX_LEN;
290 p += raptor_xml_escape_string(xml_writer->world,
291 element->xml_language, lang_len,
292 p, buf_length, quote);
293 *p++ = quote;
294 *p = '\0';
295
296 nspace_declarations[nspace_declarations_count].declaration = buffer;
297 nspace_declarations[nspace_declarations_count].length = buf_length;
298 nspace_declarations[nspace_declarations_count].nspace = NULL;
299 nspace_declarations_count++;
300 }
301
302
303 raptor_iostream_write_byte('<', iostr);
304
305 if(element->name->nspace && element->name->nspace->prefix_length > 0) {
306 raptor_iostream_counted_string_write((const char*)element->name->nspace->prefix,
307 element->name->nspace->prefix_length,
308 iostr);
309 raptor_iostream_write_byte(':', iostr);
310 }
311 raptor_iostream_counted_string_write((const char*)element->name->local_name,
312 element->name->local_name_length,
313 iostr);
314
315 /* declare namespaces and attributes */
316 if(nspace_declarations_count) {
317 int need_indent = 0;
318
319 /* sort them into the canonical order */
320 qsort((void*)nspace_declarations,
321 nspace_declarations_count, sizeof(struct nsd),
322 raptor_xml_writer_nsd_compare);
323
324 /* declare namespaces first */
325 for(i = 0; i < nspace_declarations_count; i++) {
326 if(!nspace_declarations[i].nspace)
327 continue;
328
329 if(auto_indent && need_indent) {
330 /* indent attributes */
331 raptor_xml_writer_newline(xml_writer);
332 xml_writer->depth++;
333 raptor_xml_writer_indent(xml_writer);
334 xml_writer->depth--;
335 }
336 raptor_iostream_write_byte(' ', iostr);
337 raptor_iostream_counted_string_write((const char*)nspace_declarations[i].declaration,
338 nspace_declarations[i].length,
339 iostr);
340 RAPTOR_FREE(char*, nspace_declarations[i].declaration);
341 nspace_declarations[i].declaration = NULL;
342 need_indent = 1;
343
344 if(raptor_namespace_stack_start_namespace(nstack,
345 (raptor_namespace*)nspace_declarations[i].nspace,
346 depth))
347 goto error;
348 }
349
350 /* declare attributes */
351 for(i = 0; i < nspace_declarations_count; i++) {
352 if(nspace_declarations[i].nspace)
353 continue;
354
355 if(auto_indent && need_indent) {
356 /* indent attributes */
357 raptor_xml_writer_newline(xml_writer);
358 xml_writer->depth++;
359 raptor_xml_writer_indent(xml_writer);
360 xml_writer->depth--;
361 }
362 raptor_iostream_write_byte(' ', iostr);
363 raptor_iostream_counted_string_write((const char*)nspace_declarations[i].declaration,
364 nspace_declarations[i].length,
365 iostr);
366 need_indent = 1;
367
368 RAPTOR_FREE(char*, nspace_declarations[i].declaration);
369 nspace_declarations[i].declaration = NULL;
370 }
371 }
372
373 if(!auto_empty)
374 raptor_iostream_write_byte('>', iostr);
375
376 if(nstack)
377 RAPTOR_FREE(stringarray, nspace_declarations);
378
379 return 0;
380
381 /* Clean up nspace_declarations on error */
382 error:
383
384 for(i = 0; i < nspace_declarations_count; i++) {
385 if(nspace_declarations[i].declaration)
386 RAPTOR_FREE(char*, nspace_declarations[i].declaration);
387 }
388
389 RAPTOR_FREE(stringarray, nspace_declarations);
390
391 return 1;
392 }
393
394
395 static int
raptor_xml_writer_end_element_common(raptor_xml_writer * xml_writer,raptor_xml_element * element,int is_empty)396 raptor_xml_writer_end_element_common(raptor_xml_writer* xml_writer,
397 raptor_xml_element *element,
398 int is_empty)
399 {
400 raptor_iostream* iostr = xml_writer->iostr;
401
402 if(is_empty)
403 raptor_iostream_write_byte('/', iostr);
404 else {
405
406 raptor_iostream_write_byte('<', iostr);
407
408 raptor_iostream_write_byte('/', iostr);
409
410 if(element->name->nspace && element->name->nspace->prefix_length > 0) {
411 raptor_iostream_counted_string_write((const char*)element->name->nspace->prefix,
412 element->name->nspace->prefix_length,
413 iostr);
414 raptor_iostream_write_byte(':', iostr);
415 }
416 raptor_iostream_counted_string_write((const char*)element->name->local_name,
417 element->name->local_name_length,
418 iostr);
419 }
420
421 raptor_iostream_write_byte('>', iostr);
422
423 return 0;
424
425 }
426
427
428 /**
429 * raptor_new_xml_writer:
430 * @world: raptor_world object
431 * @nstack: Namespace stack for the writer to start with (or NULL)
432 * @iostr: I/O stream to write to
433 *
434 * Constructor - Create a new XML Writer writing XML to a raptor_iostream
435 *
436 * Return value: a new #raptor_xml_writer object or NULL on failure
437 **/
438 raptor_xml_writer*
raptor_new_xml_writer(raptor_world * world,raptor_namespace_stack * nstack,raptor_iostream * iostr)439 raptor_new_xml_writer(raptor_world* world,
440 raptor_namespace_stack *nstack,
441 raptor_iostream* iostr)
442 {
443 raptor_xml_writer* xml_writer;
444
445 RAPTOR_CHECK_CONSTRUCTOR_WORLD(world);
446
447 if(!iostr)
448 return NULL;
449
450 raptor_world_open(world);
451
452 xml_writer = RAPTOR_CALLOC(raptor_xml_writer*, 1, sizeof(*xml_writer));
453 if(!xml_writer)
454 return NULL;
455
456 xml_writer->world = world;
457
458 xml_writer->nstack_depth = 0;
459
460 xml_writer->nstack = nstack;
461 if(!xml_writer->nstack) {
462 xml_writer->nstack = raptor_new_namespaces(world, 1);
463 xml_writer->my_nstack = 1;
464 }
465
466 xml_writer->iostr = iostr;
467
468 raptor_object_options_init(&xml_writer->options,
469 RAPTOR_OPTION_AREA_XML_WRITER);
470
471 return xml_writer;
472 }
473
474
475 /**
476 * raptor_free_xml_writer:
477 * @xml_writer: XML writer object
478 *
479 * Destructor - Free XML Writer
480 *
481 **/
482 void
raptor_free_xml_writer(raptor_xml_writer * xml_writer)483 raptor_free_xml_writer(raptor_xml_writer* xml_writer)
484 {
485 if(!xml_writer)
486 return;
487
488 if(xml_writer->nstack && xml_writer->my_nstack)
489 raptor_free_namespaces(xml_writer->nstack);
490
491 raptor_object_options_clear(&xml_writer->options);
492
493 RAPTOR_FREE(raptor_xml_writer, xml_writer);
494 }
495
496
497 static void
raptor_xml_writer_write_xml_declaration(raptor_xml_writer * xml_writer)498 raptor_xml_writer_write_xml_declaration(raptor_xml_writer* xml_writer)
499 {
500 if(!xml_writer->xml_declaration_checked) {
501 /* check that it should be written once only */
502 xml_writer->xml_declaration_checked = 1;
503
504 if(RAPTOR_OPTIONS_GET_NUMERIC(xml_writer,
505 RAPTOR_OPTION_WRITER_XML_DECLARATION)) {
506 raptor_iostream_string_write((const unsigned char*)"<?xml version=\"",
507 xml_writer->iostr);
508 raptor_iostream_counted_string_write((XML_WRITER_XML_VERSION(xml_writer) == 10) ?
509 (const unsigned char*)"1.0" :
510 (const unsigned char*)"1.1",
511 3, xml_writer->iostr);
512 raptor_iostream_string_write((const unsigned char*)"\" encoding=\"utf-8\"?>\n",
513 xml_writer->iostr);
514 }
515 }
516
517 }
518
519
520 /**
521 * raptor_xml_writer_empty_element:
522 * @xml_writer: XML writer object
523 * @element: XML element object
524 *
525 * Write an empty XML element to the XML writer.
526 *
527 * Closes any previous empty element if XML writer option AUTO_EMPTY
528 * is enabled.
529 **/
530 void
raptor_xml_writer_empty_element(raptor_xml_writer * xml_writer,raptor_xml_element * element)531 raptor_xml_writer_empty_element(raptor_xml_writer* xml_writer,
532 raptor_xml_element *element)
533 {
534 raptor_xml_writer_write_xml_declaration(xml_writer);
535
536 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
537
538 if(xml_writer->pending_newline || XML_WRITER_AUTO_INDENT(xml_writer))
539 raptor_xml_writer_indent(xml_writer);
540
541 raptor_xml_writer_start_element_common(xml_writer, element, 1);
542
543 raptor_xml_writer_end_element_common(xml_writer, element, 1);
544
545 raptor_namespaces_end_for_depth(xml_writer->nstack, xml_writer->depth);
546 }
547
548
549 /**
550 * raptor_xml_writer_start_element:
551 * @xml_writer: XML writer object
552 * @element: XML element object
553 *
554 * Write a start XML element to the XML writer.
555 *
556 * Closes any previous empty element if XML writer option AUTO_EMPTY
557 * is enabled.
558 *
559 * Indents the start element if XML writer option AUTO_INDENT is enabled.
560 **/
561 void
raptor_xml_writer_start_element(raptor_xml_writer * xml_writer,raptor_xml_element * element)562 raptor_xml_writer_start_element(raptor_xml_writer* xml_writer,
563 raptor_xml_element *element)
564 {
565 raptor_xml_writer_write_xml_declaration(xml_writer);
566
567 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
568
569 if(xml_writer->pending_newline || XML_WRITER_AUTO_INDENT(xml_writer))
570 raptor_xml_writer_indent(xml_writer);
571
572 raptor_xml_writer_start_element_common(xml_writer, element,
573 XML_WRITER_AUTO_EMPTY(xml_writer));
574
575 xml_writer->depth++;
576
577 /* SJS Note: This "if" clause is necessary because raptor_rdfxml.c
578 * uses xml_writer for parseType="literal" and passes in elements
579 * whose parent field is already set. The first time this function
580 * is called, it sets element->parent to 0, causing the warn-07.rdf
581 * test to fail. Subsequent calls to this function set
582 * element->parent to its existing value.
583 */
584 if(xml_writer->current_element)
585 element->parent = xml_writer->current_element;
586
587 xml_writer->current_element = element;
588 if(element->parent)
589 element->parent->content_element_seen = 1;
590 }
591
592
593 /**
594 * raptor_xml_writer_end_element:
595 * @xml_writer: XML writer object
596 * @element: XML element object
597 *
598 * Write an end XML element to the XML writer.
599 *
600 * Indents the end element if XML writer option AUTO_INDENT is enabled.
601 **/
602 void
raptor_xml_writer_end_element(raptor_xml_writer * xml_writer,raptor_xml_element * element)603 raptor_xml_writer_end_element(raptor_xml_writer* xml_writer,
604 raptor_xml_element* element)
605 {
606 int is_empty;
607
608 xml_writer->depth--;
609
610 if(xml_writer->pending_newline ||
611 (XML_WRITER_AUTO_INDENT(xml_writer) && element->content_element_seen))
612 raptor_xml_writer_indent(xml_writer);
613
614 is_empty = XML_WRITER_AUTO_EMPTY(xml_writer) ?
615 !(element->content_cdata_seen || element->content_element_seen) : 0;
616
617 raptor_xml_writer_end_element_common(xml_writer, element, is_empty);
618
619 raptor_namespaces_end_for_depth(xml_writer->nstack, xml_writer->depth);
620
621 if(xml_writer->current_element)
622 xml_writer->current_element = xml_writer->current_element->parent;
623 }
624
625
626 /**
627 * raptor_xml_writer_newline:
628 * @xml_writer: XML writer object
629 *
630 * Write a newline to the XML writer.
631 *
632 * Indents the next line if XML writer option AUTO_INDENT is enabled.
633 **/
634 void
raptor_xml_writer_newline(raptor_xml_writer * xml_writer)635 raptor_xml_writer_newline(raptor_xml_writer* xml_writer)
636 {
637 xml_writer->pending_newline = 1;
638 }
639
640
641 /**
642 * raptor_xml_writer_cdata:
643 * @xml_writer: XML writer object
644 * @s: string to XML escape and write
645 *
646 * Write CDATA XML-escaped to the XML writer.
647 *
648 * Closes any previous empty element if XML writer option AUTO_EMPTY
649 * is enabled.
650 *
651 **/
652 void
raptor_xml_writer_cdata(raptor_xml_writer * xml_writer,const unsigned char * s)653 raptor_xml_writer_cdata(raptor_xml_writer* xml_writer,
654 const unsigned char *s)
655 {
656 raptor_xml_writer_write_xml_declaration(xml_writer);
657
658 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
659
660 raptor_xml_escape_string_any_write(s, strlen((const char*)s),
661 '\0',
662 XML_WRITER_XML_VERSION(xml_writer),
663 xml_writer->iostr);
664
665 if(xml_writer->current_element)
666 xml_writer->current_element->content_cdata_seen = 1;
667 }
668
669
670 /**
671 * raptor_xml_writer_cdata_counted:
672 * @xml_writer: XML writer object
673 * @s: string to XML escape and write
674 * @len: length of string
675 *
676 * Write counted CDATA XML-escaped to the XML writer.
677 *
678 * Closes any previous empty element if XML writer option AUTO_EMPTY
679 * is enabled.
680 *
681 **/
682 void
raptor_xml_writer_cdata_counted(raptor_xml_writer * xml_writer,const unsigned char * s,unsigned int len)683 raptor_xml_writer_cdata_counted(raptor_xml_writer* xml_writer,
684 const unsigned char *s, unsigned int len)
685 {
686 raptor_xml_writer_write_xml_declaration(xml_writer);
687
688 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
689
690 raptor_xml_escape_string_any_write(s, len,
691 '\0',
692 XML_WRITER_XML_VERSION(xml_writer),
693 xml_writer->iostr);
694
695 if(xml_writer->current_element)
696 xml_writer->current_element->content_cdata_seen = 1;
697 }
698
699
700 /**
701 * raptor_xml_writer_raw:
702 * @xml_writer: XML writer object
703 * @s: string to write
704 *
705 * Write a string raw to the XML writer.
706 *
707 * Closes any previous empty element if XML writer option AUTO_EMPTY
708 * is enabled.
709 *
710 **/
711 void
raptor_xml_writer_raw(raptor_xml_writer * xml_writer,const unsigned char * s)712 raptor_xml_writer_raw(raptor_xml_writer* xml_writer,
713 const unsigned char *s)
714 {
715 raptor_xml_writer_write_xml_declaration(xml_writer);
716
717 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
718
719 raptor_iostream_string_write(s, xml_writer->iostr);
720
721 if(xml_writer->current_element)
722 xml_writer->current_element->content_cdata_seen = 1;
723 }
724
725
726 /**
727 * raptor_xml_writer_raw_counted:
728 * @xml_writer: XML writer object
729 * @s: string to write
730 * @len: length of string
731 *
732 * Write a counted string raw to the XML writer.
733 *
734 * Closes any previous empty element if XML writer option AUTO_EMPTY
735 * is enabled.
736 *
737 **/
738 void
raptor_xml_writer_raw_counted(raptor_xml_writer * xml_writer,const unsigned char * s,unsigned int len)739 raptor_xml_writer_raw_counted(raptor_xml_writer* xml_writer,
740 const unsigned char *s, unsigned int len)
741 {
742 raptor_xml_writer_write_xml_declaration(xml_writer);
743
744 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
745
746 raptor_iostream_counted_string_write(s, len, xml_writer->iostr);
747
748 if(xml_writer->current_element)
749 xml_writer->current_element->content_cdata_seen = 1;
750 }
751
752
753 /**
754 * raptor_xml_writer_comment:
755 * @xml_writer: XML writer object
756 * @s: comment string to write
757 *
758 * Write an XML comment to the XML writer.
759 *
760 * Closes any previous empty element if XML writer option AUTO_EMPTY
761 * is enabled.
762 *
763 **/
764 void
raptor_xml_writer_comment(raptor_xml_writer * xml_writer,const unsigned char * s)765 raptor_xml_writer_comment(raptor_xml_writer* xml_writer,
766 const unsigned char *s)
767 {
768 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
769
770 raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"<!-- ", 5);
771 raptor_xml_writer_cdata(xml_writer, s);
772 raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" -->", 4);
773 }
774
775
776 /**
777 * raptor_xml_writer_comment_counted:
778 * @xml_writer: XML writer object
779 * @s: comment string to write
780 * @len: length of string
781 *
782 * Write a counted XML comment to the XML writer.
783 *
784 * Closes any previous empty element if XML writer option AUTO_EMPTY
785 * is enabled.
786 *
787 **/
788 void
raptor_xml_writer_comment_counted(raptor_xml_writer * xml_writer,const unsigned char * s,unsigned int len)789 raptor_xml_writer_comment_counted(raptor_xml_writer* xml_writer,
790 const unsigned char *s, unsigned int len)
791 {
792 XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer);
793
794 raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"<!-- ", 5);
795 raptor_xml_writer_cdata_counted(xml_writer, s, len);
796 raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" -->", 4);
797 }
798
799
800 /**
801 * raptor_xml_writer_flush:
802 * @xml_writer: XML writer object
803 *
804 * Finish the XML writer.
805 *
806 **/
807 void
raptor_xml_writer_flush(raptor_xml_writer * xml_writer)808 raptor_xml_writer_flush(raptor_xml_writer* xml_writer)
809 {
810 if(xml_writer->pending_newline) {
811 raptor_iostream_write_byte('\n', xml_writer->iostr);
812 xml_writer->pending_newline = 0;
813 }
814 }
815
816
817 /**
818 * raptor_xml_writer_set_option:
819 * @xml_writer: #raptor_xml_writer xml_writer object
820 * @option: option to set from enumerated #raptor_option values
821 * @string: string option value (or NULL)
822 * @integer: integer option value
823 *
824 * Set xml_writer option.
825 *
826 * If @string is not NULL and the option type is numeric, the string
827 * value is converted to an integer and used in preference to @integer.
828 *
829 * If @string is NULL and the option type is not numeric, an error is
830 * returned.
831 *
832 * The @string values used are copied.
833 *
834 * The allowed options are available via
835 * raptor_world_get_option_description().
836 *
837 * Return value: non 0 on failure or if the option is unknown
838 **/
839 int
raptor_xml_writer_set_option(raptor_xml_writer * xml_writer,raptor_option option,char * string,int integer)840 raptor_xml_writer_set_option(raptor_xml_writer *xml_writer,
841 raptor_option option, char* string, int integer)
842 {
843 return raptor_object_options_set_option(&xml_writer->options, option,
844 string, integer);
845 }
846
847
848 /**
849 * raptor_xml_writer_get_option:
850 * @xml_writer: #raptor_xml_writer xml_writer object
851 * @option: option to get value
852 * @string_p: pointer to where to store string value
853 * @integer_p: pointer to where to store integer value
854 *
855 * Get xml_writer option.
856 *
857 * Any string value returned in *@string_p is shared and must
858 * be copied by the caller.
859 *
860 * The allowed options are available via
861 * raptor_world_get_option_description().
862 *
863 * Return value: option value or < 0 for an illegal option
864 **/
865 int
raptor_xml_writer_get_option(raptor_xml_writer * xml_writer,raptor_option option,char ** string_p,int * integer_p)866 raptor_xml_writer_get_option(raptor_xml_writer *xml_writer,
867 raptor_option option,
868 char** string_p, int* integer_p)
869 {
870 return raptor_object_options_get_option(&xml_writer->options, option,
871 string_p, integer_p);
872 }
873
874
875 /**
876 * raptor_xml_writer_get_depth:
877 * @xml_writer: #raptor_xml_writer xml writer object
878 *
879 * Get the current XML Writer element depth
880 *
881 * Return value: element stack depth
882 */
883 int
raptor_xml_writer_get_depth(raptor_xml_writer * xml_writer)884 raptor_xml_writer_get_depth(raptor_xml_writer *xml_writer)
885 {
886 return xml_writer->depth;
887 }
888
889
890 #endif
891
892
893
894 #ifdef STANDALONE
895
896 /* one more prototype */
897 int main(int argc, char *argv[]);
898
899
900 const unsigned char *base_uri_string = (const unsigned char*)"http://example.org/base#";
901
902 #define OUT_BYTES_COUNT 135
903
904 int
main(int argc,char * argv[])905 main(int argc, char *argv[])
906 {
907 raptor_world *world;
908 const char *program = raptor_basename(argv[0]);
909 raptor_iostream *iostr;
910 raptor_namespace_stack *nstack;
911 raptor_namespace* foo_ns;
912 raptor_xml_writer* xml_writer;
913 raptor_uri* base_uri;
914 raptor_qname* el_name;
915 raptor_xml_element *element;
916 unsigned long offset;
917 raptor_qname **attrs;
918 raptor_uri* base_uri_copy = NULL;
919
920 /* for raptor_new_iostream_to_string */
921 void *string = NULL;
922 size_t string_len = 0;
923
924 world = raptor_new_world();
925 if(!world || raptor_world_open(world))
926 exit(1);
927
928 iostr = raptor_new_iostream_to_string(world, &string, &string_len, NULL);
929 if(!iostr) {
930 fprintf(stderr, "%s: Failed to create iostream to string\n", program);
931 exit(1);
932 }
933
934 nstack = raptor_new_namespaces(world, 1);
935
936 xml_writer = raptor_new_xml_writer(world, nstack, iostr);
937 if(!xml_writer) {
938 fprintf(stderr, "%s: Failed to create xml_writer to iostream\n", program);
939 exit(1);
940 }
941
942 base_uri = raptor_new_uri(world, base_uri_string);
943
944 foo_ns = raptor_new_namespace(nstack,
945 (const unsigned char*)"foo",
946 (const unsigned char*)"http://example.org/foo-ns#",
947 0);
948
949
950 el_name = raptor_new_qname_from_namespace_local_name(world,
951 foo_ns,
952 (const unsigned char*)"bar",
953 NULL);
954 base_uri_copy = base_uri ? raptor_uri_copy(base_uri) : NULL;
955 element = raptor_new_xml_element(el_name,
956 NULL, /* language */
957 base_uri_copy);
958
959 raptor_xml_writer_start_element(xml_writer, element);
960 raptor_xml_writer_cdata_counted(xml_writer, (const unsigned char*)"hello\n", 6);
961 raptor_xml_writer_comment_counted(xml_writer, (const unsigned char*)"comment", 7);
962 raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n");
963 raptor_xml_writer_end_element(xml_writer, element);
964
965 raptor_free_xml_element(element);
966
967 raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n");
968
969 el_name = raptor_new_qname(nstack,
970 (const unsigned char*)"blah",
971 NULL /* no attribute value - element */);
972 base_uri_copy = base_uri ? raptor_uri_copy(base_uri) : NULL;
973 element = raptor_new_xml_element(el_name,
974 NULL, /* language */
975 base_uri_copy);
976
977 attrs = RAPTOR_CALLOC(raptor_qname**, 1, sizeof(raptor_qname*));
978 attrs[0] = raptor_new_qname(nstack,
979 (const unsigned char*)"a",
980 (const unsigned char*)"b" /* attribute value */);
981 raptor_xml_element_set_attributes(element, attrs, 1);
982
983 raptor_xml_writer_empty_element(xml_writer, element);
984
985 raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n");
986
987 raptor_free_xml_writer(xml_writer);
988
989 raptor_free_xml_element(element);
990
991 raptor_free_namespace(foo_ns);
992
993 raptor_free_namespaces(nstack);
994
995 raptor_free_uri(base_uri);
996
997
998 offset = raptor_iostream_tell(iostr);
999
1000 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
1001 fprintf(stderr, "%s: Freeing iostream\n", program);
1002 #endif
1003 raptor_free_iostream(iostr);
1004
1005 if(offset != OUT_BYTES_COUNT) {
1006 fprintf(stderr, "%s: I/O stream wrote %d bytes, expected %d\n", program,
1007 (int)offset, (int)OUT_BYTES_COUNT);
1008 fputs("[[", stderr);
1009 (void)fwrite(string, 1, string_len, stderr);
1010 fputs("]]\n", stderr);
1011 return 1;
1012 }
1013
1014 if(!string) {
1015 fprintf(stderr, "%s: I/O stream failed to create a string\n", program);
1016 return 1;
1017 }
1018 string_len = strlen((const char*)string);
1019 if(string_len != offset) {
1020 fprintf(stderr, "%s: I/O stream created a string length %d, expected %d\n", program, (int)string_len, (int)offset);
1021 return 1;
1022 }
1023
1024 #if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
1025 fprintf(stderr, "%s: Made XML string of %d bytes\n", program, (int)string_len);
1026 fputs("[[", stderr);
1027 (void)fwrite(string, 1, string_len, stderr);
1028 fputs("]]\n", stderr);
1029 #endif
1030
1031 raptor_free_memory(string);
1032
1033 raptor_free_world(world);
1034
1035 /* keep gcc -Wall happy */
1036 return(0);
1037 }
1038
1039 #endif
1040