Configure namespaces

This is a guide on how FontoXML APIs can be used to accommodate for the use of namespaces, both in XML and in XPath and XQuery.

Starting from the 7.0 version of FontoXML, the editor supports namespaces. If your schema uses namespaces and your application manipulates nodes directly, make sure to use the namespace related functions (with names ending in NS) present on DOM nodes and Blueprint, such as createElementNS and getAttributeNS. This ensures that new elements and attributes are assigned to the correct namespace. Alternatively, use the convenience APIs such as Stencils or JsonML, the NamespaceManager or the various built-in operations, which make namespaces easy and clear to use by referring to them using separately configured prefixes.

Do my documents use namespaces?

This guide only applies to editors loading documents which use namespaces. Most editors use them in one way or another, either by using namespaces themselves, like the TEI or the JATS standards. Or by including other schemas, like MathML.

If an editor loads documents containing prefixed elements, or if an xmlns attribute is present, the editor should use namespaces. In general, it is preferred to use namespace related functions ending with NS (like createElementNS) over the normal functions (like createElement).

Introduction to namespaces

Namespaces are a way to use elements from different schemas into a single document. This is done by adding a URI to the name of an element. These URIs can be bound to a prefix for the sake of readability.

<mml:math xmlns:mml="https://www.w3.org/1998/Math/MathML/">
// A piece of mathML here
</math>

Namespaces do not have to have a prefix. A namespace without a prefix is called the 'default namespace'. XHTML usually does not use a prefix:

<html xmlns="https://www.w3.org/1999/xhtml/">
// A piece of XHTML
</math>

The namespace declaration does not have to exist at the top level element. It may exist at any (inclusive) ancestor of an element 'in' the namespace.

<html xmlns="https://www.w3.org/1999/xhtml/">
	<body xmlns:mml="https://www.w3.org/1998/Math/MathML/">
		<p>
			<mml:math>
				// A piece of mathML here
			</math>
		</p>
	</body>
</math>

Elements do not have to be in a namespace. For example, the DITA standard requires all DITA elements to be in the null namespace. The 'null namespace' is the namespace without a URI and without a prefix.

<topic>
	// A piece of dita content here
</topic>

Attributes work similarly. An attribute with a prefix exists 'in' the namespace associated with this prefix. However, attributes without prefixes always exist in the 'null namespace', not the default one.

<p>
	XLink defines a number of attributes <emph xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="...">in the xlink namespace</emph>.
</p>
<p>
	Attributes lacking a prefix <emph color="blue"> are in the null namespace</emph>.
</p>
<p xmlns="http://example.com/ns">
	Defining a default namespace <emph color="pink">does not affect this</emph>.
</p>

The full name of an element is called a qualified name. The part before the colon is called the prefix. The part after the colon is called a local name.

Namespaces can only apply to elements and attributes. There is no such thing as a comment or processing instruction 'in a namespace'.

XPath and namespaces

The XPath and XQuery implementation used by FontoXML also supports namespaces. It is provided with the NamespaceManager to relate prefixes used in the XPath to the namespaces. If the XPath needs to directly refer to namespace uris, the Q{} syntax can be used.

descendant::Q{https://www.w3.org/1998/Math/MathML/}math/attribute::Q{http://www.w3.org/1999/xlink/}href

The XPath engine does not yet fully support namespace usage for types. Namespace prefixes that are used only for defining custom XPath functions using registerCustomXPathFunction should be registered in the NamespaceManager. If the custom function is defined in an add-on, it might be a good idea to register the function without a prefix:

registerCustomXPathFunction({localName: 'do-something', namespaceURI: 'http://www.example.com/custom-function'}, [  ], 'xs:string?', function (dynamicContext) {
    ...
});

Namespace related APIs

Registering namespaces

Before FontoXML can use a namespace, it must be registered. This can be done in a configuration.js file, using the NamespaceManager:

Using an up to date version of FDT, namespace configuration is automatically generated when initializing a new Fonto Editor instance. However we might not be able to use a user friendly prefix, and use a numbered prefix, for example ns1. If possible change these generated prefixes to something sensible, and make sure to update the selectors for the CVK family configuration of the elements in the sx-modules accordingly.


configuration.js
// Register the XHTML namespace without a prefix. This a analogous to 'xmlns="https://www.w3.org/1999/xhtml/"'
namespaceManager.addNamespace(null, 'http://www.w3.org/1999/xhtml/');

// Register the MathML namespace, using the mml prefix. This is analogous to 'xmlns:mml="https://www.w3.org/1998/Math/MathML/"'
namespaceManager.addNamespace('mml', 'http://www.w3.org/1998/Math/MathML/');

// Also register a prefix for any application-specific XPath functions.
// Both the prefix and the namespace URI can be chosen by the application. This can be the same one as the namespace URI schema for which the editor is built, for example.
namespaceManager.addNamespace('app', 'http://www.fontoxml.com/app/your-app-name-here');

Creating elements

The namespace manager can also be used to create elements:

// Create an element in the XHTML namespace (which is bound to the empty prefix)
var xhtmlElement = namespaceManager.createElement(documentNode, 'html');

// Create a math element, in the mathML namespace (which is registered to bind to the mathml namespace URI)
var mathElement = namespaceManager.createElement(documentNode, 'mathml:math');

By using JsonML or Stencils, the namespace manager will be used to resolve the prefixes used in the element names:

var dom = jsonMLMapper.parseNode(documentNode, [
	'html',
	[
		'body',
		[ 
			'p', 
			[ 'mathml:math' ]
	]
]);

Note that it is unnecessary to mention the xmlns:whatever 'attributes'. The namespace manager will be used to resolve these prefixes, and the xmlns attributes will be added as needed when the document is serialized.

It is also possible to use the namespace related methods on Document like createElementNS, or the createElementNS method on NamespaceManager. This does require one to repeat the namespace URI for every call to these methods. This can be necessary if the prefix for this namespace is not known for some reason. This may be the case in addons which can be reused for multiple schemas.

Setting and getting attributes

The namespace manager can also be used to resolve a prefix to a uri. This uri can then be used to work with attributes:

var qname = namespaceManager.resolveQualifiedNameForAttribute(element, 'xlink:href');
blueprint.setAttributeNS(element, qname.namespaceURI, qname.qualifiedName, 'Some value');
blueprint.getAttributeNS(element, qname.namespaceURI, 'href');

// It is also possible to 'hard-code' the prefix like this:
blueprint.getAttribute(element, 'xlink:href');

// Many attributes do not use a prefix. For these attributes, the normal setAttribute methods suffice
blueprint.setAttribute(element, 'color', 'blue');

Higher level APIs like JsonML support namespaces in attributes by mentioning the qualified name of an attribute.

Using the setAttribute method with a prefixed name may yield unexpected results. This will correctly edit an attribute, but can not be used to create the attribute if it does not exist. To avoid this, always use the *NS methods when dealing with namespaced attributes.

Limitations

At this moment, FontoXML requires the relation between prefixes and namespaces to be one-to-one. One prefix may only bind to one URI and vice versa. Because of this, namespace overriding is not possible in the 7.0 version of FontoXML.