What does a namespace do in XSLT when a url is provided such as:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
does this attempt to make a connection to the internet?
No; it just so happens that the specification for XML Namespaces (see W3C XSL Namespace specifications) are URI's.
They work in exactly the same way that namespaces in other languages do; they help uniquely identify things with the same names but in different contexts.
You can prove that no attempt is made to retrieve the resource by using a HTTP Monitor on your machine while loading or using the XSL Transformation - this answer has many good suggestions.
No.
Whatever the namespace is in a xsd, an xslt or any other xml file, there is no internet request.
The namespace is used to qualified your xml element.
When you conduct an XSLT transformation, the XSLT engine validates the XSLT file. It performs many checks, such as the root element being named stylesheet, etc. The engine must also be able to discern literal result elements (like <table>) from XSLT-specific elements (like <xsl:stylesheet>).
An element is recognized as XSLT-specific when it resides in the XSLT namespace. The value of the URI you posted (http://www.w3.org/1999/XSL/Transform) is simply a convention that makes it clear we're talking about XSLT. The prefix being defined (xsl) is the prefix used in the XSLT file to qualify the XSLT elements. You can use another prefix if you choose, provided you map it to the XSLT namespace.
Note that it's actually just a URI (an identifier), not a URL (a locator). There is no HTTP request to locate anything, it just identifies an abstract concept (in this case "XSLT").
Related
I am using the XML file here
http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml
And I have written this code
<xsl:for-each select="registry/record">
However it never finds anything because of this line in the XML
<registry xmlns="http://www.iana.org/assignments" id="service-names-port-numbers">
If I change that to
<registry>
It works, however I cannot change the XML, I must change the XSLT. What can I do to make it work? I just need to find those records.
Thanks.
XSLT and XPath are namespace-aware. Unfortunately they don't have any notation for setting a default namespace for the path, so you have to use an explicit prefix bound to the namespace.
If you aren't familiar with XML Namespaces, do review them. They're important.
Taking your specific example, here's a simplified version of the start of the SNTP document
<registry xmlns="http://www.iana.org/assignments" id="service-names-port-numbers">
<title>Service Name and Transport Protocol Port Number Registry</title>
<category>Service Names and Transport Protocol Port Numbers</category>
<updated>2014-02-06</updated>
<xref type="rfc" data="rfc6335"/>
<expert> ... names of experts ... </expert>
<note> ... usage notes ... </note>
<record>
<protocol>tcp</protocol>
<xref type="person" data="Jon_Postel"/>
<description>Reserved</description>
<number>0</number>
</record>
</registry>
The xmlns="http://www.iana.org/assignments" is a default namespace binding. All elements in this document will be in that namespace unless they have a prefix bound to another namespace or another xmlns= is used to change the default for them and their children.
Your XPaths and Match Expressions MUST reference this namespace, or they won't work.
Change
<xsl:for-each select="registry/record">
to
<xsl:for-each select="assignments:registry/assignments:record"
xmlns:assignments="http://www.iana.org/assignments">
(You can use a shorter prefix than assignments; I'm just trying to make this as clear as possible. You can also bind the prefix higher in your XSLT document -- typically, on the <xsl:stylesheet> element -- so it's available throughout the stylesheet rather than just in this one place.)
This will work, assuming the rest of your code is correct.
Also: In general, <xsl:for-each> tends to be overused. In general, unless this is a place where you really do need to do different processing than anywhere else in the stylesheet, you should instead be using <xsl:apply-templates> so the normal template-matching rules can apply. Otherwise you're making the stylesheet hard to extend and maintain. XSL is a rule-matching, nonprocedural language; learn to use it that way.
I've created an XSLT stylesheet document. Within this document I create a new XML document as stated below:
...
<CREATE_REQ
xsi:schemaLocation="http://fcubs.ofss.com/service/aServices theService.xsd"
xmlns="http://fcubs.ofss.com/service/aServices"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
...
After transformation (see below) the ordering of the namespaces is different. A normal XML parser can handle this and it is normally no problem. The problem in my case is that the receiving application can't handle this and the order of the namespace may and shouldn't be changed.
<CREATE_REQ xmlns="http://fcubs.ofss.com/service/aServices"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://fcubs.ofss.com/service/aServices theService.xsd">
...
Is there a function or declaration that the namespaces will not be changed?
If the receiving application can't handle it then it needs to be fixed. Whoever wrote it doesn't seem to have grasped what XML is all about. Fix the receiving application, or throw it in the bin where it belongs.
After transformation (see below) the ordering of the namespaces is
different.
No, the ordering is exactly the same. According to the W3C XPath 1.0 Data Model:
The attribute nodes and namespace nodes of an element occur before the children of the element. The namespace nodes are defined to occur before the attribute nodes.
This means that although in the provided XML fragment the attribute xmlns:xsi seems to precede the namespace declarations, in fact it follows them.
Therefore, the produced output doesn't change the ordering of namespaces and attributes of the original XML document.
Producing an XML document where an attribute precedes a namespace node would violate the above quoted definition, therefore a compliant XSLT processor wouldn't produce such a document.
XSL requires this at the top of every stylesheet:
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
and throws an error if the url in the namespace is not exactly right.
Today, "http://www.w3.org/1999/XSL/Transform" is offline. I cannot run any transformations. The transformation hangs and then returns "unexpected end of file" when the net request times out. If I change the URL in the namespace declaration to a random URL, the transformation fails with an error telling me that "http://www.w3.org/1999/XSL/Transform" is the required xsl namespace.
So how do I work around W3's site being down?
Using xmlns:something="..." declares an XML namespace. Such a namespace is merely a string, something that will help to attribute a unique meaning to element names like template or href, making sure multiple XML-based languages can be used in a single document without creating confusion as to its meaning.
Some of those namespaces are reserved for use by the W3C. The XSLT namespace is one of those. A proper XSLT processor will check if a stylesheet declares the correct namespace to make sure there can be no incorrect interpretation. The root element of the stylesheet should be in that XSLT namespace.
For an actual namespace value, you'd usually have a URI (and most often a URL) since that's normally a good unique identifier. However, this should never be used to actually resolve to any online resources during XML processing. Whereas HTTP URLs are normally treated in a case-insensitive manner and may make use of URL encoding for characters (e.g. space becomes %20), such resolution or equality of URLs is not checked in XML namespace processing. A namespace in XML is nothing but a string that's always checked in its exact form, casing and everything.
So if an XSLT processor complains that some resource at a URL cannot be found, then either it's doing something it shouldn't do, or the problem has nothing to do with namespace processing.
You're using Saxon, which most definitely isn't a processor that doesn't understand the concept of a namespace. Its father is Michael Kay who is also responsible for the XSLT 2.0 spec. But Saxon does support schema-aware XSLT processing. If a document specifies a schema location, then a processor using this for validation would actually use that location to get the schema. That's the difference with a namespace. DTDs and XML Schema locations can definitely result in network activity.
So I advise you to check if...
the XML uses a DTD with external definitions and whether those are available;
the XML specifies a schema location and whether that location can be reached;
the stylesheet makes use of a schema or some other external resource and whether that's available.
Once you've found the cause, look into the use of XML catalogs in conjunction with the processor. An XML catalog will allow you to use local resources if they can't be resolved from their URIs.
Simple answer: The http://www.w3.org/1999/XSL/Transform isn't a URL, it's just a string. If W3C had decided, there's no reason it couldn't have been 'ThisIsAnXsltStylesheet'. By convention, they usually resemble URL's, but this isn't required.
So, the fact that there's nothing at that URL isn't relevant to why your stylesheet is failing, and certainly won't be the cause. Logically speaking, if that were the case, then nobody without an internet connection would ever be able to use XSLT, and w3c's servers would be seriously overworked.
I'd recommend adding the first few lines of your XSLT into your question; it might shed some light on where your problem really is.
I have some XML/TEI documents, and i'm writing an XSLT 2.0 to extract their content.
Almost all TEI documents has no namespace, but one has the default namespace (xmlns="http://www.tei-c.org/ns/1.0").
So all documents has the same aspect, with unqulified tags like <TEI> or <teiHeader>, but if I try to extract the content, all works with "non-namespaced-documents", but nothing (of course) is extracted from the namespaced-document.
So i used the attribute xpath-default-namespace="http://www.tei-c.org/ns/1.0" and now (of course) the only document working is the namespaced one.
I can't edit documents at all, so what I'm asking is if there's a way to change dynamically the xpath-default-namespace in order to make work xpaths like //teiHeader both with namespaced and non-namespaced documents
If you are using XSLT 2.0, then you do have the option for a wildcard match for the namespace in a node test.
e.g. //*:teiHeader
http://www.w3.org/TR/xpath20/#node-tests
A node test can also have the form
*:NCName. In this case, the node test is true for any node of the principal
node kind of the step axis whose local
name matches the given NCName,
regardless of its namespace or lack of
a namespace.
This is functionally equivalent to Dimitre Novatchev's example, but a little shorter/easier to type.
However, this will only work in XSLT/XPATH 2.0.
There isn't really a clean way to do precisely what you are asking. However, there are workarounds available. You could use a two stage process whereby you strip the namespace from the document if it's present and then pass it through the same templates for all content.
There is a good example (in XSLT 1) of doing this in the DocBook XSLT. Take a look at html/docbook.xsl and common/stripns.xsl
Basically, you would need to assign the result of stripping the namespace to a variable and then call your existing templates (for the non namespaced) content but select the variable.
It is ugly, but this gives you what you want:
//*[name()='teiHeader']
If you use this style for all location steps in any XPath expression, the XPath expressions will select elements only by name, regardless whether or not the elements belong to any namespace.
is it at all possible to 'pre-proccess' in XSLT?
with preprocessing i mean updating the (in memory representation) of the source tree.
is this possible, or do i need to do multiple transforms for it.
use case:
we have Docbook reference manuals for out clients but for certain clients these need different 'skins' (different images etc). so what i was hoping to do is transform the image fileref path depending on a parameter. then apply the rest of the normal Docbook XSL templates.
Expanding on Eamon's answer...
In the case of either XSLT 1.0 or 2.0, you'd start by putting the intermediate (pre-processed) result in an <xsl:variable> element, declared either globally (top-level) or locally (inside a template).
<xsl:variable name="intermediate-result">
<!-- code to create pre-processed result, e.g.: -->
<xsl:apply-templates mode="pre-process"/>
</xsl:variable>
In XSLT 2.0, the value of the $intermediate-result variable is a node sequence consisting of one document node (was called "root node" in XSLT/XPath 1.0). You can access and use it just as you would any other variable, e.g., select="$intermediate-result/doc"
But in XSLT 1.0, the value of the $intermediate-result variable is not a first-class node-set. Instead, it's something called a "result tree fragment". It behaves like a node-set containing one root node, but you're restricted in how you can use it. You can copy it and get its string-value, but you can't drill down using XPath, as in select="$intermediate-result/doc". To do that, you must first convert it to a first-class node-set using your processor's node-set() extension function. In Saxon 6.5, libxslt, and 4xslt, you can use exsl:node-set() (as in Eamon's answer). In MSXML, you'd need to use msxsl:node-set(), where xmlns:msxsl="urn:schemas-microsoft-com:xslt", and in Xalan, I believe it's called xalan:nodeset() (without the hyphen, but you'll have to Google for the namespace URI). For example: select="exsl:node-set($intermediate-result)/doc"
XSLT 2.0 simply abolished the result tree fragment, making node-set() unnecessary.
This is not possible with standards compliant XSLT 1.0. It is possible in every actual implementation I've used, however. The extensions with which to do that differ by engine, however. It is also possible in standard XSLT 2.0 (which is in any case much easier to work with - so if you can, just use that).
If your xslt processor supports EXSLT, the exsl:node-set() function does what you're looking for. msxml has an identically named extension function as well (but with a different namespace uri, the functions are unfortunately not trivially compatible).
Since you are trying to generate slightly different output from the same DocBook XML source, you might want to look into the "profiling" (conditional markup) support in DocBook XSL stylesheets. See Chapter 26 in DocBook XSL: The Complete Guide by Bob Stayton:
Profiling is the term used in DocBook
to describe conditional text.
Conditional text means you can create
a single XML document with some
elements marked as conditional. When
you process such a document, you can
specify which conditions apply for
that version of output, and the
stylesheet will include or exclude the
marked text to satisfy the conditions.
This feature is useful when you need
to produce more than one version of a
document, and the versions differ in
minor ways.
For example, to use different images for, say, Windows and Mac versions of the same document, you might have a DocBook XML fragment like this:
<figure>
<title>The Foo dialog</title>
<mediaobject>
<imageobject os="windows">
<imagedata fileref="screenshots/windows/foo.png"/>
</imageobject>
<imageobject os="mac">
<imagedata fileref="screenshots/mac/foo.png"/>
</imageobject>
</mediaobject>
</figure>
Then, you would use the profiling-enabled versions of the DocBook XSL stylesheets with the profile.os parameter set to windows or mac.
Maybe you should use XSLT "OOP" methods here. Put all the common templates to all clients in a stylesheet, and create an stylesheet for each client with specific templates overriding common ones. Import the common stylesheet within the specific ones with xsl:import, and you'll do only one processing by calling the stylesheet corresponding to a client.