xslt namespace, namespaces
1. | Understanding namespaces | ||
Jeni Tennison, David Carlisle, Mike Kay, Chris Maden > <B> > <A xmlns:x="X" xmlns:y="Y" /> > <A xmlns:x="X" /> > </B> > > this has ns declarations 'for' two ns. > Which ns is the first A element 'in'? > Or is that a factor of the prefix used? I.e. they are in the null ns? Absolutely. The namespace that an element or attribute is *in* is a factor of their name. The name is made up of a prefix and a local name. The prefix indicates the namespace that the element or attribute is in. Thus, all the elements in the above are have no prefixes, so they are in the *default* namespace. In the example, the default namespace hasn't been declared, so they are in the *null* namespace. > So the subtleties appear to be differentiating between > the (single) ns an element is *in* > the (possibly multiple) ns declared *for* the element > the (possibly multiple) ns's *in scope* > (Guess that the latter two are equivalent?) Yes, the latter two are equivalent. Technically, a namespace declaration adds a namespace node to the element the namespace declaration is on, and to all the elements it has as descendants. That namespace is 'in scope' to that element and all its descendants. > Which leaves the 'null' ns and no ns declaration. > Equivalent? > <A xmlns:x="" /> > and <A> David interjects with a nuance, More or less equivalant. It is really a mismatch of terminoligy. The namespace spec does not admit to a concept of a "null namespace" it says that in the absence of any declarations <A/> is not in a namespace. However, XPath, in common with some other systems needs _something_ to return for the namespace, to denote the lack of a namespace. It uses the empty string for this so if you are using such a system it is (perhaps) natural to refer to elements that are not in a namespace as being in the "empty" or "null" namespace. Mike comes back with Technically, according to the Namespaces Rec, element A is not in a namespace; according to the XPath model, it therefore has a null namespace URI, and when an element has a null namespace URI, the value of the namespace-uri() function is an empty string. Not precisely equivalent. <A xmlns:x="" /> Translates to: +- (element node) A - null namespace \- (namespace node) xml \- (namespace node) x Whereas: <A /> Translates to: +- (element node) A - null namespace \- (namespace node) xml Both A elements are in the same (null) namespace, but the first has a namespace node named 'x' on it. The example you're missing is: <x:A xmlns:x="" /> which is almost exactly the same as: <A xmlns:x="" /> The only difference from XSLT's point of view is that the name() function will return 'x:A' for the former and 'A' for the latter. (David C notes, except that the first one doesn't conform to the namespace spec so would be rejected by a namespace aware parser:-) From the rec Definition:] If the attribute name matches PrefixedAttName, then the NCName gives the namespace prefix, used to associate element and attribute names with the namespace name in the attribute value in the scope of the element to which the declaration is attached. In such declarations, the namespace name may not be empty. ie xmlns:foo="" is not allowed [Definition:] If the attribute name matches DefaultAttName, then the namespace name in the attribute value is that of the default namespace in the scope of the element to which the declaration is attached. In such a default declaration, the attribute value may be empty. ie xmlns="" is allowed Another gem from David, (Every element has a namespace node for the xml: prefix) This is stressed again at several points in the doc, I just noticed these two: If the URI reference in a default namespace declaration is empty, then unprefixed elements in the scope of the declaration are not considered to be in any namespace. .... The default namespace can be set to the empty string. This has the same effect, within the scope of the declaration, of there being no default namespace. Mike notes, An element can have any number of namespace declarations within the element start tag, and it also inherits namespace declarations from its parent element. But of course only one of these namespaces can be used in the element name. If we're going to be precise, an element node can be the parent of multiple namespace nodes, but it can only have one expanded name, and therefore only one namespace URI. From Chris Maden An element has one, and exactly one, name. That name has a namespace URI and a local part. The namespace part may be null, if there is no prefix and no default namespace in scope. This example has no namespace URI and a local part of "foo": <foo xmlns=""/> The namespace part may be a URI. In both of these examples, the URI is "http://crism.maden.org/consulting/example-namespace" and the local part is "foo": <foo xmlns="http://crism.maden.org/consulting/example-namespace"/> <ex:foo xmlns:ex="http://crism.maden.org/consulting/example-namespace"/> Now, this is getting confused with the namespace declarations in scope. An element only ever has one namespace. But more than one namespace *declaration* may be in scope for that element. In these examples, the element has the namespace http://crism.maden.org/consulting/example-namespace and a local part of "foo", but there are two namespace declarations in scope: <ex:foo xmlns:ex="http://crism.maden.org/consulting/example-namespace" xmlns="http://crism.maden.org/consulting/example-namespace-2"/> <foo xmlns="http://crism.maden.org/consulting/example-namespace" xmlns:ex="http://crism.maden.org/consulting/example-namespace-2"/> These elements are of the same type. In XPath 1.0, you must use a prefix to match an element type with a URI. In XSLT, the way to bind that prefix to a URI is to have namespace declarations in scope in the XML document that is the stylesheet: <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ex="http://crism.maden.org/consulting/example-namespace"> <xsl:template match="ex:foo"/> </xsl:stylesheet> That template matches *all* of the foo elements given above, except the first one (which has no namespace URI). | |||
2. | Namespace explanation - 1 | ||
Namespaces are identified with URIs that don't have to point to anything. They are used to differentiate between XML element names. The classic example is an element type of 'title'. In your document it might mean book title, and in mine it might mean job title. If we want to avoid confusion we need to bind your 'title' elements to one URI and mine to another. The nice backward-compatible way of doing this in XML is to use a special kind of attribute called a namespace declaration to either establish a default namespace URI for the element and its descendant elements, or to associate a namespace URI with a prefix that can then be tacked on to the beginning of an element name. So let's say you have an element called 'for-each' and you want your XSL processor to know that this is an XSLT instruction, not just something you happened to call 'for-each'. The processor, if it supports XSLT, will know that elements associated with the namespace URI 'http://www.w3.org/1999/XSL/Transform' are XSLT instructions and will process them appropriately. The typical way to designate the 'for-each' element as an XSLT instruction is to first bind the prefix 'xsl' (or any other prefix) to the XSLT namespace URI, and then tack that on the element name, like this: <xsl:for-each xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> The magic is not in the placement of the xmlns:xsl (well, for the most part, anyway), nor in the choice of 'xsl' as the prefix, nor in the fact that a prefix was used at all; it is merely the fact that this particular element is associated with the URI 'http://www.w3.org/1999/XSL/Transform'. If the XSL processor only recognizes a certain other namespace URI as being special, it will treat your xsl:whatever element as being just an ordinary element, which in the world of XSL is interpreted as a 'literal result element' you want copied to the result tree. | |||
3. | Namespaces in the source document | ||
I am new to xslt. Much of the explanation of xslt (books, websites) discuss namespace from the .xsl perspective and doesn't give examples where the -IN xml document uses namespaces. My specific problem is that when I add a namespace, the examples break. In your first example, the programme, opera etc. elements were all in *no namespace* as you had no default namespace declaration (and they weren't prefixed). In your second example, the programme, opera etc. elements were all in the namespace 'http://www.emilygraham.com/java/other/Opera' as that was the namespace specified by the default namespace declaration. When expressions or patterns select or match elements and attributes, they select or match them according to *both* their local name (e.g. 'programme', 'opera') and their namespace. As far as an XSLT processor is concerned, the two following programme elements are completely different: <programme ... </programme <programme xmlns="http://www.emilygraham.com/java/other/Opera" ... </programme I sometimes use the extended representation {namespace-uri}local-name to make this clearer. In the first example, the programme element is {}programme. In the second example, the programme element is actually {http://www.emilygraham.com/java/other/Opera}programme. When you use an element or attribute name in an XPath and you don't give a prefix to that element or attribute name, the XSLT processor *always* looks for elements/attributes in no namespace. So: /programme/composer is equivalent to: /{}programme/{}composer To process your second example, you need to have the equivalent of: /{http://www.emilygraham.com/java/other/Opera}programme To do this, you need to have a prefix in your XSLT stylesheet that is associated with the namespace 'http://www.emilygraham.com/java/other/Opera'. You do this in the same way as you do in normal documents, with an xmlns:xx attribute: <xsl:stylesheet version="1.0" Within the stylesheet, the 'op' prefix is associated with the 'http://www.emilygraham.com/java/other/Opera' namespace. So you can do: /op:programme/op:composer to get the XPath that you need. To put it into simple steps - if you add a default namespace to your instance document you need to:
One of the requirements for XSLT 2.0 is that you should be able to easily change the default namespace used when an element (or attribute?) name in a path doesn't have a prefix, so that adding a namespace to a document doesn't involve a massive change in the stylesheet. | |||
4. | Namespace explanation- 2 | ||
Namespaces are identified with URIs that don't have to point to anything. They are used to differentiate between XML element names. The classic example is an element type of 'title'. In your document it might mean book title, and in mine it might mean job title. If we want to avoid confusion we need to bind your 'title' elements to one URI and mine to another. The nice backward-compatible way of doing this in XML is to use a special kind of attribute called a namespace declaration to either establish a default namespace URI for the element and its descendant elements, or to associate a namespace URI with a prefix that can then be tacked on to the beginning of an element name. So let's say you have an element called 'for-each' and you want your XSL processor to know that this is an XSLT instruction, not just something you happened to call 'for-each'. The processor, if it supports XSLT, will know that elements associated with the namespace URI 'http://www.w3.org/1999/XSL/Transform' are XSLT instructions and will process them appropriately. The typical way to designate the 'for-each' element as an XSLT instruction is to first bind the prefix 'xsl' (or any other prefix) to the XSLT namespace URI, and then tack that on the element name, like this: <xsl:for-each xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> The magic is not in the placement of the xmlns:xsl (well, for the most part, anyway), nor in the choice of 'xsl' as the prefix, nor in the fact that a prefix was used at all; it is merely the fact that this particular element is associated with the URI 'http://www.w3.org/1999/XSL/Transform'. If the XSL processor only recognizes a certain other namespace URI as being special, it will treat your xsl:whatever element as being just an ordinary element, which in the world of XSL is interpreted as a 'literal result element' you want copied to the result tree. | |||
5. | What exactly does xmlns do | ||
it declares the xml namespace (hence xmlns) which has name the URL http://www.w3.org/1999/XSL/Transform is to be associated with elements and attributes that have the prefix xsl: You could just as well have <jha:stylesheet xmlns:jha="http://www.w3.org/1999/XSL/Tranform" version="1.0"> and then use <jha:apply-templates etc, the XSL engine would treat this exactly the same as a stylesheet using xsl:. > Does the proper execution of the styleseet depend on the specified url > being up and running? No, it is just a name. > Does the xsl processor download something from this site? No. The correct namespace does matter in that it uniquely identifies the xml file as being XSL rather than some other form of XML. So if you use the correct URL your stylesheet works, if you use the wrong one, it doesn't. | |||
6. | Understanding xsl namespace | ||
> Basically, is it right that the result contains a definition > for both the default prefix AND the xsl prefix? > > <xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' > version="1.0"> > <xsl:output method="xml" indent="yes"/> > <xsl:namespace-alias stylesheet-prefix="#default" > result-prefix="xsl"/> > > <xsl:template match="/"> > <stylesheet version="1.0"/> > </xsl:template> > > </xsl:stylesheet> The <stylesheet> element has an expanded name of the form (local-part:"stylesheet", uri:""). It has three namespace nodes, namely: 1) "xml" = "http://whatever-the-xml-namespace-is" 2) "xsl" = "http://www.w3.org/1999/XSL/Transform" 3) "" = "" The uri of the expanded name, and the three URIs of the namespace nodes, are all "literal namespace URIs". The spec says that any literal namespace URI corresponding to the stylesheet prefix ("") is changed to the URI corresponding to the result-prefix (http://www.w3.org/1999/XSL/Transform). So after applying the alias: the expanded name of the stylesheet element is (local-part: "stylesheet", uri: "http://www.w3.org/1999/XSL/Transform") and the three namespace nodes are: 1) "xml" = "http://whatever-the-xml-namespace-is" 2) "xsl" = "http://www.w3.org/1999/XSL/Transform" 3) "" = "http://www.w3.org/1999/XSL/Transform" Now we copy the literal result element to the result tree. The spec says that all namespace nodes will be copied except those having the namespace http://www.w3.org/1999/XSL/Transform, which would exclude (2) and (3). However, the spec is unclear what happens if a namespace that is excluded under these rules is actually in use. James Clark's response is that this is covered by section 16.1: (a) the output must be well-formed XML that satisfies the namespaces recommendation, and (b) the new tree may contain namespace nodes that were not present in the result tree. It would be possible to satisfy these conditions by outputting namespace (3) but not (2). However, Saxon outputs both: it retains any namespace node for a namespace that is actually in use. There is nothing in the spec to prohibit this, in fact there is nothing to stop arbitrary namespace declarations being invented at the serialization stage. The XSLT 1.1 draft tightens this up. Section 3.5 describes the conditions under which namespace nodes may be added to the result tree (they are now added to the tree, not added at serialization time). It still leaves the details a little implementation dependent, but it says the implementation is allowed to add both (2) and (3) above, under the rule that the namespace URI is that of the parent element. So I think Saxon's behavior is correct under both XSLT 1.0 and 1.1; but omitting namespace (2) would also be correct. | |||
7. | Namespace axis question | ||
<template match="//city"> would match all city elements from the xsl namespace. This is not what is wanted. All you need do is declare the namespaces that appear in your source in your stylesheet, with perhaps differing prefixes. Say city is in the namespace "urn:schemas-biztalk.org:your-namespace/purchaseorder.xml" so if you declare that namespace to be prefix x: in your stylesheet then what you want is <template match="//x:city">Found a city If you really don't care about the second namespace in your source document then.... XSL does not let you wildcard on namespaces, so you can not do *:city however you can get the same effect by wildcarding on all element nodes and then filtering on local-name <template match="//*[local-name(.)='city']" >Found a city | |||
8. | Which namespace should I use for XSL | ||
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/XSL/Transform/1.0" xmlns=" > http://www.w3.org/TR/REC-html40"> > > Is there something that I am missing from the XSL declaration?? You're using the XSLT namespace URI that was effective in the 21 Apr 1999, 09 Jul 1999, 13 Aug 1999 working drafts of XSLT 1.0. The 08 Oct 1999 proposed recommendation changed the URI to "http://www.w3.org/1999/XSL/Transform" and added the version attribute to xsl:stylesheet. This was also adopted by the final recommendation dated 16 Nov 1999. You want <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns="http://www.w3.org/TR/REC-html40"> (although the HTML namespace there is not really needed). | |||
9. | XSLT namespace | ||
> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/TR/WD-xsl"> This is the namespace for Microsoft's implementation of XSL which was based on the December 1998 working draft of the XSL specification (the last version before IE5 went production). > <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> This is the official XSLT 1.0 Recommendation namespace supported by XSLT 1.0-compliant processors like: -> Apache's "xalan" -> Microsoft's "msxsl3" (July 2000 Beta is latest version) -> Oracle's "oraxsl" -> Michael Kay's "saxon" -> James Clark's "xt" To use XSLT 1.0 Recommendation stylesheets with IE5 you need to download Microsoft's MSXSL3 version from MSDN and run the script provided that substitutes this newer XSLT 1.0 compliant processor for the default one that ships with IE 5.0 and IE5.5 It might be simpler for you to use one of the above XSLT processors from the command line to do: $ oraxsl emp.xml emp.xsl to see the transformed results. | |||
10. | XT Question -- Output always equals input | ||
If the output is always a copy of the stylesheet then most likely you have the wrong namespace so that the stylesheet is taken as a literal result template, with no xsl instructions. | |||
11. | How do I set the namespace correctly | ||
Usual way is: <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> You don't have to use the xsl: prefix, but most people do, but the namespace URI has to be _exactly_ that, with (eg) capital T. | |||
12. | Explain the XSLT namespace URI change - Oct 1999 | ||
> I note the change in the XSLT namespace URI from > http://www.w3.org/XSL/Transform/1.0 > to > http://www.w3.org/1999/XSL/Transform > I'm glad to see the version number go into an attribute, > and I note that the PR says that 1999 indicates the year > the W3C allotted the namespace > <http://www.w3.org/TR/xslt#xslt-namespace. > Does this also mean that http://www.w3.org/2000/XSL/Transform > is a valid and completely distinct namespace? It would be a completely distinct namespace. > Or does it imply there is a > connection between all the namespaces > http://www.w3.org/*/XSL/Transform? No connection. > If version 1.1 is released in 2000 will the namespace URI change, or > will XSLT's namespace URI retain 1999 forever? 1.1 would use the same namespace URI (i.e. using 1999 rather than 2000), except in the unlikely event that there were changes so drastic that XSLT 1.0 processors would be able to do nothing useful with 1.1 stylesheets. > Apart from preserving a bit of history, does having the year in the > namespace serve a function? The W3C seems to believe that it assists them in the long term management of the www.w3.org site. It is the W3C not the XSL WG that is responsible for the choice of namespace URI. My personal opinion is that it's rather confusing. > Is this pattern going to be made explicit in a recommendation for all > namespace URIs, or is it merely a suggestion? It appears to be W3C policy for W3C namespace URIs to include at least a year. | |||
13. | Matching namespaces on source documents | ||
My source document is: <?xml version="1.0"?> <document xmlns:test="http://www.test.org"> <test:foo>Element foo with namespace test</test:foo> <document> My stylesheet is: <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Tranform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="/"> <xsl:apply-templates/> </xsl:template> <xsl:template match="test:foo"> <TEST.FOUND/> </xsl:template> <xsl:template match="*" priority="-1.0"> <TEST.MISSED/> </xsl:template> </xsl:stylesheet> I get an error message: test.xsl:13: undefined prefix where line 13 is the tempate trying to match test:foo. Answer: <xsl:template match="test:foo"> This says "this template matches elements with the local name 'foo' that have associated with them a namespace URI that has been assigned to the 'test' prefix in this stylesheet" ... it does *not* say "this template matches elements designated 'test:foo' in the source document". It's kind of confusing because you do have access to the 'test' prefix from the source document, but not in this way. You're matching the namespace URI that 'foo' is assigned to, not 'foo'. It might help if you consider what happens when you don't use prefixes: <?xml version="1.0"?> <document> <foo xmlns="http://www.test.org">hello world</foo> <document> How would you make a template match this foo? match="foo" wouldn't work because the namespace URI is not null. match="foo[namespace-uri(.)='http://www.test.org']" would probably work, but is inconvenient. So, you can declare a prefix-to-namespace-URI assignment in your stylesheet: <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Tranform" version="1.0"> xmlns:mytest="http://www.test.org"> and then use <xsl template match="mytest:foo">. The URIs have to match between the stylesheet and source document. Whether the prefixes do or don't is irrelevant. One of the consequences of this is that there's apparently no way of knowing whether the prefix assignment was done in the stylesheet to aid in processing or if you're intending to have the assignment appear in the result tree. Your XSL processor might be inclined to put the assignment in the output, even if the prefix is not used in the result tree. The result tree would probably have to be reparsed after it is built in order to determine whether the prefix is actually needed. Then you're still left wondering what to do if you wanted the prefix to be declared anyway... | |||
14. | Namespace problems | ||
Q expansion: I have the following XML document: <?xml version="1.0"?> <?xml-stylesheet href="xsl/portal-html.xsl" type="text/xsl"?> <?cocoon-process type="xslt"?> <Portal:Page xmlns:Portal="http://url.com"> <!-- User Specific Information --> <Portal:User> </Portal:User> <Portal:Content> <Portal:Header> Header </Portal:Header> <Portal:Body> Body </Portal:Body> <Portal:Footer> Footer </Portal:Footer> </Portal:Content> etc I want to process the Portal:Content tag only, and use the rest of the information as variables. The following stylesheet fails, the Portal:Content match never occurs. . <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/XSL/Transform/1.0"> <xsl:template match="Portal:Content"> Answer: <xsl:template match="Portal:Content"> should be an error as you haven't declared Portal as a namespace prefix in your stylesheet. Try <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:Portal="http://url.com" version="1.0"> | |||
15. | Templates applied to namespaces | ||
I have an input document that looks like this: <?xml version="1.0" encoding="UTF-8" ?> <ROOTELEMENT xmlns="http://www.somewhere.com/mynamespace"> <ERRORCODE>0</ERRORCODE> <BOOKLIST> <BOOK> etc The particular issue is that it uses the default namespace on its elements but no prefix. I'm having a devil of a time getting a template in the XSLT stylesheet to match up with anything by its name, either with or without a prefix. Everything works fine if I remove the namespace declaration from the input document. However declaring the namespace in the stylesheet, with or without a prefix, doesn't seem to help. Answer: That is the same input document as this: <?xml version="1.0" encoding="UTF-8" ?> <x:ROOTELEMENT xmlns:x="http://www.somewhere.com/mynamespace"> <x:ERRORCODE>0</x:ERRORCODE> <x:BOOKLIST> That is, an XSLT engine sees the same input tree in either case. It is probably simpler to think of the latter syntax rather than the former when writing the stylesheet, even if you know all the actual documents are in the first form. so <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:x="http://www.somewhere.com/mynamespace" > <xsl:template match="x:BOOKLIST"> ... <xsl:for-each select="x:ERRORCODE"> ... | |||
16. | exclude-result-prefixes uses | ||
David puts in the basics.. You could for example use the namespace http://purchasingcenter.com as the namespace for any elements that you have ever or will ever dream up. There does not have to be anything at that address that lists the names, there doesn't have to be anything at the address at all. The point is if that you have an element x then chances are that someone else has same, but if you have an element x in namespace http://purchasingcenter.com then it won't clash with anyone else, and it's up to you to make sure you don't clash with yourself. So a namespace parser never actually uses the URI to fetch anything it is just a unique identifier. All the prefix rubbish is just a hack to get round the fact that <{http://purchasingcenter.com,x}> isn't a legal XML name and it is anyway a pain to type every time. So the real `abstract' name of your element is the pair {http://purchasingcenter.com,x} but when you come to use it in a document you use an (arbitrary) prefix to stand in for the URL <p:x xmlns:p="http://purchasingcenter.com"/> or <q:x xmlns:q="http://purchasingcenter.com"/> or indeed <x xmlns="http://purchasingcenter.com"/> all mean the same thing, which is the element x from the namespace http://purchasingcenter.com There is (currently at least) no notion of validating that the specified namespace is supposed to contain an element called x. You may want to specify that the document validates against a schema or dtd, but that is a slightly different thing. DaveP..What earthly use could they be? DC answers: Actually there _is_ a reason for namespace nodes. Imagine that the input tree had xpath expressions. so there is a <xxxx href="aaa/b:ggg[c:y]"> you can grab hold of that attribute with @href but if you want to make use of it _as an xpath expression_ you need to know what namespace is attatched to the prefix b: at this point in the input document. Note unlike normal matching on attributes and elements it is the _prefixes_ b: and c: that matter here. Ken on using them.... An XSLT processor is allowed to serialize the output with as many namespace declarations it thinks it is going to need. Doing so early on (say in the document element of the result) prevents the need to multiply declare the namespace when used lower down in the hierarchy. It is an acceptable assumption by the processor that any namespace other than XSLT that is declared in the stylesheet is probably going to be needed somewhere in the result ... so XT will automatically emit a declaration in the result for each declaration found in the stylesheet. Often, non-XSLT namespaces are used in stylesheets for XSLT named object identification, or embedded top-level documentation, or embedded data to be processed from the stylesheet, or other issues, so when these facilities are used the stylesheet writer has to declare the namespaces. Hence, using these facilities could very easily produce declarations in the result that will *never* be used in the result. The stylesheet writer can declare to the processor the intention that a namespace found in the stylesheet isn't going to be used in the result, and the processor will assume the writer is telling the truth and not emit a declaration unless it absolutely has to based on the need to serialize a particular result construct using the namespace. If the assertion was true, then the result ends up without the extraneous declarations indicated by the writer. David C adds: literal result elements pick up namespace nodes from ancestors in the stylesheet (as in the example I gave) nodes from input documents copied with copy or copy-of get their namespace nodes from ancestors in the input document. But the result is the same, you often don't want them in the output. Ken continues.. First, here are the sources of all of the files I'm using down below: (1) - an XML source file without namespaces T:\ftemp>type test.xml <?xml version="1.0"?> <doc> <para>First para</para> <para>Second para</para> </doc> (2) - an XML source file with namespaces T:\ftemp>type testns.xml <?xml version="1.0"?> <doc xmlns:ken="ken.com"> <para>First para</para> <para>Second para</para> </doc> (3) - an XSLT stylesheet without namespaces T:\ftemp>type test.xsl <?xml version="1.0"?><!--filename.xsl--> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="/"> <!--root rule--> <result> <xsl:copy-of select="/doc/para"/> </result> </xsl:template> </xsl:stylesheet> (4) - an XSLT stylesheet with a documentation namespace T:\ftemp>type testns.xsl <?xml version="1.0"?><!--filename.xsl--> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:ken="ken.com"> <xsl:output method="xml"/> <ken:hello>test</ken:hello> <xsl:template match="/"> <!--root rule--> <result> <xsl:copy-of select="/doc/para"/> </result> </xsl:template> </xsl:stylesheet> (5) - an XSLT stylesheet with an exclude on a literal result element T:\ftemp>type testnsex.xsl <?xml version="1.0"?><!--filename.xsl--> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:ken="ken.com"> <xsl:output method="xml"/> <ken:hello>test</ken:hello> <xsl:template match="/"> <!--root rule--> <result xsl:exclude-result-prefixes="ken"> <xsl:copy-of select="/doc/para"/> </result> </xsl:template> </xsl:stylesheet> (6) - an XSLT stylesheet with an exclude on the document element of the stylesheet T:\ftemp>type testnsde.xsl <?xml version="1.0"?><!--filename.xsl--> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:ken="ken.com" exclude-result-prefixes="ken"> <xsl:output method="xml"/> <ken:hello>test</ken:hello> <xsl:template match="/"> <!--root rule--> <result> <xsl:copy-of select="/doc/para"/> </result> </xsl:template> </xsl:stylesheet> (7) - an XSLT stylesheet with an exclude on the document element of the stylesheet and using template rules instead of copy-of: T:\ftemp>type testnstr.xsl <?xml version="1.0"?><!--filename.xsl--> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:ken="ken.com" exclude-result-prefixes="ken"> <xsl:output method="xml"/> <ken:hello>test</ken:hello> <xsl:template match="/"> <!--root rule--> <result> <xsl:apply-templates select="/doc/para"/> </result> </xsl:template> <xsl:template match="para"> <para> <xsl:apply-templates/> </para> </xsl:template> </xsl:stylesheet> (8) - an XSLT stylesheet using template rules without any exclude-result-prefixes= <?xml version="1.0"?><!--filename.xsl--> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="/"> <!--root rule--> <result> <xsl:apply-templates select="/doc/para"/> </result> </xsl:template> <xsl:template match="para"> <para> <xsl:apply-templates/> </para> </xsl:template> </xsl:stylesheet> =============8<---------------------- (T1) - Okay, so first no namespaces to show the desired result: T:\ftemp>xt test.xml test.xsl <?xml version="1.0" encoding="utf-8"?> <result><para>First para</para><para>Second para</para></result> (T2) - Introducing the documentation namespace without an exclude produces a result: T:\ftemp>xt test.xml testns.xsl <?xml version="1.0" encoding="utf-8"?> <result xmlns:ken="ken.com"><para>First para</para><para>Second para</para></result> .... where the processor emits a contingent declaration *just in case*. (T3) - Using an exclude-result-prefixes= on the stylesheet document element filters it out (this is as far as I have gone in my book to date, focusing on the use of namespaces in embedded documentation): T:\ftemp>xt test.xml testnsde.xsl <?xml version="1.0" encoding="utf-8"?> <result><para>First para</para><para>Second para</para></result> (T4) - Using an exclude-result-prefixex= on the literal result element isn't recognized for XT (an http://www.jclark.com/xml/xt.html documented limitation, so we shouldn't be expecting it, but that might be the source of some confusion), but does for Saxon: T:\ftemp>xt test.xml testnsex.xsl <?xml version="1.0" encoding="utf-8"?> <result xmlns:ken="ken.com"><para>First para</para><para>Second para</para></result> T:\ftemp>saxon test.xml testnsex.xsl <?xml version="1.0" encoding="utf-8" ?><result><para>First para</para><para>Second para</para></result> (T5) - Now, the source file with the namespace declaration on the document element is processed with both types of exclude-result-prefixes= and while the document element of the result doesn't have the namespace declaration, the descendants do: T:\ftemp>saxon testns.xml testnsex.xsl <?xml version="1.0" encoding="utf-8" ?><result><para xmlns:ken="ken.com">First para</para><para xmlns:ken="ken.com">Second para</para></result> T:\ftemp>xt testns.xml testnsde.xsl <?xml version="1.0" encoding="utf-8"?> <result><para xmlns:ken="ken.com">First para</para><para xmlns:ken="ken.com">Second para</para></result> T:\ftemp>saxon testns.xml testnsde.xsl <?xml version="1.0" encoding="utf-8" ?><result><para xmlns:ken="ken.com">First para</para><para xmlns:ken="ken.com">Second para</para></result> At first one might not expect the above behaviour in Test5 ... if none of my result tree descendents utilize the namespace, then why would each one get a namespace declaration? It has nothing to do with the exclude-result-prefixes= because the scope of that attribute is in the stylesheet. It is because of the use of <xsl:copy-of> and the first sentence of section 5.4 of the XPath 1.0 Recommendation:
Thus, the <para> elements of the source node tree each have an invisible namespace node for the "ken" namespace that we cannot see. Because I used <xsl:copy-of>, I copied *all* of the nodes of the source tree (including the invisible namespace nodes) to the result tree ... hence, the processor is obliged to put out the namespace declaration for the namespace nodes found in the result tree. (T6) - So, to avoid using <xsl:copy-of> I then used the stylesheet that uses template rules instead: T:\ftemp>xt testns.xml testnstr.xsl <?xml version="1.0" encoding="utf-8"?> <result><para>First para</para><para>Second para</para></result> .... and sure enough, since my stylesheet isn't adding any namespace nodes to the result tree, there are no namespace declarations in the result. (T7) - The last test looks at *not* using exclude-result-prefixes= but still having namespaces in the source to illustrate there was never any need for exclude-result-prefixes= to handle source issues: T:\ftemp>xt testns.xml testtr.xsl <?xml version="1.0" encoding="utf-8"?> <result><para>First para</para><para>Second para</para></result> ... and note that since I didn't copy any of the invisible (or visible) namespace nodes, the end result doesn't need any namespace declarations. There is the evidence supporting the Recommendations ... and it seems the processors here obey the rules where they are documented to obey the rules. Perhaps the key that was missing was the knowledge of the hidden namespace nodes implied by the scope of ancestral namespace declarations. I will put all of the above into the next edition of our book, with some of the sentences fleshed out and perhaps rearranged as I think about the best way to present it. I don't think I've missed any of the combinations or the explanations ... if something still isn't said about namespace processing, please post your question. | |||
17. | About the xmlns:xsl attribute | ||
> Could anyone explain to me the meaning and the different possible values > of the xmlns:xls attribute ? A namespace gives an element a unique name. If you specify http://www.w3.org/1999/XSL/Transform then it means that the elements come from the XSLT language. If you specify http://www.w3.org/TR/WD-xsl then it means that the elements come from the-language-known-as-xsl-in-ie5 this is an entirely different language and it is not possible to have one stylesheet that works both on an xslt system and on ie5 in its default setup. | |||
18. | Namespaces and IE5 | ||
(ednote: this is dated 4 2000, hence will date as MS updates) > The damn thing has an http:// in front of it tho'! Is that really needed > if the address is designed never to be actually accessed? the claim is that using uri's guarantees global uniqueness, that is it is clear that I shouldn't define a namespace http://www.es.co.nz. While technically this is true. It has probably generated more confusion than any other xml feature. > Would it have been correct for Microsoft, when it published its own > implimentation, to have instead specified > xmlns:xsl="http://www.microsoft.com/1999/XSL/Transform" and saved a lot > of headaches? well even as is, they have a different namespace but that doesn't really help, people get confused anyway. Partly the problem is that the documentation for the microsoft variant (which was rather good I thought when I tried to use it) was rather quiet about which features were in the w3c draft (at that time, end of 98) and which were microsoft extensions. so the problem isn't so much technical as one of perception, what people `expect' to find in xsl. as noted above, the namespace ie5 used wasn't a microsoft special namespace it was (at the time) the namespace used in the w3c draft, but since then xslt changed drastically but of course microsoft had by then shipped a few dozen copies of IE5. So it isn't really that in this case microsoft were so bad, just overtaken by events. By being `out of line' I am being a bit unfair to microsoft, but a) I suspect that they are big enough to take a bit of leg pulling, and b) it helps to stress to people that it isn't just a simple matter of `changing namespaces'. If they are used to the IE5 system then they need to either keep to that or to quite radically re-write their stylesheets. Microsoft do supply some tools to help with the conversion, but still unlikely to be fuly automatic on all but the simplest stylesheets. The top level element may declare any number of namespaces, there is no way for a system to know in general which namespace is supposed to be the xsl-variant that should run the stylesheet. If the XSL namespace isn't declared then it should raise an error. (a higher level filter could look at the sheet and decide which processor to pass it to based on some extra information about the range of processors supported, but once the file is passed to an XSL processor, it had better be XSL. The prefix (if there is one) is arbitrary. All of the following are legal syntax for the start of an XSL stylesheet. The _only_ thing that matters, both in the stylesheet and in the input document is the full `expanded' name of an element name, which consists of a pair, uri and local name. The prefix is just a syntax trick. In particular, as you see, XSL places no special significance on the xsl: prefix. David <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" > <xsl:template..... <stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0" > <template..... <css:stylesheet xmlns:css="http://www.w3.org/1999/XSL/Transform" version="1.0" > <css:template..... David Marston adds I think that there is a worthwhile middle-ground view, even if resolving through the URI is never implemented. First of all, keep in mind that we can expect to see many namespaces co-existing in XSLT stylesheets as they will be used in real-world e-business(TM) applications. For each namespace, you will have the question (in colloquial English) "Says who?" that applies to the namespace. For example, when my stylesheet processes an element called "auction:bid", I need to know whether that "auction" prefix is as defined by eBay, steelbrokers.com, or any of dozens of other companies and consortia that may define a set of tags relating to auctions. If I could say something equivalent to your suggested "XSLT 1.0" declaration, that would mean that all those organizations had agreed on a single vocabulary, or at least that they had agreed on a set of disambiguated names that would apply to the different variations on the auction tag-set. By requiring a URI, we are imposing a practical amount of discipline, yet tapping into a naming scheme (domain names) that is already disambiguated across the whole world. If we try to just put in the name of the standard, then we just put the "Says who?" question at one level of indirection, rather than truly resolving it. Each domain name owner (like w3c.org) is still responsible for associating individual URIs with individual namespaces, so that the rest of us can use those URIs in exchanging data. | |||
19. | XSL to XSL How to get an XSL script to output XSL elements | ||
You can take advantage of the built-in XSLT 1.0 feature called <xsl:namespace-alias> to do the following: <x:stylesheet xmlns:x="http://www.w3.org/1999/XSL/Transform" xmlns:xsl="anything" version="1.0"> <x:output method="xml" indent="yes"/> <x:namespace-alias stylesheet-prefix="xsl" result-prefix="x"/> <x:template match="/"> <xsl:stylesheet version="1.0"> <xsl:template match="/"> <xsl:value-of select="foo"/> </xsl:template> </xsl:stylesheet> </x:template> </x:stylesheet> This outputs the valid XSLT stylesheet: <?xml version = '1.0' encoding = 'UTF-8'?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <xsl:value-of select="foo"/> </xsl:template> </xsl:stylesheet> I tried this with the Oracle XSLT Processor release 2.0.2.7, but any XSLT-REC-compliant processor should behave similarly. I just also tried Saxon 5.2, XT which work as well. | |||
20. | Selecting elements regardless of namespace | ||
Write select="//*[local-name()='apple']" | |||
21. | Result tree namespaces | ||
> 1. Are you supposed to output a namespace declaration for each namespace node XSLT gives you no way of creating a namespace declaration. You just put element and attribute nodes into the result tree. Each of these has a (possibly null) namespace name and a local name. When the result tree is linearised, the processor will add whatever namespace declarations are needed to ensure that the nodes end up in the right namespace if the linerised result is reparsed as an XMl document. In addition element nodes will have attatched namespace declaration nodes, and if the element is copied to the result this will also generate namespace declarations unless this is suppressed (see 3) > 2. Does it matter what prefixes are used (this includes using the > default namespace)? No > 3. Is there a convention on removing unused namespaces? declare namespaces you have used in the source or stylesheet but don't use in the output using exclude-result-prefixes, thenthe processor should not add any declarations for those. | |||
22. | Namespace handling | ||
With this source document <x> <xsd:schema xmlns:xsd="http://www.w3.org/1999/XMLSchema"> <xsd:element name="swissBankAccountNo" type="xsd:string"/> </xsd:schema> <schema xmlns="http://www.w3.org/1999/XMLSchema"> <element name="luxembourgBankAccountNo" type="string"/> </schema> <xsd:schema xmlns:xsd="http://www.w3.org/1999/XMLSchema"> <xsd:element name="englishBankAccountNo" type="xsd:string2"/> </xsd:schema> <schema xmlns="http://www.w3.org/1999/XMLSchema"> <element name="frenchBankAccountNo" type="string2"/> </schema> <xsd:schema xmlns:xsd="file:/notschema"> <xsd:element name="swissBankAccountNo" type="xsd:string"/> </xsd:schema> <schema xmlns="file:/notschema"> <element name="luxembourgBankAccountNo" type="string"/> </schema> </x> This stylesheet <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:xsd="http://www.w3.org/1999/XMLSchema" > <xsl:strip-space elements="*"/> <xsl:output method="text" /> <xsl:template match="xsd:element"> Element name <xsl:value-of select="@name"/> type=<xsl:text/> <xsl:variable name="p"> <xsl:if test="contains(@type,':')"> <xsl:value-of select="substring-before(@type,':')"/> </xsl:if> </xsl:variable> <xsl:variable name="n"> <xsl:choose> <xsl:when test="contains(@type,':')"> <xsl:value-of select="substring-after(@type,':')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="@type"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="ns" select="namespace::*[name()=$p]"/> <xsl:text>{</xsl:text> <xsl:value-of select="$ns"/> <xsl:text>}</xsl:text> <xsl:value-of select="$n"/> Elements with the same type are: <xsl:for-each select="//xsd:element"> <xsl:variable name="p2"> <xsl:if test="contains(@type,':')"> <xsl:value-of select="substring-before(@type,':')"/> </xsl:if> </xsl:variable> <xsl:variable name="n2"> <xsl:choose> <xsl:when test="contains(@type,':')"> <xsl:value-of select="substring-after(@type,':')"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="@type"/> </xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="ns2" select="namespace::*[name()=$p2]"/> <xsl:if test="$n=$n2 and $ns=$ns2"> <xsl:value-of select="@name"/><xsl:text> </xsl:text> </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet> Produces this output: Element name swissBankAccountNo type={http://www.w3.org/1999/XMLSchema}string Elements with the same type are: swissBankAccountNo luxembourgBankAccountNo Element name luxembourgBankAccountNo type={http://www.w3.org/1999/XMLSchema}string Elements with the same type are: swissBankAccountNo luxembourgBankAccountNo Element name englishBankAccountNo type={http://www.w3.org/1999/XMLSchema}string2 Elements with the same type are: englishBankAccountNo frenchBankAccountNo Element name frenchBankAccountNo type={http://www.w3.org/1999/XMLSchema}string2 Elements with the same type are: englishBankAccountNo frenchBankAccountNo | |||
23. | Matching nodes in the default namespace | ||
Here's the XML: <?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="test.xsl"?> <!--catalog last updated 2000-11-01--> <catalog xmlns="http://www.example.com/catalog/"> <book id="bk101"> <author>Some author</author> <title>Some Title</title> <genre>Some genre</genre> <price>Some price</price> <publish_date>Some date</publish_date> <description>Some description</description> </book> </catalog> What's the magic word that enables you to do a match/select on an element in an explicitly URI'd default namespace? Answer: so that is the same input to XSL as <c:catalog xmlns:c="http://www.example.com/catalog/"> <c:book id="bk101"> <c:author>Some author</c:author> <c:title>Some Title</c:title> And here's test.xsl: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/REC-html40" > .... <xsl:template match="catalog"> <xsl:apply-templates/> </xsl:template> and that matches an element called catalog in the null namespace (or as the namespace rec calls it, not in a namespace at all) You want to match <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/REC-html40" xmlns:c="http://www.example.com/catalog/" exclude-result-prefixes="c"> .... <xsl:template match="c:catalog"> <xsl:apply-templates/> </xsl:template> even if your source file is using "http://www.example.com/catalog/" as the default namespace. Evan Lenz expands: You have to include a corresponding namespace declaration in your stylesheet, binding it to a prefix of your choice. Then, in your match patterns, include that prefix. Your stylesheet is written to match elements that are not in a namespace. It matches nothing because all of the source document's elements *are* in a namespace. Below is the corrected stylesheet: <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/REC-html40" xmlns:cat="http://www.example.com/catalog/"> <xsl:template match="/"> <html> <title>Book catalog</title> <body> <table border="1"> <tr> <th>Author</th> <th>Title</th> <th>Genre</th> <th>Price</th> <th>Pub Date</th> <th>Description</th> </tr> <xsl:apply-templates select="*"/> </table> </body> </html> </xsl:template> <xsl:template match="cat:catalog"> <xsl:apply-templates/> </xsl:template> <!-- Suppress individual children of <book>, and built-in processing of all text nodes --> <xsl:template match="*|text()"/> <xsl:template match="cat:book"> <tr> <td><xsl:value-of select="cat:author"/></td> <td><cite><xsl:value-of select="cat:title"/></cite></td> <td><xsl:value-of select="cat:genre"/></td> <td><xsl:value-of select="cat:price"/></td> <td><xsl:value-of select="cat:publish_date"/></td> <td><xsl:value-of select="cat:description"/></td> </tr> </xsl:template> </xsl:stylesheet> If your stylesheet doesn't include a namespace declaration for a namespace that's in the source document, there is no way you'll be able to explicitly match nodes in that namespace (apart from using a wildcard, such as *). Remember, whether the source document uses prefixes or not is completely immaterial in XSLT. Forget about prefixes and think only about fully qualified names which consist of a local name and a namespace URI. How that fully-qualified name is represented, whether by a default namespace or a namespace prefix, is immaterial. | |||
24. | xml:space namespace prefix | ||
> (I did notice that I'm looking for xml:space with the prefix "xml". I can't > tell from XML namespaces what's supposed to happen if you bind a different > prefix to the namespace http://www.w3.org/XML/1998/namespace. Anyone know > the answer?) I asked on xml-dev. (Paraphrasing) Tim Bray said it wouldn't be wrong to recognize foo:space as xml:space, if the namespace were the same, but only when the qname is xml:space can it be counted upon as having the special meaning. | |||
25. | Mixing Namespaces | ||
>Can someone send me some examples about namespaces in xsl templates ? The purpose of namespaces is to mix two XML vocabularies within the same document. A classic example would be if you were embedding some MathML within an HTML document: all the HTML elements would be in the HTML namespace and all the MathML elements would be in the MathML namespace. If you are after namespaces, then your XML source has to define and use them as well as your XSLT. So you might have: <doc xmlns:page="page-namespace" xmlns:content="content-namespace"> ... <page:title>Title in the 'page' namespace</page:title> <content:title>Title in the 'content' namespace</content:title> ... </doc> Within your XSLT, you need to define the same namespaces as those that appear within your XML source, as well as the XSLT namespace itself. [You don't have to use the same prefixes as in the XML source, though sometimes it makes things easier to understand if you do.] The namespaces are usually defined by putting namespace declarations on the xsl:stylesheet start tag: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:page="page-namespace" xmlns:content="content-namespace"> Then, within your stylesheet, you refer to any elements within that namespace using the namespace prefix. So, to have different templates for page:title and content:title, you'd use: <xsl:template match="page:title"> <!-- matches 'title' elements in 'page' namespace --> ... </xsl:template> <xsl:template match="content:title"> <!-- matches 'title' elements in 'content' namespace --> ... </xsl:template> And similarly for any select expressions or tests that you use: all the XPaths will use the qualified (i.e. prefixed) names. | |||
26. | template pattern does not get matched properly with xmlns declaration | ||
> However after I removed xmlns declaration(i.e xmlns=" > http://www.ipdr.org/namespaces/ipdr" part) from IPDRDoc element > in test.xml, everything is just working fine. > I have no idea what's wrong with > the xml/xsl test files. The fact that taking the default namespace declaration out changed things indicates that it's a namespace issue. Because of the default namespace declaration, all the elements that don't have a prefix are placed in the 'http://www.ipdr.org/namespaces/ipdr' (IPDR) namespace. Now, in your stylesheet you match against IPDRDoc elements but don't specify a prefix for them. If you don't specify a prefix when you're matching/selecting an element, then it assumes you mean an element in the *null* namespace. The IPDRDoc element in the IPDR namespace isn't an IPDRDoc element in the null namespace, so it doesn't match that template, and the built in templates are used all the way through. To get around this, you need to declare the IPDR namespace (with a prefix) within the XSLT stylesheet. Something like: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ipdr="http://www.ipdr.org/namespaces/ipdr"> ... </xsl:stylesheet> Then, whenever you want to refer to an element in that namespace, you have to use the prefix you've assigned to it (ipdr in this case) within the name. For example, the match pattern for the template should be: <xsl:template match="ipdr:IPDRDoc"> ... </xsl:template> | |||
27. | Null and empty namespace | ||
> so how can you distinguish the null namespace from > the namespace ""? > Is <p:a xmlns:p=""/> valid according to the > namespaces rec? I can't actually see any reason why not. Actually, it is invalid: <quote href="http://www.w3.org/TR/1999/REC-xml-names-19990114/#dt-prefix"> [Definition:] If the attribute name matches PrefixedAttName, then the NCName gives the namespace prefix, used to associate element and attribute names with the namespace name in the attribute value in the scope of the element to which the declaration is attached. <emphasis_added>In such declarations, the namespace name may not be empty.</emphasis_added> </quote> There should be no distinction between "null namespace URI", "not in a namespace", empty URI, empty string, "", whatever. It's all the same thing. This means that any element or attribute name that has a prefix *is* in a namespace, and, to be in a namespace means to have a non-empty URI to identify the namespace. | |||
28. | Creating an attribute name of xmlns:xyz | ||
> I an writing an xsl file which creates another xsl file. It works fine > except I need teh original xsl file to create the following statement: > > <stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" > xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0" version="1.0"> > > To do so, the following xsl statements are used: > > <element name="stylesheet"> > <attribute > name="xmlns">http://www.w3.org/1999/XSL/Transform > </attribute> > <attribute name="xmlns:xfa" > namespace="http://www.xfa.org/schema/xfa-data/1.0"> > http://www.xfa.org/schema/xfa-data/1.0 > </attribute> > <attribute name="version">1.0</attribute> > ... > </element> Namespace declarations (which are what the xmlns:... attributes are) aren't treated as attributes in XSLT. The purpose of a namespace declaration is to associate a particular prefix (e.g. 'xfa') with a particular namespace URI (e.g. http://www.xmfa.org/schema/xfa-data/1.0) in a particular document. Within a node tree, there are no namespace declarations. Instead, every element within the scope of a namespace declaration has a namespace *node* on it, representing the mapping between the prefix and the namespace URI. XSLT works on these namespace nodes - the namespace declarations themselves don't exist in a node tree. This works on the source XML (you can't select a namespace declaration with the attribute axis) and on the result XML (you can't create a namespace declaration as an attribute, which is what you're attempting to do above). Instead, namespace declarations are created automatically when a node tree is serialised into some output. When an element is written, if it has a namespace node on it but there's not been a namespace declaration that matches that namespace node, then the serialiser writes a namespace declaration on that element. So what you are really trying to do is to create a 'stylesheet' element in the result tree that has (at least) two namespace nodes on it: the XSLT namespace and the XFA namespace. And you'd like the XSLT namespace to be the default namespace (though logically it doesn't matter - it's just a case of which prefix is used for it). Now consider the node tree for the XSLT stylesheet itself. It will have things like xsl:template element nodes, namespace nodes for the XSLT namespace and so on. If you declare a namespace at the top of your stylesheet, then all the elements in the stylesheet node tree will have namespace nodes for that namespace. The rules for what namespace nodes are put on an element in the result tree depend on how you create the element. If you create the element with a literal result element, then most namespace nodes that are present on that literal result element are put in the result tree. If you use xsl:element, then the only extra namespace node that can be created is one that you use to identify the namespace of the element itself. [It's only *most* namespace nodes because some namespace nodes, namely the XSLT namespace node and any with prefixes given in the extension-element-prefixes or exclude-result-prefixes attributes, aren't put in the result tree. This has implications I'll come on to later.] So, there are two ways to get the XFA namespace node onto the element that you're creating. You can declare it for the stylesheet as a whole: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0"> ... <stylesheet version="1.0"> ... </stylesheet> ... </xsl:stylesheet> or you can declare it specifically for the stylesheet element that you're creating: <stylesheet version="1.0" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0"> ... </stylesheet> Remember that this is *not* the same as creating an attribute on the 'stylesheet' element - the xmlns:xfa attribute is a namespace declaration, used to create a load of *namespace nodes* on the 'stylesheet' element and all its element descendants in the *stylesheet tree* (including any XSLT instructions that it holds). Because the 'stylesheet' element in the stylesheet node tree has this namespace node, it will be copied with it into the result tree, so the 'stylesheet' element in the result tree (or one of its ancestors) will have an equivalent namespace declaration on it. So that's the *easy* one! ;) Now, when we come to the XSLT namespace it's a bit more tricky because the XSLT namespace nodes aren't included within the result tree 'cos most of the time you don't care about them. If they *were* included, then most result documents would have XSLT namespace declarations all over the place - really annoying! Instead, there's a trick specifically designed to help you create stylesheets that create stylesheets: xsl:namespace-alias. xsl:namespace-alias allows you to say that the namespace URI of a particular namespace in the result tree should be replaced with another namespace URI. What you need to do is declare a namespace with a made-up namespace URI, for example http://www.w3.org/1999/XSL/TransformAlias, that you use as a placeholder for the XSLT namespace URI that you want to use. Then you can place this made-up namespace on any element in the same way as indicated above, e.g.: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0" xmlns="http://www.w3.org/1999/XSL/TransformAlias"> ... <stylesheet version="1.0"> ... </stylesheet> ... </xsl:stylesheet> Now, the 'stylesheet' literal result element's namespace nodes will include the alias for the XSLT namespace, as well as the XFA namespace node. In fact, because the 'stylesheet' element has no prefix, it will be placed in the default namespace, specified as "http://www.w3.org/1999/XSL/TransformAlias". You then use xsl:namespace-alias to tell the XSLT processor that the namespace URI "http://www.w3.org/1999/XSL/TransformAlias" (the default namespace) should be mapped to the namespace URI "http://www.w3.org/1999/XSL/Transform" in the final result. You refer to each of these namespaces using their prefix, or '#default' if it's the default namespace: <xsl:namespace-alias stylesheet-prefix="#default" result-prefix="xsl" /> The other approach would be to state that the 'stylesheet' element is in the XSLT namespace by defining it with the xsl:element element: <xsl:element name="stylesheet" namespace="http://www.w3.org/1999/XSL/Transform"> <xsl:attribute name="version">1.0</xsl:attribute> ... </xsl:element> This is quite a bit longer, especially because it means you have to define the other attributes using xsl:attribute elements and so on. | |||
29. | Finding namespaces | ||
> How do I find out -- in the most efficient way -- what namespaces > have been mapped using xmlns? I want to known in the document node > so that I can apply some text in the beginning of the result document. You can do select="//namespace::*" but the list will contain many duplicates. These are not easy to eliminate using the normal techniques because namespace nodes are not on the preceding axis and cannot be keyed (because they cannot be matched in a pattern). With Saxon you can do saxon:distinct(//namespace::*) If you are only interested in namespaces that are actually used in the name of an element, you can do Muenchian grouping on the full set of element nodes (//*) with a grouping key of namespace-uri(); you can add those used in attribute names by using (//*|//@*). | |||
30. | Copy namespace definition to the result tree | ||
> Is there no way I can output the element as > <xsd:schema xmlns:xsd="http://www.w3.org/1999/XMLSchema"> No. If there is a namespace node on that element in the result tree, normaly the output serialiser will not output a namespace declaration if there is already a declaration for that namespace in scope. You have no direct control over this linearisation, no more than you can control whetehr " or ' is used to quote attribute values. | |||
31. | namespace alias use | ||
namespace transform issue My code looks like this <?xml version="1.0" encoding="UTF-8"?> <alex:stylesheet xmlns:xsl="http://www.alex.com" xmlns:larry="http://www.w3.org/1999/XSL/Transform" version="1.0"> <alex:namespace-alias stylesheet-prefix="alex" result-prefix="xsl"/> you have that backwards! You are writing an xsl stylesheet, and you are using alex: as the prefix for XSL instructions so you need to make alex the namespace http://www.w3.org/1999/XSL/Transform. Otherwise the XSL processor won't see <alex:stylesheet as the start of the stylesheet but as a literal result element. Having a literal result element at th etop is legal in the simplified syntax, so long as you have an xsl:version attribute, > Xalan refuses to transform unless http://alex.com is replaced with > http://www.w3.org/1999/XSL/Transform. Well without that, it can't know that you intended this to be a stylesheet. > I thought this URL had nothing to do with transforming, On the contrary, it has everything to with transforming. Elements in that namespace are XSLT instructions for making transformations, elements in any other namespace are just copied to the output. | |||
32. | Attributes in a namespace | ||
I now have the following approaches to testing whether the attribute context node's name is a particular namespaced name: @*[local-name()='foo' namespace-uri()='&xyzURI;'] @*[generate-id()=generate-id(../@xyz:foo)] @*[count(.|../@xyz:foo)=count(../@xyz:foo)] (Thanks Ken) The first is definitely the most intuitive, though it's still messy in that it requires you to explicitly include the namespace URI, regardless of whether a corresponding prefix binding is in scope. What I naturally tried was: @*[self::xyz:foo] But that doesn't work, because the self axis will *never* select attributes except with self::node(), being that *element* is the principal node type of the self axis and there is no attribute() node test (not that that would be useful). Joe English suggested attribute::xyz:foo or @xyz:foo work? To which David Carlisle responded: yes but the real problem is that you can't negate, you can do *[not(self::foo)] to select all elements but foo, but you can't do @*[not(self::foo)] well you can, but it is the same as @*. | |||
33. | How to output a namespace in the declaration | ||
I have a stylesheet A that is outputting stylesheet B (using xsl:namespace-alias'ing). Stylesheet B will be matching elements from namespace N so it must have a namespace declaration for N. But the problem is that namespace N is not known at the time I construct A and does not appear in the input to A. I would like to pass the prefix and URI for N to stylesheet A as top-level parameters. How can I get stylesheet A to generate a namespace declaration in B from the parameters? Something like this, maybe? A.xsl: ==== <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias"> <xsl:param name="ns" select="'anyns'"/> <xsl:param name="ns-uri" select="'http://www.whatever.uri'"/> <xsl:output method="xml"/> <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/> <xsl:template match="/"> <xsl:text disable-output-escaping="yes"> <!DOCTYPE axsl:stylesheet [ <!ATTLIST axsl:stylesheet xmlns:</xsl:text> <xsl:value-of select="$ns"/> <xsl:text> CDATA #FIXED "</xsl:text> <xsl:value-of select="$ns-uri"/> <xsl:text>"
</xsl:text> <xsl:text>xmlns</xsl:text> <xsl:text> CDATA #FIXED "</xsl:text> <xsl:value-of select="$ns-uri"/> <xsl:text>"</xsl:text> <xsl:text disable-output-escaping="yes"> >]> </xsl:text> <axsl:stylesheet version="1.0"> <axsl:template match="{$ns}:*"> <axsl:element name="{$ns}:node"/> </axsl:template> </axsl:stylesheet> </xsl:template> </xsl:stylesheet> With Saxon 6.3 (YMMV with other processors in terms of escaping and line-breaking) this generates (reformatted for aesthetic purposes only): B.xsl: ==== <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE axsl:stylesheet [ <!ATTLIST axsl:stylesheet xmlns:anyns CDATA #FIXED "http://www.whatever.uri" xmlns CDATA #FIXED "http://www.whatever.uri" >]> <axsl:stylesheet xmlns:axsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <axsl:template match="anyns:*"> <axsl:element name="anyns:node"/> </axsl:template> </axsl:stylesheet> If you feed B.xsl this test.xml: ====== <anyns:rootNode xmlns:anyns="http://www.whatever.uri"/> You get back out.xml: ====== <?xml version="1.0" encoding="utf-8"?> <anyns:node xmlns:anyns="http://www.whatever.uri"/> | |||
34. | Creating namespace declarations | ||
(June 2001)
You are right. The requirement is recognized in the published XSLT 2.0 requirements. You can get close in XSLT 1.0 (+errata) by creating an external document dd.xml <doc xmlns:ns="urn:namespace/> and doing <example> <xsl:copy-of select="document('dd.xml')/doc/namespace::ns"/> <xsl:attribute name="value">ns:something</xsl:attribute> </example> But it's probably simpler to create a dummy attribute in the required namespace. | |||
35. | How to output a xmlns:prefix attribute | ||
Was this what you were after? Anyhow, note that you Note that you can't do <xsd:schema targetNamespace="http://whatever.com"> with Saxon 6.4.2, it throws an run-time error "Cannot copy a namespace node to an element after attributes have been added". In MSXML, and Xalan this works. With Saxon you can do it by using xsl:attribute <xsd:schema> | |||
36. | Unwanted namespaces in output | ||
You can use exclude-result-prefixes to stop unnecessary namespace declarations being added to the result tree, but not to stop necessary ones. This one is necessary because the element name xsd:element can't be used in the result tree unless the namespace with prefix xsd is in scope. The language of the XSLT 1.0 spec doesn't explain this very clearly. It's model is that the result tree has no namespace node for namespace xsd, but a namespace declaration is added at serialization time to make the output document namespace-conformant. The XSLT 1.1 draft has a better model - namespace nodes are added to the result tree under a process called "namespace fixup". | |||
37. | Using namespaces | ||
David C. If by empty ns you meant empty namespace name rather than empty prefix then that is special in that it can only be assigned to the default namespace (ie the empty prefix) you can't assign a non empty prefix to the non-namespace. I've now read that eight times and I'm off to let my head heal. I think it means <el xmlns="" == the default namespace, is 'special' I think the double negative means I can't do <pre:el xmlns="" Not quite. The namespace name is the namespace URI used to identify the namespace, our favourite example being "http://www.w3.org/1999/XSL/Transform". An empty namespace name ("") means 'no namespace' or 'null namespace'. The namespace prefix is the character(s) that you associate with the namespace URI within a particular document. We usually use 'xsl' as the namespace prefix for the XSLT namespace, for example. An empty namespace prefix is what you use with the default namespace - element names without a prefix (with an empty namespace prefix) are in the default namespace. What David said that you can't assign a non-empty namespace prefix to an empty namespace name. That means you can't do: <el xmlns:pre=""...</el You can, however, assign an empty namespace prefix to a non-empty namespace name (that's what you do when you create a default namespace): <el xmlns="my-namespace"...</el or You can also assign an empty namespace prefix to an empty namespace name, and, of course, a non-empty namespace prefix to an non-empty namespace name: <pre:el xmlns="" xmlns:pref="my-namespace"...</pre:el | |||
38. | Namespace clarification | ||
Perfectly standard: namespace declarations only *look* like attributes. They are not treated as such by XML parsers. You need to use the namespace axis. Namespace declarations are represented by every element node having a list of namespace nodes attached: one for every namespace declaration in scope at that node. So in your case the 'element' element node has a namespace node attached to it corresponding to mynamespace="http://something.org/path". Two things you ned to know about namespace nodes: local-name() and name() both return the namespace *prefix* - I tend to use local-name() becuase it sounds like it should return the prefix (the 'local' name for the namespace in this document) but I'm not as convinced about name() string() returns the namespace *URI* - recall that xsl:value-of is defined in terms of the string() function So this should do the trick: <xsl:template match="element"> Note that you do not need to go chasing off up the tree with ancestor-or-self : the namespace node is there regardless of where the declaration is, it just has to be in scope. Anticipationg the obvious question: if you want to generate a namespace declaration (which you normally only need to do if the namespace prefix is used in an attribute value as in your example) don't try to do it with an attribute. Instead copy a namespace node using xsl:copy-of. | |||
39. | XHTL to fo, namespace problems. | ||
In other words, the XHTML to XSL-FO conversion requires that the html element (and other elements, I imagine) are in the XHTML namespace. They need to be in the XHTML namespace because that's what the transformation uses to identify elements that it knows how to convert.
In other words, you're creating an html element in *no namespace* (there's no default namespace declaration, so elements without a prefix are in no namespace). You happen to have the XHTML namespace associated with the prefix 'html' but I guess there's nothing in your stylesheet that uses the prefix 'html' so the namespace declaration doesn't do much. To create an html element with no prefix and in the XHTML namespace, you need to declare the XHTML namespace as the default namespace within your stylesheet: <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml"> <xsl:template match="/"> <html> </html> </xsl:template> </xsl:stylesheet> Note that placing the default namespace declaration on the xsl:stylesheet element means that its scope is the entire stylesheet -- any literal result element that doesn't have a prefix will be placed in the XHTML namespace. That's what you want to happen. Paul Brown's suggestion of: <xsl:template match="/"> <html xmlns="http://www.w3.org/1999/xhtml"> </html> </xsl:template> will place the html element in the XHTML namespace, and it will place any literal result element actually inside that html element *in the stylesheet* in the correct namespace. However, if you had something like: <xsl:template match="/"> <html xmlns="http://www.w3.org/1999/xhtml"> <xsl:apply-templates /> </html> </xsl:template> <xsl:template match="/*"> <head> </head> <body> </body> </xsl:template> then the head and body elements would again be in no namespace, since there is no default namespace declaration that covers them. | |||
40. | Namespace processing in XSLT 2 | ||
Unfortunately not in XSLT 1.0. As far as XPath and XSLT are concerned, an element with a namespace is completely different from an element without a namespace. To change an XSLT 1.0 stylesheet from working over a source document without namespaces to one with, you have to change every XPath that refers to elements that now have a namespace, so that they include prefixes pointing to that namespace. Because this is a common problem, XSLT 2.0 has an attribute, 'default-xpath-namespace', which you can use to tell the XPath processor that any element name tests without prefixes in XPaths should count as selecting/matches elements in that default XPath namespace rather than in no namespace. So come XSLT 2.0 you'll be able to just slide your new namespace into that attribute and everything (well, assuming that *all* your elements were in that namespace) would work fine. > Perhaps the best would be to make some sort of pre-processing and > remove all namespaces before applying the XSL. > > I'm trying to avoid changing the way my XSL works because I guess it > won't be that easy (or maybe it is...?) If you want to carry on being able to process the original documents, that didn't have a namespace, then a pre-processing step would be sensible (and isn't hard to do in XSLT). If you now *only* want to use the documents with namespaces as the source, you may as well change the XPaths; it'll probably be simpler in the long run, and more in the spirit of the namespace use. | |||
41. | Remove namespaces | ||
A variation on the identity transform described in the XSLT 1.0 spec, under Copying, would do the trick. For the root node, comments and PIs you will copy them through. For elements and attributes you'll create a new element or attribute without copying the namespace nodes that are attached to them. <?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="no"/> <xsl:template match="/|comment()|processing-instruction()"> <xsl:copy> <!-- go process children (applies to root node only) --> <xsl:apply-templates/> </xsl:copy> </xsl:template> <xsl:template match="*"> <xsl:element name="{local-name()}"> <!-- go process attributes and children --> <xsl:apply-templates select="@*|node()"/> </xsl:element> </xsl:template> <xsl:template match="@*"> <xsl:attribute name="{local-name()}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:template> </xsl:stylesheet> | |||
42. | Generating xml with a runtime resolved default namespace | ||
You are thinking of xmlns as an attribute with scope . that's the wrong way to think of it. Just think of the namespace as part of the name. <rdf:RDF xmlns="{$prefix}#" xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"> You don't care about $prefix here, so just do <rdf:RDF xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <xsl:element name="@owls:class"> but you want this to be in the namespace so <xsl:element name="@owls:class" namespace="{$prefix}#"> | |||
43. | Change namespace with copy-of? | ||
No. xsl:copy-of can only be used to create an exact copy. If you want to change anything, you need to process each node individually using a template rule ("or otherwise", as they say in maths exams). In XSLT 2.0 there is an <xsl:namespace> instruction designed to fill this gap. In XSLT 1.0 the usual circumvention is to create an RTF containing the required namespace node, and then copy it (which requires xx:node-set): <xsl:variable name="dummy"> <xsl:element name="{$prefix}:xxx" namespace="{$uri}"/> </xsl:variable> ... <xsl:copy-of select="xx:node-set($dummy)/*/namespace::*[name()=$prefix]"/> Copying of namespace nodes is defined by an erratum to XSLT 1.0. | |||
44. | Add a namespace to all elements | ||
You change the namespace the same way you'd change the local name, walk over the tree and generate the new names with xsl:element something like <xsl:template match="*"> <xsl:element name="local-name()" namespace="mynamespace.uri"> <xsl:copy-of select="@*"/> <xsl:apply-templates/> </xsl:element> <xsl:template> <xsl:template match="/*"> <xsl:element name="local-name()" namespace="mynamespace.uri"> <xsl:copy-of select="@*"/> <xsl:attribute name="xsi:schemaLocation" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >mynamespace.uri trap.xsd"</xsl:attribute> <xsl:apply-templates/> </xsl:element> <xsl:template> Mike Kay offers Getting rid of the DTD reference is trivial. Adding the XSD reference is trivial. The only non-trivial part is changing the element names to be in a different namespace. For that you need a variant of the identity template: <xsl:template match="*"> <xsl:element name="local-name()" namespace="mynamespace.uri"> <xsl:copy-of select="@*"/> <xsl:apply-templates/> </xsl:element> </xsl:template> To add the schema reference just add another rule for the top-level element: <xsl:template match="/*"> <xsl:element name="local-name()" namespace="mynamespace.uri" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <xsl:attribute name="xsi:schemaLocation">mynamespace.uri trap.xsd</xsl:attribute> <xsl:copy-of select="@*"/> <xsl:apply-templates/> </xsl:element> </xsl:template> | |||
45. | Adding namespaces | ||
No, you do not have to do that, and it is bad practice if there are any other althernative. What you want to to is to add the namespace as you copy each of the imported elements. You can do this by modifying the standard identity template so that you get a chance to modify each element as it gets processed - <xsl:template match="/"> <myheader xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="www.abc.org/schema/mainschema.xsd" supplier="My Company Ltd"> <xx> <xsl:apply-templates select="$imported-xml" mode='import'/> </xx> </myheader > </xsl:template> <!-- Here you add the namespace to each element and otherwise copy its contents --> <xsl:template match='*' mode='import'> <xsl:element name='{name()}' namespace='www.abc.org'> <xsl:apply-templates select='@*' mode='import'/> <xsl:apply-templates select="* | text()" mode='import'/> </xsl:element> </xsl:template> <!-- Here you pick up any attributes --> <xsl:template match='@*' mode='import'> <xsl:copy-of select='.'/> </xsl:template> I used the mode "import" to avoid any conflict with other templates you might want to write that will not be handling the imported xml. With this approach you do not have to put a default namespace declaration into "myheader" - the stylesheet will insert it for you in the top-level element of the imported document. Michael Kay adds If you want the new elements to be in namespace "www.abc.org" when the old elements were in no namespace, then you are modifying them rather than copying them. To do this you can't use xsl:copy-of, you have to walk the tree using xsl:apply-templates and a template rule that does something like: <xsl:template match="*" mode="change-namespace"> <xsl:element name="local-name()" namespace="www.abc.org"> <xsl:apply-templates/> </xsl:element> </xsl:template> | |||
46. | Adding namespaces | ||
First, you need to understand that the namespace declarations that you see in the result of your transformation come about because of the position of namespace nodes within the result tree that you're generating. A namespace declaration will be added to an element if it has a namespace node that its parent doesn't have. So the tree that you want to create looks like: (I've omitted the namespace node for the XML namespace from the above, for brevity.) You want the <payload> element to have a namespace node that associates the prefix 'x' with the namespace 'http://www.example.com/ex/' but for none of its parents to have that namespace node. When you create an element using a literal result element such as the <ListRecords> element in: > <xsl:template match="data"> > <ListRecords> > <xsl:apply-templates select=".//datum" /> > </ListRecords> > </xsl:template> then the resulting element is given namespace nodes for all the namespaces that are in-scope for that element, minus the XSLT namespace and minus those namespaces that are specified as being excluded result prefixes (using the [xsl:]exclude-result-prefixes attribute). In your stylesheet, you declare the http://www.example.com/ex/ namespace right at the top level of the stylesheet, on the <xsl:transform> element, and you don't list it as an excluded namespace. That means that it's in-scope throughout the stylesheet, so every element that you create with a literal result element gets a namespace node for that namespace. This is why you get the namespace declaration on the <ListRecords> element in the result. What you need to do is make sure that the namespace node for the http://www.example.com/ex/ namespace is either only in scope for the <payload> element or exclude it for all but the <payload> element. To achieve the effect that you want by only having the namespace in scope for the <payload> element, I think it would be easiest to split the stylesheet into two, since you want to use the 'x' namespace in other templates -- one part that handles the wrapper and one part that handles the payload -- and include the former into the latter. For example: --- wrapper.xsl --- <?xml version="1.0" encoding="UTF-8"?> <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:include href="payload.xsl" /> <xsl:output method="xml" omit-xml-declaration="yes" /> <xsl:template match="data"> <ListRecords> <xsl:apply-templates select=".//datum" /> </ListRecords> </xsl:template> <xsl:template match="datum"> <record> <header> <identifier> <xsl:value-of select="identifier" /> </identifier> </header> <body> <xsl:apply-templates select="." mode="payload" /> </body> </record> </xsl:template> </xsl:transform> --- payload.xsl --- <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:q="http://www.example.com/queue/" xmlns:x="http://www.example.com/ex/" exclude-result-prefixes="q"> <xsl:template match="datum" mode="payload"> <payload> <xsl:apply-templates select=".//q:one" /> <xsl:apply-templates select=".//q:two" /> </payload> </xsl:template> <xsl:template match="q:one"> <x:one> <xsl:value-of select="." /> </x:one> </xsl:template> <xsl:template match="q:two"> <x:two> <xsl:value-of select="." /> </x:two> </xsl:template> </xsl:transform> To achieve the effect you want by managing exclude-result-prefixes, you need to exclude the 'x' prefix only on the subtree that's used for generating the wrapper: <?xml version="1.0" encoding="UTF-8"?> <xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:q="http://www.example.com/queue/" xmlns:x="http://www.example.com/ex/" exclude-result-prefixes="q"> <xsl:output method="xml" omit-xml-declaration="yes" /> <xsl:template match="data"> <ListRecords xsl:exclude-result-prefixes="x"> <xsl:apply-templates select=".//datum" /> </ListRecords> </xsl:template> <xsl:template match="datum"> <record xsl:exclude-result-prefixes="x"> <header> <identifier> <xsl:value-of select="identifier" /> </identifier> </header> <body> <xsl:apply-templates select="." mode="payload" /> </body> </record> </xsl:template> <xsl:template match="datum" mode="payload"> <payload> <xsl:apply-templates select=".//q:one" /> <xsl:apply-templates select=".//q:two" /> </payload> </xsl:template> <xsl:template match="q:one"> <x:one> <xsl:value-of select="." /> </x:one> </xsl:template> <xsl:template match="q:two"> <x:two> <xsl:value-of select="." /> </x:two> </xsl:template> </xsl:transform> You'll notice that in both stylesheets I've used a separate template, in 'payload' mode, to generate the <payload> element, so that it appears in a different scope from its parent and can therefore have different namespace nodes on it. Mike Kay adds, The general rules are: literal result elements copy all in-scope namespaces declared in the stylesheet, other than those you exclude using exclude-result-prefixes copying an element from the source document copies all the in-scope namespaces from that element in the source document creating elements using xsl:element creates only those namespace declarations that are actually needed for the element and attribute names | |||
47. | Add a namespace | ||
> Given some document with unknown elements (i.e., I can't enumerate the the namespace is part of the element name, so as far as XSLT is concerned this is like saying Given some document with unknown elements (i.e., I can't enumerate the elements inside the stylesheet for special processing) in a null namespace: Can I use XSLT to process this document and prefix every element name with "A"? You code them pretty much the same way. To do the first:
To do the second, you do <xsl:template match="*"> <xsl:element name="{local-name()}" namespace="http://wibble.com/ns"> <xsl:apply-templates/> </xsl:element> </xsl:template> which will produce <random xmlns="http://wibble.com/ns"> If you need to specify the prefix you need a combination of both: <xsl:template match="*"> <xsl:element name="concat('w:',{local-name()})" namespace="http://wibble.com/ns"> <xsl:apply-templates/> </xsl:element> </xsl:template> In that case if your stylesheet element already has xmlns:w="http://wibble.com/ns" so that the w: prefix is in scope then you could simplify the last to <xsl:template match="*"> <xsl:element name="concat('w:',{local-name())}"> <xsl:apply-templates/> </xsl:element> </xsl:template> as xsl:element will use the right namespace for the w: prefix in that case. | |||
48. | Adding namespace and schema directive | ||
I can specify this element in my xslt template as: <xsl:element name="ACORD" namespace=" http://www.ACORD.org/standards/PC_Surety/ACORD1.4.1/xml/" > but I can find no documentation on how to reproduce the second namespace directive or the schema directive. The xmlns:xsi declaration should be generated automatically when you do <xsl:attribute name="xsi:schemaLocation" namespace="http://www.w3.org/2001/XMLSchema-instance">...</xsl:attribute > The xmlns:Marsh one is more tricky: in XSLT 2.0 you've got <xsl:namespace>, but in 1.0 the only way of generating a namespace node that isn't actually used by the element or any of its attributes is to copy the namespace node from somewhere. One way is to have a source document <dummy xmlns:Marsh="http://www.marsh.com/"/> and then do <xsl:copy-of select="document('dummy.xml')/dummy/namespace::Marsh"/> | |||
49. | Get rid of namespace attribute? | ||
Let's use the notation {uri}local to refer to the expanded name of an element. If you write the literal result element <template xmlns=""> in your stylesheet, then the element name (in both the stylesheet and the result document) is {}template - i.e. local name "template", in no namespace. In the result tree, a processor can always ensure that the template element is in "no namespace" by writing <template xmlns="">. However, most processors will avoid redundant namespace declarations, and the xmlns="" is redundant if there is no outer element with a namespace declaration such as xmlns="something". As I said, don't worry about namespace declarations. Only worry about (expanded) element names. Put the element in the right namespace, and leave the serializer to worry about getting the namespace declarations right. | |||
50. | Is a namespace an attribute? | ||
Correct, because namespace attributes show up on the namespace axis, not on the attribute axis. I hope the example below helps. T:\ftemp>type munna.xml <?xml version="1.0" encoding="utf-8"?> <!--extract for example--> <feed version="0.2" xmlns="http://purl.org/atom/ns#" xmlns:tt="http://www.tt.org/ns#"/> <!--end of extract--> T:\ftemp>type munna.xsl <?xml version="1.0" encoding="iso-8859-1"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="text"/> <xsl:template match="*"> <xsl:for-each select="namespace::node()"> The prefix: <xsl:value-of select="name(.)"/> The URI: <xsl:value-of select="."/> </xsl:for-each> </xsl:template> </xsl:stylesheet> T:\ftemp>saxon munna.xml munna.xsl The prefix: xml The URI: http://www.w3.org/XML/1998/namespace The prefix: The URI: http://purl.org/atom/ns# The prefix: tt The URI: http://www.tt.org/ns# T:\ftemp> | |||
51. | Superfluous xmlns attributes in result | ||
When elements from a source document are copied to a result document, all their in-scope namespaces are copied too. This is because it is in general impossible to tell which namespaces are used and which aren't. XSLT 2.0 provides a means to suppress this copying of namespace nodes using the attribute copy-namespaces=yes|no on xsl:copy and xsl:copy-of. | |||
52. | Superfluous xmlns attributes in result | ||
When elements from a source document are copied to a result document, all their in-scope namespaces are copied too. This is because it is in general impossible to tell which namespaces are used and which aren't. XSLT 2.0 provides a means to suppress this copying of namespace nodes using the attribute copy-namespaces=yes|no on xsl:copy and xsl:copy-of. | |||
53. | Change the namespace prefix | ||
As you may know, XSLT (or any XML-namespace-conformant system) doesn't distinguish between elements on the basis of their prefixes, but on the basis of the expanded name when those prefixes are resolved to their URI bindings. So if you have <example xmlns:n1="myURL.com" xmlns:n2="myURL.com"> <n1:element/> <n2:element/> </example> n1:element and n2:element are considered to be the same. What this means is that you really only need an identity transform that writes your output using the prefix you want. This can probably be done (although I haven't tried it) very simply: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:math="http://www.w3.org/1998/Math/MathML "> <xsl:template match="/"> <xsl:copy-of select="/"/> </xsl:template> </xsl:stylesheet> This will work since the "math" prefix here is bound to the same URI as the "mml" prefix in your input. (I'm assuming your input declares the correct namespace. :-) And most XSLT engines should serialize the result using the prefix you have chosen, "math". (Note however that strictly speaking they don't have to do this: in effect you are relying on an optional feature of the serializer, and you should test the technique on any processor before depending on its working there.) | |||
54. | Copy-of and namespaces | ||
Correct. In XSLT 1.0, xsl:copy-of copies all namespaces. In 2.0, this can be suppressed by writing <xsl:copy-of select="..." copy-namespaces="no"/> | |||
55. | Wildcards in namespace | ||
XPath 2.0 allows constructs of the form *:local which will match local in any namespace, but there's no way of matching a set of namespaces. I would recommend using a first transformation pass to normalize the namespace URI, to keep this separate from the "real" transformation logic. This is just a variant on the identity template: <xsl:template match="one-uri:*"> <xsl:element name="{local-name}" namespace="two-uri"> <xsl:copy-of select="@*"/> <xsl:apply-templates/> </xsl:element> </xsl:template> | |||
56. | getting a namespace declaration into the result tree | ||
In XSLT 1.0 there are basically three ways of getting a namespace declaration into the result tree: (a) you can copy it from the source document. This happens when you use xsl:copy to copy an element node or a namespace node (b) you can copy it from the stylesheet. This happens when you instantiate a literal result element, unless exclude-result-prefixes is used (c) you can use the namespace in the name of an element or attribute in the result tree, in which case the system will generate a declaration of that namespace automatically What you can't do is to use xsl:attribute name="xmlns:xyz". Namespaces are not attributes. The system will assume you want to generate an attribute with local name xyz, and since it can't use the prefix xmlns (it's reserved), it will generate a different prefix. I suspect Xalan 1 had a bug and was allowing you to generate an attribute with the reserved name xmlns:xyz, which was working by accident because the serializer didn't notice the error. It's easier in XSLT 2.0, there is an xsl:namespace instruction to generate a namespace node explicitly. The simplest workaround in your case is to generate the xsl:stylesheet using a literal result element, in which case its namespaces will be copied. You'll need to use xsl:namespace-alias for this. Note that xsl:namespace-alias *only* affects literal result elements, if you use it in a stylesheet with no LREs then it's ignored. | |||
57. | Remove a namespace | ||
If the namespaces came from the stylesheet, use exclude-result-prefixes="w v o" etc to avoid them finding their way into the result document. If the namespaces came from the source document, use xsl:element and xsl:value-of in preference to xsl:copy or xsl:copy-of. In XSLT 2.0 you can use <xsl:copy-of select="XXX" copy-namespaces="no"/> to copy an element except for any unused namespace declarations. | |||
58. | Template not matching, Namespace issues | ||
Oh yes sorry I didn't mean to criticize. (You could always criticise my typing accuracy if it came to that:-) However if people use completely wrong terminology then it's not too confusing as you can guess what they mean and react accordingly, but if you are unlucky and the terminology is correct (but doesn't mean what was intended) then it's harder to spot that a translation is required. How many different kinds of namespaces are there in XSLT. 1. no-namespace 2. default namespace and is there any other? Well if you phrase it that way there are others yes, such as namespaces that are neither the default (and are not no-namespace). But listing the choices like that is confusing as they are really independent. There is the syntactic/structural distinction: All namespaces have a namespace name which is a URI such as http://fooobar there is one special case of a "null namespace" for elements that are not in a namespace at all. XSLT essentially treast no-namespace as a namespace with namespace URI the empty string "" so you often hear this called the nul namespace or similar terms, although the namespace rec, says that such elements are not in a namespace. So your first distiction is saying whether the namespace has a namespace URI or not. Then there is a syntactic issue, if an element is in a namespace say element xx in namespace http://foobar then it may appear with (any) prefix or with no prefix, but Xpath essentially treats all these things as equivalent, just as <x n="2"/> and <x n='2'/> are equivalent. so <xx xmlns="http://fooobar"/> <p:xx xmlns:p="http://fooobar"/> <zzz:xx xmlns:zzz="http://fooobar"/> the term "default namespace" refers to using the first unprefixed from above. But this is essentially a syntactic issue apart from one (or two:-) special functions XSLT and XPath can not tell that the default namespace syntax was used, and if it was not used, it can't tell which prefix was used. In all the cases above you woul duse the same match expression something like match="qqq:xx" xmlns:qqq="http://fooobar" James Fuller offers a few links I think David succintly explained XML namespaces as constrasted with XSLT, here are a few background links older stuff xml.com xml names at W3C James Clarks site zvon David C later answered another one I include here. namespace FAQ number 1: <Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" ... ... <Worksheet so that is Workbook and Worksheet in namespace urn:schemas-microsoft-com:office:spreadsheet and this <xsl:for-each select="Workbook/Worksheet selects so that is Workbook and Worksheet in no-namespace so selects nothing in this case. You want xmlns:x="urn:schemas-microsoft-com:office:spreadsheet" on your xsl:stylseheet then <xsl:for-each select="x:Workbook/x:Worksheet etc so that you select elements from this namespace. > I can't figure out how to get the declaration of such a prefix into > the xs:schema result element since both the prefix and the URI to > which it refers are unknown until runtime. Michael Kay answers this one. The xsl:namespace instruction was added in XSLT 2.0 for this purpose. It allows you to create a namespace node with a prefix and uri, just as you would use xsl:attribute to create an attribute node. The only way to achieve the same effect in XSLT 1.0 is a workaround: create a result tree fragment containing an element in the relevant namespace, and then copy the resulting namespace node: <xsl:variable name="temp"> <xsl:element name="{concat($prefix, ':dummy')}" namespace="{$uri}"/> </xsl:variable> <xsl:copy-of select="xx:node-set($temp)//namespace::*[name()=$prefix]"/> | |||
59. | Namespace prefix? | ||
substring-before(name(),':') or or to know the prefix used for http://www.example.com.ns use name(namespace::*[.='http://www.example.com.ns']) in both cases what you actually get is the prefix used in the input tree, which need not be (but always is on systems that I use) the same as the prefix used in the original document. (xslt allowed xml parsers _not_ to report original prefixes (in which case the system would make up prefixes) but in practice all namespace parsers do report prefixes otherwise supporting namespsaces in attributes in xpath and xschema etc would be very hard. | |||
60. | What namespaces are used in the document? | ||
That's the declared namespaces. You can find the namespaces used in element and attribute names as distinct-values((//*|//@*)/namespace-uri()) | |||
61. | Tidy up namespace declarations | ||
It's a bit hacky but this identity transform should move all prefixed namespaces to the root element: <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:saxon="http://saxon.sf.net/" exclude-result-prefixes="xs saxon"> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="/*"> <xsl:copy> <xsl:for-each select="for $x in distinct-values(//*/in-scope-prefixes(.)), $y in //* return QName(namespace-uri-for-prefix($x, $y), concat($x, ':', 'dummy')) [normalize-space(namespace-uri-for-prefix($x, $y))]"> <xsl:namespace name="{prefix-from-QName(.)}" select="namespace-uri-from-QName(.)"/> </xsl:for-each> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> </xsl:stylesheet> | |||
62. | Namespaces, and attributes | ||
Namespaces in XML states that attributes without prefixes are in no namespace, not in the default namespace: W3C > Should the result be: > <test xmlns="http://test" test=""/> Yes ... because the element is in the default namespace and the attribute is in no namespace. > Is there anyone on this list who happens to know what the > real reasons where why that rule was added to that > recommendation? It can be hard to work out why a WG has made a decision even when you were at the meeting. There was a lot of debate about this: I think the three options were that unprefixed attributes should be (a) in no namespace, (b) in the default namespace, or (c) in the namespace of the containing element. The underlying principle is that most attributes are defined as part of the same vocabulary as the containing element (a "vocabulary" being a unit of design and change control). You don't want (b) because that means if you give the element a prefix you have to give most of its attributes a prefix too (<html:table html:width="10" html:height="30"/> gets pretty ugly). The choice between (a) and (c) is more arbitrary, but (a) reflects that the definition and semantics of the attribute are usually local to the element; the fact that a height attribute is defined for an html:table element doesn't mean you can use it (in the form html:height) on an invoice element. This also explains the idea that "no-namespace" names are not in a namespace - the thinking is that a namespace has a definition, it is controlled by a design authority, whereas the no-namespace is a bucket in which anyone can put anything. While this idea has merit, the language of a lot of specifications would be simpler if the "no-namespace" were treated as just another namespace that happens to have no name (or a name of ""). | |||
63. | How to move all Namespace declarations to Header with XSLT? | ||
To move all namespace declarations to the top level:
To move all namespace declarations as far down as they will go: <xsl:template match="/"> <xsl:copy-of select="." copy-namespaces="no"/> </xsl:template> |