diff options
Diffstat (limited to '')
-rw-r--r-- | src/raptor_qname.c | 695 |
1 files changed, 695 insertions, 0 deletions
diff --git a/src/raptor_qname.c b/src/raptor_qname.c new file mode 100644 index 0000000..3995f8f --- /dev/null +++ b/src/raptor_qname.c @@ -0,0 +1,695 @@ +/* -*- Mode: c; c-basic-offset: 2 -*- + * + * raptor_qname.c - Raptor XML qname class + * + * Copyright (C) 2002-2008, David Beckett http://www.dajobe.org/ + * Copyright (C) 2002-2004, 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" + + +/* + * Namespaces in XML + * http://www.w3.org/TR/1999/REC-xml-names-19990114/#defaulting + * says: + * + * -------------------------------------------------------------------- + * 5.2 Namespace Defaulting + * + * A default namespace is considered to apply to the element where it + * is declared (if that element has no namespace prefix), and to all + * elements with no prefix within the content of that element. + * + * If the URI reference in a default namespace declaration is empty, + * then unprefixed elements in the scope of the declaration are not + * considered to be in any namespace. + * + * Note that default namespaces do not apply directly to attributes. + * + * [...] + * + * 5.3 Uniqueness of Attributes + * + * In XML documents conforming to this specification, no tag may + * contain two attributes which: + * + * 1. have identical names, or + * + * 2. have qualified names with the same local part and with + * prefixes which have been bound to namespace names that are + * identical. + * -------------------------------------------------------------------- + */ + +/** + * raptor_new_qname: + * @nstack: namespace stack to look up for namespaces + * @name: element or attribute name + * @value: attribute value (else is an element) + * + * Constructor - create a new XML qname. + * + * Create a new qname from the local element/attribute name, + * with optional (attribute) value. The namespace stack is used + * to look up the name and find the namespace and generate the + * URI of the qname. + * + * Return value: a new #raptor_qname object or NULL on failure + **/ +raptor_qname* +raptor_new_qname(raptor_namespace_stack *nstack, + const unsigned char *name, + const unsigned char *value) +{ + raptor_qname* qname; + const unsigned char *p; + raptor_namespace* ns; + unsigned char* new_name; + unsigned int prefix_length; + unsigned int local_name_length = 0; + +#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1 + RAPTOR_DEBUG2("name %s\n", name); +#endif + + qname = RAPTOR_CALLOC(raptor_qname*, 1, sizeof(*qname)); + if(!qname) + return NULL; + qname->world = nstack->world; + + if(value) { + size_t value_length = strlen((char*)value); + unsigned char* new_value; + + new_value = RAPTOR_MALLOC(unsigned char*, value_length + 1); + if(!new_value) { + RAPTOR_FREE(raptor_qname, qname); + return NULL; + } + + memcpy(new_value, value, value_length + 1); /* copy NUL */ + qname->value = new_value; + qname->value_length = value_length; + } + + + /* Find : */ + for(p = name; *p && *p != ':'; p++) + ; + + + if(!*p) { + local_name_length = (unsigned int)(p - name); + + /* No : in the name */ + new_name = RAPTOR_MALLOC(unsigned char*, local_name_length + 1); + if(!new_name) { + raptor_free_qname(qname); + return NULL; + } + memcpy(new_name, name, local_name_length); /* no NUL to copy */ + new_name[local_name_length] = '\0'; + qname->local_name = new_name; + qname->local_name_length = local_name_length; + + /* For elements only, pick up the default namespace if there is one */ + if(!value) { + ns = raptor_namespaces_get_default_namespace(nstack); + + if(ns) { + qname->nspace = ns; +#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1 + RAPTOR_DEBUG2("Found default namespace with URI %s\n", ns->uri ? raptor_uri_as_string(ns->uri) : (unsigned char*)"None"); +#endif + } else { +#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1 + RAPTOR_DEBUG1("No default namespace defined\n"); +#endif + } + } /* if is_element */ + + } else { + /* There is a namespace prefix */ + + prefix_length = (unsigned int)(p - name); + p++; + + /* p now is at start of local_name */ + local_name_length = (unsigned int)strlen((char*)p); + new_name = RAPTOR_MALLOC(unsigned char*, local_name_length + 1); + if(!new_name) { + raptor_free_qname(qname); + return NULL; + } + memcpy(new_name, p, local_name_length); /* No NUL to copy */ + new_name[local_name_length] = '\0'; + qname->local_name = new_name; + qname->local_name_length = local_name_length; + + /* Find the namespace */ + ns = raptor_namespaces_find_namespace(nstack, name, prefix_length); + + if(!ns) { + /* failed to find namespace - now what? */ + raptor_log_error_formatted(qname->world, RAPTOR_LOG_LEVEL_ERROR, NULL, + "The namespace prefix in \"%s\" was not declared.", name); + } else { +#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1 + RAPTOR_DEBUG3("Found namespace prefix %s URI %s\n", ns->prefix, ns->uri ? raptor_uri_as_string(ns->uri) : (unsigned char*)"None"); +#endif + qname->nspace = ns; + } + } + + + + /* If namespace has a URI and a local_name is defined, create the URI + * for this element + */ + if(qname->nspace && local_name_length) { + raptor_uri *uri = raptor_namespace_get_uri(qname->nspace); + if(uri) + uri = raptor_new_uri_from_uri_local_name(qname->world, uri, new_name); + + qname->uri = uri; + } + + + return qname; +} + + +/** + * raptor_new_qname_from_namespace_local_name: + * @world: raptor_world object + * @ns: namespace of qname (or NULL) + * @local_name: element or attribute name + * @value: attribute value (else is an element) + * + * Constructor - create a new XML qname. + * + * Create a new qname from the namespace and local element/attribute name, + * with optional (attribute) value. + * + * Return value: a new #raptor_qname object or NULL on failure + **/ +raptor_qname* +raptor_new_qname_from_namespace_local_name(raptor_world* world, + raptor_namespace *ns, + const unsigned char *local_name, + const unsigned char *value) +{ + raptor_qname* qname; + unsigned char* new_name; + unsigned int local_name_length; + + RAPTOR_CHECK_CONSTRUCTOR_WORLD(world); + + if(!local_name) + return NULL; + + local_name_length = (unsigned int)strlen((char*)local_name); + + raptor_world_open(world); + + qname = RAPTOR_CALLOC(raptor_qname*, 1, sizeof(*qname)); + if(!qname) + return NULL; + qname->world = world; + + if(value) { + unsigned int value_length = (unsigned int)strlen((char*)value); + unsigned char* new_value; + + new_value = RAPTOR_MALLOC(unsigned char*, value_length + 1); + if(!new_value) { + RAPTOR_FREE(raptor_qname, qname); + return NULL; + } + + memcpy(new_value, value, value_length + 1); /* Copy NUL */ + qname->value = new_value; + qname->value_length = value_length; + } + + new_name = RAPTOR_MALLOC(unsigned char*, local_name_length + 1); + if(!new_name) { + raptor_free_qname(qname); + return NULL; + } + + memcpy(new_name, local_name, local_name_length); /* No NUL to copy */ + new_name[local_name_length] = '\0'; + qname->local_name = new_name; + qname->local_name_length = local_name_length; + + qname->nspace = ns; + + if(qname->nspace) { + qname->uri = raptor_namespace_get_uri(qname->nspace); + if(qname->uri) + qname->uri = raptor_new_uri_from_uri_local_name(qname->world, qname->uri, new_name); + } + + return qname; +} + + +/** + * raptor_qname_copy: + * @qname: existing qname + * + * Copy constructor - copy an existing XML qname. + * + * Return value: a new #raptor_qname object or NULL on failure + **/ +raptor_qname* +raptor_qname_copy(raptor_qname *qname) +{ + raptor_qname* new_qname; + unsigned char* new_name; + + RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(qname, raptor_qname, NULL); + + new_qname = RAPTOR_CALLOC(raptor_qname*, 1, sizeof(*qname)); + if(!new_qname) + return NULL; + new_qname->world = qname->world; + + if(qname->value) { + size_t value_length = qname->value_length; + unsigned char* new_value; + + new_value = RAPTOR_MALLOC(unsigned char*, value_length + 1); + if(!new_value) { + RAPTOR_FREE(raptor_qname, new_qname); + return NULL; + } + + memcpy(new_value, qname->value, value_length + 1); /* Copy NUL */ + new_qname->value = new_value; + new_qname->value_length = value_length; + } + + new_name = RAPTOR_MALLOC(unsigned char*, qname->local_name_length + 1); + if(!new_name) { + raptor_free_qname(new_qname); + return NULL; + } + + memcpy(new_name, qname->local_name, qname->local_name_length + 1); /* Copy NUL */ + new_qname->local_name = new_name; + new_qname->local_name_length = qname->local_name_length; + + new_qname->nspace = qname->nspace; + + new_qname->uri = raptor_namespace_get_uri(new_qname->nspace); + if(new_qname->uri) + new_qname->uri = raptor_new_uri_from_uri_local_name(qname->world, new_qname->uri, new_name); + + return new_qname; +} + + +#ifdef RAPTOR_DEBUG +void +raptor_qname_print(FILE *stream, raptor_qname* name) +{ + if(name->nspace) { + const unsigned char *prefix = raptor_namespace_get_prefix(name->nspace); + if(prefix) + fprintf(stream, "%s:%s", prefix, name->local_name); + else + fprintf(stream, "(default):%s", name->local_name); + } else + fputs((char*)name->local_name, stream); +} +#endif + + +/** + * raptor_free_qname: + * @name: #raptor_qname object + * + * Destructor - destroy a raptor_qname object. + **/ +void +raptor_free_qname(raptor_qname* name) +{ + if(!name) + return; + + if(name->local_name) + RAPTOR_FREE(char*, name->local_name); + + if(name->uri && name->nspace) + raptor_free_uri(name->uri); + + if(name->value) + RAPTOR_FREE(char*, name->value); + RAPTOR_FREE(raptor_qname, name); +} + + +/** + * raptor_qname_equal: + * @name1: first #raptor_qname + * @name2: second #raptor_name + * + * Compare two XML Qnames for equality. + * + * Return value: non-0 if the qnames are equal. + **/ +int +raptor_qname_equal(raptor_qname *name1, raptor_qname *name2) +{ + if(name1->nspace != name2->nspace) + return 0; + if(name1->local_name_length != name2->local_name_length) + return 0; + if(strcmp((char*)name1->local_name, (char*)name2->local_name)) + return 0; + return 1; +} + + + +/** + * raptor_qname_string_to_uri: + * @nstack: #raptor_namespace_stack to decode the namespace + * @name: QName string or NULL + * @name_len: QName string length + * + * Get the URI for a qname. + * + * Utility function to turn a string representing a QName in the + * N3 style, into a new URI representing it. A NULL name or name ":" + * returns the default namespace URI. A name "p:" returns + * namespace name (URI) for the namespace with prefix "p". + * + * Partially equivalent to + * qname = raptor_new_qname(nstack, name, NULL); + * uri = raptor_uri_copy(qname->uri); + * raptor_free_qname(qname) + * but without making the qname, and it also handles the NULL and + * ":" name cases as well as error checking. + * + * Return value: new #raptor_uri object or NULL on failure + **/ +raptor_uri* +raptor_qname_string_to_uri(raptor_namespace_stack *nstack, + const unsigned char *name, size_t name_len) +{ + raptor_uri *uri = NULL; + const unsigned char *p; + const unsigned char *original_name = name; + const unsigned char *local_name = NULL; + unsigned int local_name_length = 0; + raptor_namespace* ns; + + /* Empty string is default namespace URI */ + if(!name) { + ns = raptor_namespaces_get_default_namespace(nstack); + } else { + /* If starts with :, it is relative to default namespace, so skip it */ + if(*name == ':') { + name++; + name_len--; + p = name + name_len; + } else { + for(p = name; *p && *p != ':'; p++) + ; + } + + /* If ends with :, it is the URI of a namespace */ + if(RAPTOR_GOOD_CAST(size_t, p-name) == (name_len - 1)) { + ns = raptor_namespaces_find_namespace(nstack, name, + RAPTOR_BAD_CAST(int, (name_len - 1))); + } else { + if(!*p) { + local_name = name; + local_name_length = (unsigned int)(p - name); + + /* pick up the default namespace if there is one */ + ns = raptor_namespaces_get_default_namespace(nstack); + } else { + /* There is a namespace prefix */ + unsigned int prefix_length = (unsigned int)(p - name); + p++; + + local_name = p; + local_name_length = (unsigned int)strlen((char*)p); + + /* Find the namespace */ + ns = raptor_namespaces_find_namespace(nstack, name, prefix_length); + } + } + } + + if(!ns) { + raptor_log_error_formatted(nstack->world, RAPTOR_LOG_LEVEL_ERROR, NULL, + "The namespace prefix in \"%s\" was not declared.", + original_name); + } + + + + /* If namespace has a URI and a local_name is defined, return the URI + * for this name + */ + if(ns && (uri = raptor_namespace_get_uri(ns))) { + if(local_name_length) + uri = raptor_new_uri_from_uri_local_name(nstack->world, uri, local_name); + else + uri = raptor_uri_copy(uri); + } + + return uri; +} + + +/** + * raptor_qname_write: + * @qname: QName to write + * @iostr: raptor iosteram + * + * Write a formatted qname to an iostream + * + * Return value: non-0 on failure + **/ +int +raptor_qname_write(raptor_qname *qname, raptor_iostream* iostr) +{ + if(qname->nspace && qname->nspace->prefix_length > 0) { + raptor_iostream_counted_string_write(qname->nspace->prefix, + qname->nspace->prefix_length, + iostr); + raptor_iostream_write_byte(':', iostr); + } + + raptor_iostream_counted_string_write(qname->local_name, + qname->local_name_length, + iostr); + return 0; +} + + +/** + * raptor_qname_to_counted_name: + * @qname: QName to write + * @length_p: pointer to variable to store length of name (or NULL) + * + * Get the string form of a QName name + * + * Return value: new string name or NULL on failure + **/ +unsigned char* +raptor_qname_to_counted_name(raptor_qname *qname, size_t* length_p) +{ + size_t len = qname->local_name_length; + unsigned char* s; + unsigned char *p; + + if(qname->nspace && qname->nspace->prefix_length > 0) + len+= 1 + qname->nspace->prefix_length; + + if(length_p) + *length_p=len; + + s = RAPTOR_MALLOC(unsigned char*, len + 1); + if(!s) + return NULL; + + p = s; + if(qname->nspace && qname->nspace->prefix_length > 0) { + memcpy(p, qname->nspace->prefix, qname->nspace->prefix_length); /* Do not copy NUL */ + p += qname->nspace->prefix_length; + *p++ = ':'; + } + + memcpy(p, qname->local_name, qname->local_name_length + 1); /* Copy final NUL */ + + return s; +} + + +/** + * raptor_qname_get_namespace: + * @name: #raptor_qname object + * + * Get the #raptor_namespace of an XML QName. + * + * Return value: the namespace + **/ +const raptor_namespace* +raptor_qname_get_namespace(raptor_qname* name) +{ + return name->nspace; +} + + +/** + * raptor_qname_get_local_name: + * @name: #raptor_qname object + * + * Get the #raptor_local_name of an XML QName. + * + * Return value: the local_name + **/ +const unsigned char* +raptor_qname_get_local_name(raptor_qname* name) +{ + return name->local_name; +} + + +/** + * raptor_qname_get_value: + * @name: #raptor_qname object + * + * Get the #raptor_value of an XML QName. + * + * Return value: the value + **/ +const unsigned char* +raptor_qname_get_value(raptor_qname* name) +{ + return name->value; +} + +/** + * raptor_qname_get_counted_value: + * @name: #raptor_qname object + * @length_p: pointer to variable to store length of name (or NULL) + * + * Get the #raptor_value of an XML QName. + * + * Return value: the value + **/ +const unsigned char* +raptor_qname_get_counted_value(raptor_qname* name, size_t* length_p) +{ + if(length_p) + *length_p=name->value_length; + return name->value; +} + + +/** + * raptor_qname_format_as_xml: + * @qname: qname object + * @length_p: pointer to length (or NULL) + * + * Format a qname in an XML style into a newly allocated string. + * + * Generates a string of the form a:b="value" or a="value" + * depending on the qname's prefix. Double quotes are always used. + * + * If @length_p is not NULL, the length of the string is + * stored in the address it points to. + * + * Return value: qname formatted as newly allocated string or NULL on failure + **/ +unsigned char* +raptor_qname_format_as_xml(const raptor_qname *qname, size_t *length_p) +{ + size_t length; + unsigned char *buffer; + const char quote='"'; + unsigned char *p; + + length = qname->local_name_length + 3 /* ="" */; + if(qname->value_length) + length += raptor_xml_escape_string(qname->world, + qname->value, qname->value_length, + NULL, 0, quote); + + if(qname->nspace && qname->nspace->prefix_length > 0) + length += qname->nspace->prefix_length + 1; /* for : */ + + if(length_p) + *length_p = length; + + buffer = RAPTOR_MALLOC(unsigned char*, length + 1); + if(!buffer) + return NULL; + + p = buffer; + + if(qname->nspace && qname->nspace->prefix_length > 0) { + memcpy(p, qname->nspace->prefix, qname->nspace->prefix_length); + p += qname->nspace->prefix_length; + *p++ = ':'; + } + memcpy(p, qname->local_name, qname->local_name_length); + p += qname->local_name_length; + *p++ = '='; + *p++ = quote; + if(qname->value_length) { + p += raptor_xml_escape_string(qname->world, + qname->value, qname->value_length, + p, length, quote); + } + *p++ = quote; + /* *p used here since we never need to use value of p again [CLANG] */ + *p = '\0'; + + return buffer; +} + + |