XML Utils: XML namespaces

Copyright © 1995-2005 Opera Software AS. All rights reserved. This file is part of the Opera web browser. It may not be distributed under any circumstances.
$Id$

Introduction

The XML Utils module provides code for handling XML namespace declarations through the class XMLNamespaceDeclaration. This includes handling XML namespace declaration attributes, maintaining a list of namespace declarations in scope and "resolving" complete names by setting the URI component based on the value of the prefix component and a list of namespace declarations in scope.

Scope list representation

The list of namespace declarations in scope is represented as a linked list of XMLNamespaceDeclaration objects via a pointer to the object representing the most recent (nearest) namespace declaration. A null pointer represents an empty list. The objects are reference counted. Each object owns a reference to the previous namespace declaration and external users typically owns a single reference to the head of the list.

The list is maintained while parsing/processing an XML document by pushing and popping objects as namespaces are declared and go out of scope. By adding an extra reference to the current head of the list at any point, users can essentially keep a copy of the list of namespace declarations in scope at that point indefinitely while parsing/processing continues and the list changes.

Pushing namespace declarations

The list of namespace declarations in scope is updated from new namespace declaration attributes by calling the static function XMLNamespaceDeclaration::ProcessAttribute. It is perfectly legal to call the function to process attributes that are not namespace declaration attributes. If called to process such attributes, it will do nothing at all.

The scope of namespace declarations is determined by the level argument to XMLNamespaceDeclaration::ProcessAttribute. The level of an attribute is typically the number of ancestors the element on which the attribute was specified. Users are however free to use other methods to determine the level of an attribute and thus implement different scoping rules, if appropriate.

In addition from being pushed when processing namespace declaration attributes, namespace declarations can be pushed manually using one of the static functions XMLNamespaceDeclaration::Push or XMLNamespaceDeclaration::PushL. These functions work much the same way as XMLNamespaceDeclaration::ProcessAttribute except instead of an attribute name and value, a namespace URI and prefix is supplied together with the pointer to the head of the namespace declaration list to update and the level of the namespace declaration.

The first argument to each of the functions used to push namespace declarations is a pointer to the currently most recent namespace declaration object. This pointer is updated by the functions if a new namespace declaration is pushed to point to the new namespace declaration. One reference to the previous namespace declaration object, which the caller is assumed to own, is transferred to the new namespace declaration object. If the pointer was initially null the caller did not own a reference to any namespace declaration object, but will own one after the function call.

End of scope

The end of the scope of namespace declarations is signalled by calling the static function XMLNamespaceDeclaration::Pop with the same level argument as was used to process the namespace declaration argument or to push the declaration. Normally, the scope of namespace declarations end when the element on which the corresponding namespace declaration attribute was specified ends, so typically XMLNamespaceDeclaration::Pop should be called at the end of each element, with the same level argument as was used to process that element's attributes. It is okay to call XMLNamespaceDeclaration::Pop at the end of any element, even though no namespace declaration's scope ends there. XMLNamespaceDeclaration::Pop will simply pop any namespace declaration that was pushed with a equal or higher level argument than that used in the call to XMLNamespaceDeclaration::Pop.

Like to the functions used to push namespace declarations, the first argument to the function XMLNamespaceDeclaration::Pop is a pointer to the object representing the currently most recent namespace declaration. This pointer is updated if any namespace declarations are popped, and one reference to the object, which the caller is assumed to own, is transferred to the object the pointer points to after the function call. If the last namespace declaration is popped, the pointer is set to null and the reference is simply released.

Note: if the list of namespaces in scope is only modified by calls to the pushing and popping functions described here, no explicit reference counting will be necessary, unless processing is stopped before all levels are popped (that is, when the list of namespaces in scope is potentially non-empty.) If processing is so stopped, only a single reference needs to be released.