I'm trying to understand how namespaces work in XML. When I have an element like foo:bar, the attributes will often not have namespaces on them. But sometimes they will. Are the attribute in the namespace of the element, even when the default namespace has been declared? Looking over the xsd for xhtml it seems the attributes are part of the schema and should be in the namespace for xhtml, but they are never presented that way...
4 Answers
Most of the time, attributes will not be in any namespace. The namespace spec says (emphasis mine):
A default namespace declaration applies to all unprefixed element names within its scope. Default namespace declarations do not apply directly to attribute names; the interpretation of unprefixed attributes is determined by the element on which they appear.
There's a reason that most XML vocabularies use non-namespaced attributes:
When your elements have a namespace and those elements have attributes, then there can be no confusion: the attributes belong to your element, which belongs to your namespace. Adding a namespace prefix to the attributes would just make everything more verbose.
So why do namespaced attributes exist?
Because some vocabularies do useful work with mostly attributes, and can do this when mixed in with other vocabularies. The best known example is XLink.
Lastly, W3C XML Schema has an all too easy way (<schema attributeFormDefault="qualified">
) of declaring your attributes as being in a namespace, forcing you to prefix them in your documents, even when you use a default namespace.
Examples to illustrate using the Clark notation, where the namespace prefix is replaced with the namespace URL in curly brackets:
<bar xmlns:foo="http://www.foo.com/"
foo:baz="baz"
qux="qux"/>
<bar xmlns="http://www.foo.com/" xmlns:foo="http://www.foo.com/"
foo:baz="baz"
qux="qux"/>
<foo:bar xmlns="http://www.foo.com/" xmlns:foo="http://www.foo.com/"
foo:baz="baz"
qux="qux"/>
is
<{}bar
{http://www.foo.com/}baz="baz"
{}qux="qux"/>
<{http://www.foo.com/}bar
{http://www.foo.com/}baz="baz"
{}qux="qux"/>
<{http://www.foo.com/}bar
{http://www.foo.com/}baz="baz"
{}qux="qux"/>
There's something related to this attributes/namespaces subject that took me some time to understand today when I was working on a XSD. I'm going to share this experience with you in case anyone ever happens to have the same issues.
In the Schema Document I was working on there were a couple of global attributes referenced by some elements. To simplify things here let's assume this XSD I'm talking about was about a Customer.
Let's call one of these global attributes Id. And the root element using it Customer
My XSD declaration looked like this :
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns="http://schemas.mycompany.com/Customer/V1"
targetNamespace="http://schemas.mycompany.com/Customer/V1"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
My Id attribute declaration looked like this :
<xs:attribute name="Id" type="xs:positiveInteger"/>
And my Customer element used the attribute like this :
<xs:element name="Customer">
<xs:complexType>
<xs:attribute ref="Id" use="required"/>
<!-- some elements here -->
</xs:complexType>
</xs:element>
Now, let's say I wanted to declare a Customer XML document like this :
<?xml version="1.0" encoding="utf-8"?>
<Customer Id="1" xmlns="http://schemas.mycompany.com/Customer/V1">
<!-- ... other elements here -->
</Customer>
I found out that I can't : when the attribute is globally declared, it's not in the same namespace than the element who references it.
I figured out that the only solution with the XSD defined like that was to declare the namespace twice: once without a prefix in order to make it the default namespace for elements, and once with a prefix in order to use it with the attributes. So this is how it would have looked like :
<?xml version="1.0" encoding="utf-8"?>
<Customer cus:Id="1" xmlns="http://schemas.mycompany.com/Customer/V1"
xmlns:cus="http://schemas.mycompany.com/Customer/V1">
<!-- ... other elements here -->
</Customer>
This is so unpractical that I just decided to get rid of all global attributes and declare them them locally. Wich in the case of the example I gave here would have looked like this:
<xs:element name="Customer">
<xs:complexType>
<xs:attribute name="Id" type="xs:positiveInteger" use="required"/>
<!-- some elements here -->
</xs:complexType>
</xs:element>
I found it hard to find some references about what I'm talking about here in the net. I eventually found this post in the Stylus XSD Forum where a guy named Steen Lehmann suggested either to declare the attribute locally or to declare it within an attribute group
"so that the attribute declaration itself is no longer global"
This last solution has a "hacky" taste, so I just decided to stick with the first solution and declare all my attributes locally.
Read up at 6.1 Namespace Scoping and 6.2 Namespace Defaulting on w3c.
Basically:
The scope of a namespace declaration declaring a prefix extends from the beginning of the start-tag in which it appears to the end of the corresponding end-tag
However, the text here doesn't seem to explain if means a is foo:a or the default namespace in the context. I would assume that it does not refer to foo:a, but rather the documents default namespace a. Considering this quote at least:
Such a namespace declaration applies to all element and attribute names within its scope whose prefix matches that specified in the declaration.
Ie. the namespace "foo:" only applies to elements prefixed with foo: