/* ***************************************************************************** * * $RCSfile: namespace.c,v $ * $Date: 1999/05/18 18:36:20 $ * $Source: /home/richard/Xml/RCS/namespace.c,v $ * $Revision: 1.9 $ * $Author: richard $ * ***************************************************************************** * * Copyright 1999, Brown University and Richard Goerwitz * ***************************************************************************** * * Utilities for dealing with namespaces. * ***************************************************************************** */ #include "namespace.h" #include "errabort.h" #include "xtrautil.h" /* * grab_namespace_decls_from_atts * * Goes through an xn struct's attribute list, reading in all namespace * and default namespace decls, and setting xn's namespaces and default_ * namespace fields correctly. * * Must be called after the attributes have all been checked for basic * well-formedness, and the defaults have all been filled in. But call * it before checking whether all prefixes used in non-decl attributes * are declared. * * Returns the number of namespaces defined, including the default. */ int grab_namespace_decls_from_atts (struct xml_file *xf, struct xml_node *xn) { size_t i; int lineno; struct name_val *nv; struct malloc_block_list *mbl = NULL; for (i = 0; i < xn->attcount; i++) { /* If there's a prefix: component to the attribute name */ if (xn->atts[i]->prefix) { /* if prefix is "xmlns", localpart is namespace name */ if (uni_utf_strcmp (xn->atts[i]->prefix, "xmlns") == 0) { if (uni_utf_strcmp (xn->atts[i]->localpart, "xml") == 0) { /* xmlns is reserved; we use it to declare namespaces */ if (xn->atts[i]->lineno == 0) add_xml_error (xf, 1385, xn->atts[i]->name); else { lineno = xf->lineno; xf->lineno = xn->atts[i]->lineno; add_xml_error (xf, 1385, xn->atts[i]->name); xf->lineno = lineno; } } else if (uni_utf_strncmp (xn->atts[i]->localpart, "xml", 3) == 0) { /* namespaces beginning with "xml" are reserved for future use */ if (xn->atts[i]->lineno == 0) add_xml_error (xf, 1384, xn->atts[i]->name); else { lineno = xf->lineno; xf->lineno = xn->atts[i]->lineno; add_xml_error (xf, 1384, xn->atts[i]->name); xf->lineno = lineno; } } else { /* add new namespace to namespace list */ nv = create_name_val (xn->atts[i]->localpart, xn->atts[i]->val, NULL, NULL, xn->atts[i]->lineno, xn->atts[i]->was_defaulted, NULL); if (nv->was_defaulted == yes) /* namespace-declaring atts added via DTD defaulting mechanisms are bad */ add_xml_warning (xf, 1391, xn->atts[i]->name); mbl = push_block (mbl, nv, 0); } } } else { /* no prefix component; see if att is "xmlns" */ if (uni_utf_strcmp (xn->atts[i]->name, "xmlns") == 0) { if (xn->atts[i]->was_defaulted == yes) /* namespace-declaring atts added via DTD defaulting mechanisms are bad */ add_xml_warning (xf, 1392, xn->name); /* not defined; use this att's val as default; note that * the duplicate attval checker (called later on by the * parser) will pick up any duplicates here */ if (xn->default_namespace == NULL) xn->default_namespace = uni_strdup (xn->atts[i]->val); else /* duplicate default namespace decl */ xwrap (errdebug (5, "Oops; two default namespace decls, %s\n", xn->name ? utf_16_to_utf_8 (xn->name) : "(null)")); } } } xn->namecount = get_block_len (mbl); xn->namespaces = mbl ? (struct name_val **)mbl->blocks : NULL; return get_block_len (mbl); } /* * in_a_default_namespace * * Special-purpose routine that tells us, from our current attribute * list (nvp) and our xml_node (xn) whether we're in a default * namespace. Returns true or false (1 or 0). */ int in_a_default_namespace (struct xml_file *xf, struct xml_node *xn, struct name_val **nvp, size_t count) { size_t i; struct xml_node *n; if (xn == NULL) return 0; /* see if attributes declare or undeclare a default namespace */ if (nvp) for (i = 0; i < count; i++) if (uni_utf_strcmp (nvp[i]->name, "xmlns") == 0) if (nvp[i]->val) return *nvp[i]->val ? 1 : 0; for (n = xn; n; n = n->parent) if (n->default_namespace) /* * a blank default namespace means stop searching; a nonblank one * means we have a valid default namespace; a NULL default namespace * tells us to keep searching */ return *n->default_namespace ? 1 : 0; /* no default namespace decl found, from xn up to the root xml_node */ return 0; } /* * prefix_to_uri * * Take a prefix (presumably the namespace portion of an attribute * or element name), and return the corresponding namespace URI. If * the namespace is not declared, and there is therefore no such URI, * then return NULL. */ my_wchar_t * prefix_to_uri (struct xml_file *xf, struct xml_node *xn, my_wchar_t *prefix) { size_t i; struct xml_node *n; xwrap (errdebug (7, "Resolving prefix, %s, as namespace URI\n", utf_16_to_utf_8 (prefix))); /* for every xml_node n from here up to the root ... */ for (n = xn; n; n = n->parent) /* if this node has namespaces defined, then */ if (n->namespaces) /* check every namespace in node n ... */ for (i = 0; i < n->namecount; i++) /* ... to see if that namespace name is the same as our prefix */ if (uni_strcmp (n->namespaces[i]->name, prefix) == 0) /* if it is, return the URI */ return n->namespaces[i]->val; /* failed to resolve prefix as namespace URI */ return NULL; } /* * break_out_prefix * * Create a name_val struct holding 1) all of name (arg 1) in its * name field, 2) name's prefix (e.g., the "html" in "html:table") * in its prefix field, and 3) name's local part (e.g., the "table" * in "html:table" in its localpart field. * * Returns a pointer to the new name_val struct. Be sure to call * free_name_val() to reclaim any unneeded storage later on. (If * the structure is later incorporated into an xml_node struct, then * don't bother; free_xml_node() will catch it). */ struct name_val * break_out_prefix (my_wchar_t *name) { my_wchar_t c, *wp; struct name_val *nv; if (name == NULL) return NULL; /* malloc() a name_val struct; set "name" field to name */ nv = create_name_val (name, NULL, NULL, NULL, 0, no, NULL); /* move up to first colon or nil */ for (wp = name; *wp && *wp != ':'; wp++); /* if we didn't find a colon... */ if (! *wp) { /* ...then set nv->localpart to all of name */ nv->prefix = NULL; nv->localpart = uni_strdup (name); } else { /* ...otherwise, set localpart to whatever is after the colon */ c = *wp++; nv->localpart = uni_strdup (wp); if (wp == (name + 1)) /* empty prefix */ nv->prefix = NULL; else { /* set nv->prefix to whatever's before the colon */ *--wp = 0; nv->prefix = uni_strdup (name); *wp = c; } } return nv; } /* * check_for_colon * * Checks for a colon in name, and make sure that on either side of * the colon is a non-empty QName (as per the namespace spec). Spits * out the appropriate error message (err1, err2, or err3) if there * are any problems. * * Returns 1 if name (arg 2) contains a namespace. Zero otherwise. */ int check_for_colon (struct xml_file *xf, my_wchar_t *name, int err1, int err2, int err3) { my_wchar_t c, *wp; if (name == NULL) return 0; /* move up to first colon or nil */ for (wp = name; *wp && *wp != ':'; wp++); /* if we didn't find a colon, return now */ if (! *wp) return 0; /* ...otherwise, check prefix and localpart */ c = *wp++; if (! *wp) { /* empty localpart (i.e., whatever's after the colon) */ add_xml_error (xf, err2, name); return 0; } if (uni_strchr (wp, c)) { /* we can only have one colon in name */ add_xml_error (xf, err1, name); return 0; } if (wp == (name + 1)) { /* empty prefix */ add_xml_error (xf, err3, name); return 0; } return 1; } #ifdef STANDALONE_NAMESPACE_TEST #include "readcfg.h" #include "utfutil.h" xmlparse_environment xmlparse_env; int main (int argc, char **argv) { my_wchar_t *name; struct name_val *nv; readcfg (argc, argv); name = utf_8_to_utf_16 ("hello:goodbye"); nv = break_out_prefix (name); if (! (uni_utf_strcmp (nv->name, "hello:goodbye") == 0 && uni_utf_strcmp (nv->prefix, "hello") == 0 && uni_utf_strcmp (nv->localpart, "goodbye") == 0)) printf ("Prefix break-out failed for hello:goodbye.\n"); free_name_val (nv); name = utf_8_to_utf_16 (":hello:goodbye"); nv = break_out_prefix (name); if (! (uni_utf_strcmp (nv->name, ":hello:goodbye") == 0 && nv->prefix == NULL && uni_utf_strcmp (nv->localpart, "hello:goodbye") == 0)) printf ("Prefix break-out failed for :hello:goodbye.\n"); free_name_val (nv); name = utf_8_to_utf_16 ("hello:"); nv = break_out_prefix (name); if (! (uni_utf_strcmp (nv->name, "hello:") == 0 && uni_utf_strcmp (nv->prefix, "hello") == 0 && *nv->localpart == 0)) printf ("Prefix break-out failed for hello:.\n"); free_name_val (nv); name = utf_8_to_utf_16 (":goodbye"); nv = break_out_prefix (name); if (! (uni_utf_strcmp (nv->name, ":goodbye") == 0 && nv->prefix == NULL && uni_utf_strcmp (nv->localpart, "goodbye") == 0)) printf ("Prefix break-out failed for :goodbye.\n"); free_name_val (nv); name = utf_8_to_utf_16 ("::"); nv = break_out_prefix (name); if (! (uni_utf_strcmp (nv->name, "::") == 0 && nv->prefix == NULL && uni_utf_strcmp (nv->localpart, ":") == 0)) printf ("Prefix break-out failed for ::.\n"); free_name_val (nv); name = utf_8_to_utf_16 (":"); nv = break_out_prefix (name); if (! (uni_utf_strcmp (nv->name, ":") == 0 && nv->prefix == NULL && *nv->localpart == 0)) printf ("Prefix break-out failed for :.\n"); free_name_val (nv); name = utf_8_to_utf_16 (""); nv = break_out_prefix (name); if (! (*nv->name == 0 && nv->prefix == NULL && uni_strcmp (nv->name, nv->localpart) == 0)) printf ("Prefix break-out failed for empty string, \"\".\n"); free_name_val (nv); exit (0); } #endif /* STANDALONE_NAMESPACE_TEST */