Namespaces, Name With Spaces, and Attribute Values
October 8, 2003
Q: What namespace prefix should I use in a W3C Schema?
Although the W3 Schema specification uses the namespace prefix xsd:
, it looks
as though in current practice only xs:
is used.
Could you please confirm
if this is the case and is the reason just that it is shorter?
A: Actually, it depends on which part of "the W3 Schema specification" you're referring to
- XML Schema Part 0: Primer does indeed
use the
xsd:
namespace prefix. (For instance, see the sample Purchase Order Schema.) - However, that namespace prefix is nowhere to be found in the main XML Schema Part 1: Structures, which uses
xs:
everywhere. - And XML Schema Part 2: Datatypes uses
xsd:
in the examples, butxs:
for its Appendix A, the normative Schema for Datatype Schemas.
What's going on here? Isn't one prefix the right one?
While one might wish for more consistency in the specs to avoid this sort of confusion, in fact there's no such thing as a "correct" W3C Schema namespace prefix or even simply a better one. Indeed, there's no such thing as a correct or even better namespace prefix for any XML application at all. That's because XML processing software -- at least, software which conforms to the Namespaces in XML Recommendation -- doesn't care about the prefix; it cares only about what URI the prefix is associated with. The prefix is just a shorthand way of referring to the URI.
Assume an XML document, presumably a W3C Schema document, opens in this fashion:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> ... <xs:element name="elem1" type="Address">
When the processor encounters the xs:element
element, it actually
"understands" it in something like this form, substituting the URI for the prefix:
{http://www.w3.org/2001/XMLSchema}element
This notation -- the namespace URI enclosed in curly braces, followed by the element's local name -- is used internally almost universally by XPath-aware processors, such as XSLT engines. If you think about it, you'll see that it thus really doesn't matter what prefix you use, as long as you choose one which isn't misleading to a human reader and then use it consistently. For instance, you might rework the partial XML document (Schema) above as follows:
<W3CSchema:schema xmlns:W3CSchema="http://www.w3.org/2001/XMLSchema"> ... <W3CSchema:element name="elem1" type="Address">
If it doesn't make any difference which prefix we use, why choose one prefix over
another?
I don't know, but suspect, that use of the xs:
prefix might allude to a predecessor of XML Schema, known as
XSchema, later renamed the Document Definition Markup Language (DDML).
And, as you suggest, it does save a character for every namespace-qualified name.
On the
other hand, simply using x:
would be even shorter, just not as clear. As for
xsd:
, maybe it's meant to associate the namespace with the filename
extension, ".xsd", commonly used for XML Schema
documents.
So, sure, go ahead, use xs:
for brevity's sake, xsd:
if you want
to associate the namespace prefix with the Schema document's extension, or anything
else.
Just keep the URIs correct, and keep the namespace prefix meaningful and consistent.
Q: How do I ignore elements or attributes in a particular namespace?
What is the best approach to copy only elements and attributes in namespace "a" and ignore everything in namespace "b", using XSLT? For instance, in this document,
<a:root xmlns:a="a" xmlns:b="b" > <a:child name="attr1" b:foo="foo1" /> <a:child name="attr2" b:foo="foo2" /> </a:root>
I'd like to copy the a:root
and a:child
elements, as well as the
name
attribute of each a:child
, but ignore the
b:foo
attributes.
A: I'm not sure if this is the "best" approach -- it's not particularly
elegant -- but a straightforward way to do it is simply to select only those element
and
attribute names that do not start with the "undesirable" namespace prefix. This requires
that you use the XPath name()
function, in concert with the not()
and starts-with()
functions. Here's a pair of xsl:template
elements to do so might look something like this (substituting an XHTML result tree
for the
copy operation, for demonstration purposes):
<xsl:template match="*|@*[not(starts-with(name(), 'b:'))]"> <h3>Copying <xsl:value-of select="name()"/>...</h3> <xsl:apply-templates select="*|@*[not(starts-with(name(), 'b:'))]"/> </xsl:template> <xsl:template match="@*"> <h4>Copying <xsl:value-of select="name()"/>...</h4> </xsl:template>
Note that you can't use the local-name()
function, which strips off the
namespace prefixes. You also can't use the namespace-uri()
function to test for
the desirable namespace prefix: you won't pick up (in this case) the name
attributes.
Q: Can a parameter name include a space?
I need to declare some XSLT parameter with whitespace in the name. Is this
<xsl:param name="my value" />
allowed?
A: No. Parameter names must be legitimate XML names. A simple attribute
value, even that of an xsl:param
element's name
attribute, may
contain whitespace and be perfectly well-formed as XML . But xsl:param
, like
xsl:element
and xsl:attribute
, is intended to create a unique,
easily parsed instance of an object in a document. That a parameter's name, once created,
is
later referred to using a dollar sign -- like $my_value
, say -- rather than
enclosed in angle brackets is only superficially different from the name of an element
or an
attribute. Like any other programming language, XSLT simply does not allow spaces
in the
names of identifiers used by programs written in that language.
The whole point of XML is to simplify markup by eliminating as many options as possible. Nearly every XMLoid has a wish list of Things XML Might Do For My Convenience. But the XML world is complicated enough without trying to satisfy everyone. In my opinion, core XML remains a model of how to do something good enough. So you're stuck; either reevaluate your need or consider some non-XML solution.
Q: How do I build an attribute value in XSLT using a variable value?
I don't mean "variable" in the sense of an XSLT variable. I mean the actual value isn't known until runtime, taken (say) from an element's value. For instance, if I want to put this in the output:
<input style="width:some-value-in-points">...</input>
and the number of points is available as an element value elsewhere in the document, how do I substitute it in place of the "some-value-in-points"?
A: The only real trick is to know that an XSLT stylesheet can build
attributes not just using literal values, but by way of a special XSLT element,
xsl:attribute
.
Assume you've got a source document which looks like this (ignoring whitespace added for legibility):
<root> ... <textwidth>150</textwidth> ... </root>
Also assume that there's only one textwidth
element in this document. In a
template rule in the stylesheet, you'd include something like this:
<input> <xsl:attribute name="style">width:<xsl:value-of select="/root/textwidth" />pts</xsl:attribute>... </input>
![]() |
|
Also in XML Q&A |
|
The xsl:attribute
element must immediately follow the element you want to
assign the attribute to -- the input element, in this case. It takes a name attribute,
and
the resulting attribute will have the indicated name. The string-value of the
xsl:attribute
element is assigned as the resulting attribute's value. In the
above example, we've instantiated (a) an input
element, which has (b) a
style
attribute the value of which is the concatenation of the text string
"width:", the string-value (150) of the source document's textwidth
element,
and the text string "pts". Thus:
<input style="width:150pts">...</input>
By the way, note that you needn't get the value to be substituted from the source
tree. You
can get it from another document altogether, using the document()
function. And
this other document can even be the stylesheet itself, if that's what you're after:
just
supply an empty string as the argument to the function:
document("")
For one demonstration of this, see the XSL FAQ, in the example provided by Ken Holman.