/* -*- 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 #endif #ifdef WIN32 #include #endif #include #include #include #include #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_STDLIB_H #include #endif /* Raptor includes */ #include "raptor.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) * @error_handler: function to call on an error * @error_data: user data for error function * * 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_simple_message_handler error_handler, void *error_data) { raptor_qname* qname; const unsigned char *p; raptor_namespace* ns; unsigned char* new_name; int prefix_length; int local_name_length=0; #if RAPTOR_DEBUG > 1 RAPTOR_DEBUG2("name %s\n", name); #endif qname=(raptor_qname*)RAPTOR_CALLOC(raptor_qname, 1, sizeof(raptor_qname)); if(!qname) return NULL; qname->world=nstack->world; if(value) { int value_length=strlen((char*)value); unsigned char* new_value=(unsigned char*)RAPTOR_MALLOC(cstring, value_length+1); if(!new_value) { RAPTOR_FREE(raptor_qname, qname); return NULL; } strcpy((char*)new_value, (char*)value); qname->value=new_value; qname->value_length=value_length; } /* Find : */ for(p=name; *p && *p != ':'; p++) ; if(!*p) { local_name_length=p-name; /* No : in the name */ new_name=(unsigned char*)RAPTOR_MALLOC(cstring, local_name_length+1); if(!new_name) { raptor_free_qname(qname); return NULL; } strcpy((char*)new_name, (char*)name); 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 RAPTOR_DEBUG > 1 RAPTOR_DEBUG2("Found default namespace %s\n", raptor_uri_as_string_v2(nstack->world, ns->uri)); #endif } else { #if RAPTOR_DEBUG > 1 RAPTOR_DEBUG1("No default namespace defined\n"); #endif } } /* if is_element */ } else { /* There is a namespace prefix */ prefix_length=p-name; p++; /* p now is at start of local_name */ local_name_length=strlen((char*)p); new_name=(unsigned char*)RAPTOR_MALLOC(cstring, local_name_length+1); if(!new_name) { raptor_free_qname(qname); return NULL; } strcpy((char*)new_name, (char*)p); 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? */ if(error_handler) error_handler((raptor_parser*)error_data, "The namespace prefix in \"%s\" was not declared.", name); } else { #if RAPTOR_DEBUG > 1 RAPTOR_DEBUG3("Found namespace prefix %s URI %s\n", ns->prefix, raptor_uri_as_string_v2(nstack->world, ns->uri)); #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_v2(qname->world, uri, new_name); qname->uri=uri; } return qname; } #ifndef RAPTOR_DISABLE_V1 /** * raptor_new_qname_from_namespace_local_name: * @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. * * raptor_init() MUST have been called before calling this function. * Use raptor_new_qname_from_namespace_local_name_v2() if using raptor_world APIs. * * Return value: a new #raptor_qname object or NULL on failure **/ raptor_qname* raptor_new_qname_from_namespace_local_name(raptor_namespace *ns, const unsigned char *local_name, const unsigned char *value) { return raptor_new_qname_from_namespace_local_name_v2(raptor_world_instance(), ns, local_name, value); } #endif /** * raptor_new_qname_from_namespace_local_name_v2: * @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_v2(raptor_world* world, raptor_namespace *ns, const unsigned char *local_name, const unsigned char *value) { raptor_qname* qname; unsigned char* new_name; int local_name_length=strlen((char*)local_name); if(!local_name) return NULL; qname=(raptor_qname*)RAPTOR_CALLOC(raptor_qname, 1, sizeof(raptor_qname)); if(!qname) return NULL; qname->world=world; if(value) { int value_length=strlen((char*)value); unsigned char* new_value=(unsigned char*)RAPTOR_MALLOC(cstring, value_length+1); if(!new_value) { RAPTOR_FREE(raptor_qname, qname); return NULL; } strcpy((char*)new_value, (char*)value); qname->value=new_value; qname->value_length=value_length; } new_name=(unsigned char*)RAPTOR_MALLOC(cstring, local_name_length+1); if(!new_name) { raptor_free_qname(qname); return NULL; } strcpy((char*)new_name, (char*)local_name); 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_v2(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; new_qname=(raptor_qname*)RAPTOR_CALLOC(raptor_qname, 1, sizeof(raptor_qname)); if(!new_qname) return NULL; new_qname->world=qname->world; if(qname->value) { int value_length=qname->value_length; unsigned char* new_value=(unsigned char*)RAPTOR_MALLOC(cstring, value_length+1); if(!new_value) { RAPTOR_FREE(raptor_qname, qname); return NULL; } strcpy((char*)new_value, (char*)qname->value); new_qname->value=new_value; new_qname->value_length=value_length; } new_name=(unsigned char*)RAPTOR_MALLOC(cstring, qname->local_name_length+1); if(!new_name) { raptor_free_qname(new_qname); return NULL; } strcpy((char*)new_name, (char*)qname->local_name); 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_v2(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) { RAPTOR_ASSERT_OBJECT_POINTER_RETURN(name, raptor_qname); if(name->local_name) RAPTOR_FREE(cstring, (void*)name->local_name); if(name->uri && name->nspace) raptor_free_uri_v2(name->world, name->uri); if(name->value) RAPTOR_FREE(cstring, (void*)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 * @error_handler: function to call on an error * @error_data: user data for error function * * 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, error_handler, error_data); * 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_simple_message_handler error_handler, void *error_data) { raptor_uri *uri=NULL; const unsigned char *p; const unsigned char *original_name=name; const unsigned char *local_name=NULL; 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--; } for(p=name; *p && *p != ':'; p++) ; /* If ends with :, it is the URI of a namespace */ if(p-name == (int)(name_len-1)) { ns=raptor_namespaces_find_namespace(nstack, name, name_len-1); } else { if(!*p) { local_name=name; local_name_length=p-name; /* pick up the default namespace if there is one */ ns=raptor_namespaces_get_default_namespace(nstack); } else { /* There is a namespace prefix */ int prefix_length=p-name; p++; local_name=p; local_name_length=strlen((char*)p); /* Find the namespace */ ns=raptor_namespaces_find_namespace(nstack, name, prefix_length); } } } if(!ns) { if(error_handler) error_handler((raptor_parser*)error_data, "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_v2(nstack->world, uri, local_name); else uri=raptor_uri_copy_v2(nstack->world, uri); } return uri; } /** * raptor_iostream_write_qname: * @iostr: raptor iosteram * @qname: QName to write * * Write a formatted qname to an iostream * * Return value: non-0 on failure **/ int raptor_iostream_write_qname(raptor_iostream* iostr, raptor_qname *qname) { if(qname->nspace && qname->nspace->prefix_length > 0) { raptor_iostream_write_counted_string(iostr, qname->nspace->prefix, qname->nspace->prefix_length); raptor_iostream_write_byte(iostr, ':'); } raptor_iostream_write_counted_string(iostr, qname->local_name, qname->local_name_length); 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: string 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=(unsigned char*)RAPTOR_MALLOC(cstring, len+1); if(!s) return NULL; p=s; if(qname->nspace && qname->nspace->prefix_length > 0) { strncpy((char*)p, (const char*)qname->nspace->prefix, qname->nspace->prefix_length); p+= qname->nspace->prefix_length; *p++ = ':'; } strncpy((char*)p, (const char*)qname->local_name, qname->local_name_length+1); 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; }