diff options
Diffstat (limited to 'src/raptor_xml_writer.c')
-rw-r--r-- | src/raptor_xml_writer.c | 1046 |
1 files changed, 1046 insertions, 0 deletions
diff --git a/src/raptor_xml_writer.c b/src/raptor_xml_writer.c new file mode 100644 index 0000000..4426d38 --- /dev/null +++ b/src/raptor_xml_writer.c @@ -0,0 +1,1046 @@ +/* -*- Mode: c; c-basic-offset: 2 -*- + * + * raptor_xml_writer.c - Raptor XML Writer for SAX2 events API + * + * Copyright (C) 2003-2010, David Beckett http://www.dajobe.org/ + * Copyright (C) 2003-2005, University of Bristol, UK http://www.bristol.ac.uk/ + * + * This package is Free Software and part of Redland http://librdf.org/ + * + * It is licensed under the following three licenses as alternatives: + * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version + * 2. GNU General Public License (GPL) V2 or any newer version + * 3. Apache License, V2.0 or any newer version + * + * You may not use this file except in compliance with at least one of + * the above three licenses. + * + * See LICENSE.html or LICENSE.txt at the top of this package for the + * complete terms and further detail along with the license texts for + * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively. + * + * + */ + + +#ifdef HAVE_CONFIG_H +#include <raptor_config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdarg.h> +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +/* Raptor includes */ +#include "raptor2.h" +#include "raptor_internal.h" + +#ifndef STANDALONE + + +#define XML_WRITER_AUTO_INDENT(xml_writer) RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, RAPTOR_OPTION_WRITER_AUTO_INDENT) +#define XML_WRITER_AUTO_EMPTY(xml_writer) RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, RAPTOR_OPTION_WRITER_AUTO_EMPTY) +#define XML_WRITER_INDENT(xml_writer) RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, RAPTOR_OPTION_WRITER_INDENT_WIDTH) +#define XML_WRITER_XML_VERSION(xml_writer) RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, RAPTOR_OPTION_WRITER_XML_VERSION) + + +#define XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer) \ + if((XML_WRITER_AUTO_EMPTY(xml_writer)) && \ + xml_writer->current_element && \ + !(xml_writer->current_element->content_cdata_seen || \ + xml_writer->current_element->content_element_seen)) { \ + raptor_iostream_write_byte('>', xml_writer->iostr); \ +} + + +/* Define this for far too much output */ +#undef RAPTOR_DEBUG_CDATA + + +struct raptor_xml_writer_s { + raptor_world *world; + + int canonicalize; + + int depth; + + int my_nstack; + raptor_namespace_stack *nstack; + int nstack_depth; + + raptor_xml_element* current_element; + + /* outputting to this iostream */ + raptor_iostream *iostr; + + /* Has writing the XML declaration writing been checked? */ + int xml_declaration_checked; + + /* An extra newline is wanted */ + int pending_newline; + + /* Options (per-object) */ + raptor_object_options options; +}; + + +/* 16 spaces */ +#define SPACES_BUFFER_SIZE sizeof(spaces_buffer) +static const unsigned char spaces_buffer[] = { + ' ', ' ', ' ', ' ', + ' ', ' ', ' ', ' ', + ' ', ' ', ' ', ' ', + ' ', ' ', ' ', ' ' +}; + + + +/* helper functions */ + +/* Handle printing a pending newline OR newline with indenting */ +static int +raptor_xml_writer_indent(raptor_xml_writer *xml_writer) +{ + int num_spaces; + + if(!XML_WRITER_AUTO_INDENT(xml_writer)) { + if(xml_writer->pending_newline) { + raptor_iostream_write_byte('\n', xml_writer->iostr); + xml_writer->pending_newline = 0; + + if(xml_writer->current_element) + xml_writer->current_element->content_cdata_seen = 1; + } + return 0; + } + + num_spaces = xml_writer->depth * XML_WRITER_INDENT(xml_writer); + + /* Do not write an extra newline at the start of the document + * (after the XML declaration or XMP processing instruction has + * been writtten) + */ + if(xml_writer->xml_declaration_checked == 1) + xml_writer->xml_declaration_checked++; + else { + raptor_iostream_write_byte('\n', xml_writer->iostr); + xml_writer->pending_newline = 0; + } + + while(num_spaces > 0) { + + int count = (num_spaces > RAPTOR_GOOD_CAST(int, SPACES_BUFFER_SIZE)) ? + RAPTOR_GOOD_CAST(int, SPACES_BUFFER_SIZE) : num_spaces; + + raptor_iostream_counted_string_write(spaces_buffer, count, + xml_writer->iostr); + + num_spaces -= count; + } + + if(xml_writer->current_element) + xml_writer->current_element->content_cdata_seen = 1; + + return 0; +} + + +struct nsd { + const raptor_namespace *nspace; + unsigned char *declaration; + size_t length; +}; + + +static int +raptor_xml_writer_nsd_compare(const void *a, const void *b) +{ + struct nsd* nsd_a = (struct nsd*)a; + struct nsd* nsd_b = (struct nsd*)b; + + /* Sort NULLs earlier */ + if(!nsd_a->declaration) + return -1; + else if(!nsd_b->declaration) + return 1; + return strcmp((const char*)nsd_a->declaration, (const char*)nsd_b->declaration); +} + + +static int +raptor_xml_writer_start_element_common(raptor_xml_writer* xml_writer, + raptor_xml_element* element, + int auto_empty) +{ + raptor_iostream* iostr = xml_writer->iostr; + raptor_namespace_stack *nstack = xml_writer->nstack; + int depth = xml_writer->depth; + int auto_indent = XML_WRITER_AUTO_INDENT(xml_writer); + struct nsd *nspace_declarations = NULL; + size_t nspace_declarations_count = 0; + unsigned int i; + + if(nstack) { + int nspace_max_count = element->attribute_count * 2; /* attr and value */ + if(element->name->nspace) + nspace_max_count++; + if(element->declared_nspaces) + nspace_max_count += raptor_sequence_size(element->declared_nspaces); + if(element->xml_language) + nspace_max_count++; + + nspace_declarations = RAPTOR_CALLOC(struct nsd*, nspace_max_count, + sizeof(struct nsd)); + if(!nspace_declarations) + return 1; + } + + if(element->name->nspace) { + if(nstack && !raptor_namespaces_namespace_in_scope(nstack, element->name->nspace)) { + nspace_declarations[0].declaration= + raptor_namespace_format_as_xml(element->name->nspace, + &nspace_declarations[0].length); + if(!nspace_declarations[0].declaration) + goto error; + nspace_declarations[0].nspace = element->name->nspace; + nspace_declarations_count++; + } + } + + if(nstack && element->attributes) { + for(i = 0; i < element->attribute_count; i++) { + /* qname */ + if(element->attributes[i]->nspace) { + /* Check if we need a namespace declaration attribute */ + if(nstack && + !raptor_namespaces_namespace_in_scope(nstack, element->attributes[i]->nspace) && element->attributes[i]->nspace != element->name->nspace) { + /* not in scope and not same as element (so already going to be declared)*/ + unsigned int j; + int declare_me = 1; + + /* check it wasn't an earlier declaration too */ + for(j = 0; j < nspace_declarations_count; j++) + if(nspace_declarations[j].nspace == element->attributes[i]->nspace) { + declare_me = 0; + break; + } + + if(declare_me) { + nspace_declarations[nspace_declarations_count].declaration= + raptor_namespace_format_as_xml(element->attributes[i]->nspace, + &nspace_declarations[nspace_declarations_count].length); + if(!nspace_declarations[nspace_declarations_count].declaration) + goto error; + nspace_declarations[nspace_declarations_count].nspace = element->attributes[i]->nspace; + nspace_declarations_count++; + } + } + } + + /* Add the attribute's value */ + nspace_declarations[nspace_declarations_count].declaration= + raptor_qname_format_as_xml(element->attributes[i], + &nspace_declarations[nspace_declarations_count].length); + if(!nspace_declarations[nspace_declarations_count].declaration) + goto error; + nspace_declarations[nspace_declarations_count].nspace = NULL; + nspace_declarations_count++; + + } + } + + if(nstack && element->declared_nspaces && + raptor_sequence_size(element->declared_nspaces) > 0) { + for(i = 0; i< (unsigned int)raptor_sequence_size(element->declared_nspaces); i++) { + raptor_namespace* nspace = (raptor_namespace*)raptor_sequence_get_at(element->declared_nspaces, i); + unsigned int j; + int declare_me = 1; + + /* check it wasn't an earlier declaration too */ + for(j = 0; j < nspace_declarations_count; j++) + if(nspace_declarations[j].nspace == nspace) { + declare_me = 0; + break; + } + + if(declare_me) { + nspace_declarations[nspace_declarations_count].declaration= + raptor_namespace_format_as_xml(nspace, + &nspace_declarations[nspace_declarations_count].length); + if(!nspace_declarations[nspace_declarations_count].declaration) + goto error; + nspace_declarations[nspace_declarations_count].nspace = nspace; + nspace_declarations_count++; + } + + } + } + + if(nstack && element->xml_language) { + size_t lang_len = strlen(RAPTOR_GOOD_CAST(char*, element->xml_language)); +#define XML_LANG_PREFIX "xml:lang=\"" +#define XML_LANG_PREFIX_LEN 10 + size_t buf_length = XML_LANG_PREFIX_LEN + lang_len + 1; + unsigned char* buffer = RAPTOR_MALLOC(unsigned char*, buf_length + 1); + const char quote = '\"'; + unsigned char* p; + + memcpy(buffer, XML_LANG_PREFIX, XML_LANG_PREFIX_LEN); + p = buffer + XML_LANG_PREFIX_LEN; + p += raptor_xml_escape_string(xml_writer->world, + element->xml_language, lang_len, + p, buf_length, quote); + *p++ = quote; + *p = '\0'; + + nspace_declarations[nspace_declarations_count].declaration = buffer; + nspace_declarations[nspace_declarations_count].length = buf_length; + nspace_declarations[nspace_declarations_count].nspace = NULL; + nspace_declarations_count++; + } + + + raptor_iostream_write_byte('<', iostr); + + if(element->name->nspace && element->name->nspace->prefix_length > 0) { + raptor_iostream_counted_string_write((const char*)element->name->nspace->prefix, + element->name->nspace->prefix_length, + iostr); + raptor_iostream_write_byte(':', iostr); + } + raptor_iostream_counted_string_write((const char*)element->name->local_name, + element->name->local_name_length, + iostr); + + /* declare namespaces and attributes */ + if(nspace_declarations_count) { + int need_indent = 0; + + /* sort them into the canonical order */ + qsort((void*)nspace_declarations, + nspace_declarations_count, sizeof(struct nsd), + raptor_xml_writer_nsd_compare); + + /* declare namespaces first */ + for(i = 0; i < nspace_declarations_count; i++) { + if(!nspace_declarations[i].nspace) + continue; + + if(auto_indent && need_indent) { + /* indent attributes */ + raptor_xml_writer_newline(xml_writer); + xml_writer->depth++; + raptor_xml_writer_indent(xml_writer); + xml_writer->depth--; + } + raptor_iostream_write_byte(' ', iostr); + raptor_iostream_counted_string_write((const char*)nspace_declarations[i].declaration, + nspace_declarations[i].length, + iostr); + RAPTOR_FREE(char*, nspace_declarations[i].declaration); + nspace_declarations[i].declaration = NULL; + need_indent = 1; + + if(raptor_namespace_stack_start_namespace(nstack, + (raptor_namespace*)nspace_declarations[i].nspace, + depth)) + goto error; + } + + /* declare attributes */ + for(i = 0; i < nspace_declarations_count; i++) { + if(nspace_declarations[i].nspace) + continue; + + if(auto_indent && need_indent) { + /* indent attributes */ + raptor_xml_writer_newline(xml_writer); + xml_writer->depth++; + raptor_xml_writer_indent(xml_writer); + xml_writer->depth--; + } + raptor_iostream_write_byte(' ', iostr); + raptor_iostream_counted_string_write((const char*)nspace_declarations[i].declaration, + nspace_declarations[i].length, + iostr); + need_indent = 1; + + RAPTOR_FREE(char*, nspace_declarations[i].declaration); + nspace_declarations[i].declaration = NULL; + } + } + + if(!auto_empty) + raptor_iostream_write_byte('>', iostr); + + if(nstack) + RAPTOR_FREE(stringarray, nspace_declarations); + + return 0; + + /* Clean up nspace_declarations on error */ + error: + + for(i = 0; i < nspace_declarations_count; i++) { + if(nspace_declarations[i].declaration) + RAPTOR_FREE(char*, nspace_declarations[i].declaration); + } + + RAPTOR_FREE(stringarray, nspace_declarations); + + return 1; +} + + +static int +raptor_xml_writer_end_element_common(raptor_xml_writer* xml_writer, + raptor_xml_element *element, + int is_empty) +{ + raptor_iostream* iostr = xml_writer->iostr; + + if(is_empty) + raptor_iostream_write_byte('/', iostr); + else { + + raptor_iostream_write_byte('<', iostr); + + raptor_iostream_write_byte('/', iostr); + + if(element->name->nspace && element->name->nspace->prefix_length > 0) { + raptor_iostream_counted_string_write((const char*)element->name->nspace->prefix, + element->name->nspace->prefix_length, + iostr); + raptor_iostream_write_byte(':', iostr); + } + raptor_iostream_counted_string_write((const char*)element->name->local_name, + element->name->local_name_length, + iostr); + } + + raptor_iostream_write_byte('>', iostr); + + return 0; + +} + + +/** + * raptor_new_xml_writer: + * @world: raptor_world object + * @nstack: Namespace stack for the writer to start with (or NULL) + * @iostr: I/O stream to write to + * + * Constructor - Create a new XML Writer writing XML to a raptor_iostream + * + * Return value: a new #raptor_xml_writer object or NULL on failure + **/ +raptor_xml_writer* +raptor_new_xml_writer(raptor_world* world, + raptor_namespace_stack *nstack, + raptor_iostream* iostr) +{ + raptor_xml_writer* xml_writer; + + RAPTOR_CHECK_CONSTRUCTOR_WORLD(world); + + if(!iostr) + return NULL; + + raptor_world_open(world); + + xml_writer = RAPTOR_CALLOC(raptor_xml_writer*, 1, sizeof(*xml_writer)); + if(!xml_writer) + return NULL; + + xml_writer->world = world; + + xml_writer->nstack_depth = 0; + + xml_writer->nstack = nstack; + if(!xml_writer->nstack) { + xml_writer->nstack = raptor_new_namespaces(world, 1); + xml_writer->my_nstack = 1; + } + + xml_writer->iostr = iostr; + + raptor_object_options_init(&xml_writer->options, + RAPTOR_OPTION_AREA_XML_WRITER); + + return xml_writer; +} + + +/** + * raptor_free_xml_writer: + * @xml_writer: XML writer object + * + * Destructor - Free XML Writer + * + **/ +void +raptor_free_xml_writer(raptor_xml_writer* xml_writer) +{ + if(!xml_writer) + return; + + if(xml_writer->nstack && xml_writer->my_nstack) + raptor_free_namespaces(xml_writer->nstack); + + raptor_object_options_clear(&xml_writer->options); + + RAPTOR_FREE(raptor_xml_writer, xml_writer); +} + + +static void +raptor_xml_writer_write_xml_declaration(raptor_xml_writer* xml_writer) +{ + if(!xml_writer->xml_declaration_checked) { + /* check that it should be written once only */ + xml_writer->xml_declaration_checked = 1; + + if(RAPTOR_OPTIONS_GET_NUMERIC(xml_writer, + RAPTOR_OPTION_WRITER_XML_DECLARATION)) { + raptor_iostream_string_write((const unsigned char*)"<?xml version=\"", + xml_writer->iostr); + raptor_iostream_counted_string_write((XML_WRITER_XML_VERSION(xml_writer) == 10) ? + (const unsigned char*)"1.0" : + (const unsigned char*)"1.1", + 3, xml_writer->iostr); + raptor_iostream_string_write((const unsigned char*)"\" encoding=\"utf-8\"?>\n", + xml_writer->iostr); + } + } + +} + + +/** + * raptor_xml_writer_empty_element: + * @xml_writer: XML writer object + * @element: XML element object + * + * Write an empty XML element to the XML writer. + * + * Closes any previous empty element if XML writer option AUTO_EMPTY + * is enabled. + **/ +void +raptor_xml_writer_empty_element(raptor_xml_writer* xml_writer, + raptor_xml_element *element) +{ + raptor_xml_writer_write_xml_declaration(xml_writer); + + XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer); + + if(xml_writer->pending_newline || XML_WRITER_AUTO_INDENT(xml_writer)) + raptor_xml_writer_indent(xml_writer); + + raptor_xml_writer_start_element_common(xml_writer, element, 1); + + raptor_xml_writer_end_element_common(xml_writer, element, 1); + + raptor_namespaces_end_for_depth(xml_writer->nstack, xml_writer->depth); +} + + +/** + * raptor_xml_writer_start_element: + * @xml_writer: XML writer object + * @element: XML element object + * + * Write a start XML element to the XML writer. + * + * Closes any previous empty element if XML writer option AUTO_EMPTY + * is enabled. + * + * Indents the start element if XML writer option AUTO_INDENT is enabled. + **/ +void +raptor_xml_writer_start_element(raptor_xml_writer* xml_writer, + raptor_xml_element *element) +{ + raptor_xml_writer_write_xml_declaration(xml_writer); + + XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer); + + if(xml_writer->pending_newline || XML_WRITER_AUTO_INDENT(xml_writer)) + raptor_xml_writer_indent(xml_writer); + + raptor_xml_writer_start_element_common(xml_writer, element, + XML_WRITER_AUTO_EMPTY(xml_writer)); + + xml_writer->depth++; + + /* SJS Note: This "if" clause is necessary because raptor_rdfxml.c + * uses xml_writer for parseType="literal" and passes in elements + * whose parent field is already set. The first time this function + * is called, it sets element->parent to 0, causing the warn-07.rdf + * test to fail. Subsequent calls to this function set + * element->parent to its existing value. + */ + if(xml_writer->current_element) + element->parent = xml_writer->current_element; + + xml_writer->current_element = element; + if(element->parent) + element->parent->content_element_seen = 1; +} + + +/** + * raptor_xml_writer_end_element: + * @xml_writer: XML writer object + * @element: XML element object + * + * Write an end XML element to the XML writer. + * + * Indents the end element if XML writer option AUTO_INDENT is enabled. + **/ +void +raptor_xml_writer_end_element(raptor_xml_writer* xml_writer, + raptor_xml_element* element) +{ + int is_empty; + + xml_writer->depth--; + + if(xml_writer->pending_newline || + (XML_WRITER_AUTO_INDENT(xml_writer) && element->content_element_seen)) + raptor_xml_writer_indent(xml_writer); + + is_empty = XML_WRITER_AUTO_EMPTY(xml_writer) ? + !(element->content_cdata_seen || element->content_element_seen) : 0; + + raptor_xml_writer_end_element_common(xml_writer, element, is_empty); + + raptor_namespaces_end_for_depth(xml_writer->nstack, xml_writer->depth); + + if(xml_writer->current_element) + xml_writer->current_element = xml_writer->current_element->parent; +} + + +/** + * raptor_xml_writer_newline: + * @xml_writer: XML writer object + * + * Write a newline to the XML writer. + * + * Indents the next line if XML writer option AUTO_INDENT is enabled. + **/ +void +raptor_xml_writer_newline(raptor_xml_writer* xml_writer) +{ + xml_writer->pending_newline = 1; +} + + +/** + * raptor_xml_writer_cdata: + * @xml_writer: XML writer object + * @s: string to XML escape and write + * + * Write CDATA XML-escaped to the XML writer. + * + * Closes any previous empty element if XML writer option AUTO_EMPTY + * is enabled. + * + **/ +void +raptor_xml_writer_cdata(raptor_xml_writer* xml_writer, + const unsigned char *s) +{ + raptor_xml_writer_write_xml_declaration(xml_writer); + + XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer); + + raptor_xml_escape_string_any_write(s, strlen((const char*)s), + '\0', + XML_WRITER_XML_VERSION(xml_writer), + xml_writer->iostr); + + if(xml_writer->current_element) + xml_writer->current_element->content_cdata_seen = 1; +} + + +/** + * raptor_xml_writer_cdata_counted: + * @xml_writer: XML writer object + * @s: string to XML escape and write + * @len: length of string + * + * Write counted CDATA XML-escaped to the XML writer. + * + * Closes any previous empty element if XML writer option AUTO_EMPTY + * is enabled. + * + **/ +void +raptor_xml_writer_cdata_counted(raptor_xml_writer* xml_writer, + const unsigned char *s, unsigned int len) +{ + raptor_xml_writer_write_xml_declaration(xml_writer); + + XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer); + + raptor_xml_escape_string_any_write(s, len, + '\0', + XML_WRITER_XML_VERSION(xml_writer), + xml_writer->iostr); + + if(xml_writer->current_element) + xml_writer->current_element->content_cdata_seen = 1; +} + + +/** + * raptor_xml_writer_raw: + * @xml_writer: XML writer object + * @s: string to write + * + * Write a string raw to the XML writer. + * + * Closes any previous empty element if XML writer option AUTO_EMPTY + * is enabled. + * + **/ +void +raptor_xml_writer_raw(raptor_xml_writer* xml_writer, + const unsigned char *s) +{ + raptor_xml_writer_write_xml_declaration(xml_writer); + + XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer); + + raptor_iostream_string_write(s, xml_writer->iostr); + + if(xml_writer->current_element) + xml_writer->current_element->content_cdata_seen = 1; +} + + +/** + * raptor_xml_writer_raw_counted: + * @xml_writer: XML writer object + * @s: string to write + * @len: length of string + * + * Write a counted string raw to the XML writer. + * + * Closes any previous empty element if XML writer option AUTO_EMPTY + * is enabled. + * + **/ +void +raptor_xml_writer_raw_counted(raptor_xml_writer* xml_writer, + const unsigned char *s, unsigned int len) +{ + raptor_xml_writer_write_xml_declaration(xml_writer); + + XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer); + + raptor_iostream_counted_string_write(s, len, xml_writer->iostr); + + if(xml_writer->current_element) + xml_writer->current_element->content_cdata_seen = 1; +} + + +/** + * raptor_xml_writer_comment: + * @xml_writer: XML writer object + * @s: comment string to write + * + * Write an XML comment to the XML writer. + * + * Closes any previous empty element if XML writer option AUTO_EMPTY + * is enabled. + * + **/ +void +raptor_xml_writer_comment(raptor_xml_writer* xml_writer, + const unsigned char *s) +{ + XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer); + + raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"<!-- ", 5); + raptor_xml_writer_cdata(xml_writer, s); + raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" -->", 4); +} + + +/** + * raptor_xml_writer_comment_counted: + * @xml_writer: XML writer object + * @s: comment string to write + * @len: length of string + * + * Write a counted XML comment to the XML writer. + * + * Closes any previous empty element if XML writer option AUTO_EMPTY + * is enabled. + * + **/ +void +raptor_xml_writer_comment_counted(raptor_xml_writer* xml_writer, + const unsigned char *s, unsigned int len) +{ + XML_WRITER_FLUSH_CLOSE_BRACKET(xml_writer); + + raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)"<!-- ", 5); + raptor_xml_writer_cdata_counted(xml_writer, s, len); + raptor_xml_writer_raw_counted(xml_writer, (const unsigned char*)" -->", 4); +} + + +/** + * raptor_xml_writer_flush: + * @xml_writer: XML writer object + * + * Finish the XML writer. + * + **/ +void +raptor_xml_writer_flush(raptor_xml_writer* xml_writer) +{ + if(xml_writer->pending_newline) { + raptor_iostream_write_byte('\n', xml_writer->iostr); + xml_writer->pending_newline = 0; + } +} + + +/** + * raptor_xml_writer_set_option: + * @xml_writer: #raptor_xml_writer xml_writer object + * @option: option to set from enumerated #raptor_option values + * @string: string option value (or NULL) + * @integer: integer option value + * + * Set xml_writer option. + * + * If @string is not NULL and the option type is numeric, the string + * value is converted to an integer and used in preference to @integer. + * + * If @string is NULL and the option type is not numeric, an error is + * returned. + * + * The @string values used are copied. + * + * The allowed options are available via + * raptor_world_get_option_description(). + * + * Return value: non 0 on failure or if the option is unknown + **/ +int +raptor_xml_writer_set_option(raptor_xml_writer *xml_writer, + raptor_option option, char* string, int integer) +{ + return raptor_object_options_set_option(&xml_writer->options, option, + string, integer); +} + + +/** + * raptor_xml_writer_get_option: + * @xml_writer: #raptor_xml_writer xml_writer object + * @option: option to get value + * @string_p: pointer to where to store string value + * @integer_p: pointer to where to store integer value + * + * Get xml_writer option. + * + * Any string value returned in *@string_p is shared and must + * be copied by the caller. + * + * The allowed options are available via + * raptor_world_get_option_description(). + * + * Return value: option value or < 0 for an illegal option + **/ +int +raptor_xml_writer_get_option(raptor_xml_writer *xml_writer, + raptor_option option, + char** string_p, int* integer_p) +{ + return raptor_object_options_get_option(&xml_writer->options, option, + string_p, integer_p); +} + + +/** + * raptor_xml_writer_get_depth: + * @xml_writer: #raptor_xml_writer xml writer object + * + * Get the current XML Writer element depth + * + * Return value: element stack depth + */ +int +raptor_xml_writer_get_depth(raptor_xml_writer *xml_writer) +{ + return xml_writer->depth; +} + + +#endif + + + +#ifdef STANDALONE + +/* one more prototype */ +int main(int argc, char *argv[]); + + +const unsigned char *base_uri_string = (const unsigned char*)"http://example.org/base#"; + +#define OUT_BYTES_COUNT 135 + +int +main(int argc, char *argv[]) +{ + raptor_world *world; + const char *program = raptor_basename(argv[0]); + raptor_iostream *iostr; + raptor_namespace_stack *nstack; + raptor_namespace* foo_ns; + raptor_xml_writer* xml_writer; + raptor_uri* base_uri; + raptor_qname* el_name; + raptor_xml_element *element; + unsigned long offset; + raptor_qname **attrs; + raptor_uri* base_uri_copy = NULL; + + /* for raptor_new_iostream_to_string */ + void *string = NULL; + size_t string_len = 0; + + world = raptor_new_world(); + if(!world || raptor_world_open(world)) + exit(1); + + iostr = raptor_new_iostream_to_string(world, &string, &string_len, NULL); + if(!iostr) { + fprintf(stderr, "%s: Failed to create iostream to string\n", program); + exit(1); + } + + nstack = raptor_new_namespaces(world, 1); + + xml_writer = raptor_new_xml_writer(world, nstack, iostr); + if(!xml_writer) { + fprintf(stderr, "%s: Failed to create xml_writer to iostream\n", program); + exit(1); + } + + base_uri = raptor_new_uri(world, base_uri_string); + + foo_ns = raptor_new_namespace(nstack, + (const unsigned char*)"foo", + (const unsigned char*)"http://example.org/foo-ns#", + 0); + + + el_name = raptor_new_qname_from_namespace_local_name(world, + foo_ns, + (const unsigned char*)"bar", + NULL); + base_uri_copy = base_uri ? raptor_uri_copy(base_uri) : NULL; + element = raptor_new_xml_element(el_name, + NULL, /* language */ + base_uri_copy); + + raptor_xml_writer_start_element(xml_writer, element); + raptor_xml_writer_cdata_counted(xml_writer, (const unsigned char*)"hello\n", 6); + raptor_xml_writer_comment_counted(xml_writer, (const unsigned char*)"comment", 7); + raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n"); + raptor_xml_writer_end_element(xml_writer, element); + + raptor_free_xml_element(element); + + raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n"); + + el_name = raptor_new_qname(nstack, + (const unsigned char*)"blah", + NULL /* no attribute value - element */); + base_uri_copy = base_uri ? raptor_uri_copy(base_uri) : NULL; + element = raptor_new_xml_element(el_name, + NULL, /* language */ + base_uri_copy); + + attrs = RAPTOR_CALLOC(raptor_qname**, 1, sizeof(raptor_qname*)); + attrs[0] = raptor_new_qname(nstack, + (const unsigned char*)"a", + (const unsigned char*)"b" /* attribute value */); + raptor_xml_element_set_attributes(element, attrs, 1); + + raptor_xml_writer_empty_element(xml_writer, element); + + raptor_xml_writer_cdata(xml_writer, (const unsigned char*)"\n"); + + raptor_free_xml_writer(xml_writer); + + raptor_free_xml_element(element); + + raptor_free_namespace(foo_ns); + + raptor_free_namespaces(nstack); + + raptor_free_uri(base_uri); + + + offset = raptor_iostream_tell(iostr); + +#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1 + fprintf(stderr, "%s: Freeing iostream\n", program); +#endif + raptor_free_iostream(iostr); + + if(offset != OUT_BYTES_COUNT) { + fprintf(stderr, "%s: I/O stream wrote %d bytes, expected %d\n", program, + (int)offset, (int)OUT_BYTES_COUNT); + fputs("[[", stderr); + (void)fwrite(string, 1, string_len, stderr); + fputs("]]\n", stderr); + return 1; + } + + if(!string) { + fprintf(stderr, "%s: I/O stream failed to create a string\n", program); + return 1; + } + string_len = strlen((const char*)string); + if(string_len != offset) { + fprintf(stderr, "%s: I/O stream created a string length %d, expected %d\n", program, (int)string_len, (int)offset); + return 1; + } + +#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1 + fprintf(stderr, "%s: Made XML string of %d bytes\n", program, (int)string_len); + fputs("[[", stderr); + (void)fwrite(string, 1, string_len, stderr); + fputs("]]\n", stderr); +#endif + + raptor_free_memory(string); + + raptor_free_world(world); + + /* keep gcc -Wall happy */ + return(0); +} + +#endif |