|
The output was generated line by line, with a for-each loop (some like to say that, technically, XPath doesn't have loop constructs, but this for-each sure acts like one). The node-set created in that select attribute of for-each was read node by node, in order. Using the position() function, you could see the order. The position() doesn't group by nesting/indentation, but just reads right down regardles of identation. The last node in that set is identified with the, last(), function (used in a predicate such as: [position()=last()], which can also be further abbreviated). And the number of nodes is found with, count(). So working with a node-set, in order to pick any particular node in the order given in the XML document, the brackets are used, again - for example, file\externalLink\elink[2], which is a shorthand for, file\externalLink\elink[position()=2], and returns the set of nodes for the second elink, the "no link here" stuff. [There's the somewhat odd structure, as well, and called a 'result tree fragment', only in the original version 1.0, which is the node-set created for a variable/constant, using the xsl:variable element/command (which despite the name is really a constant) or else that passed with the xsl:param and xsl:with-param commands (which are the real variables). It could be an XML block, parsed by the constant and variable elements/commands. e.g. <xsl:variable name="xmlblock"><b>Hello</b><br/>There</xsl:variable>. There's not much you can do with a 'RTF' except copy it out. It can't be used like a node-set. So, just to mention, as 'ancient history'. If using msxml as one's XML/XSL processor/parser/etc, then there's a custom Microsoft function, msxsl:node-set(), which can convert such a tree 'fragment' to a node-set.]
Anyway, given a node-set, at each point in the loop, another node is
examined.
It's called the - current node - in the - current node list.
That's simple enough.
The number of nodes that result from evaluating the XPath expression is called the - context size -
and is found with the
And that brings us to the terminology of the XPath - context. Technically, the XSLT context is what is just described, above. There's a current node - in that for-each loop. It's in the particular current node list - or current context. XPath, however, is just that expression - that XPath expression. It's separate from the XSLT. And so there's a context in evaluating that expression. The context is each step along the way of each node-set, say, passed along to the next location step to the right, or to one or more predicates. So there's the context for the XSLT. And there's this separate expression context when evaluating the steps in an XPath expression. So in this example, there is no location step operator - no slash. The context node is whatever the template is looking at, in the XSLT, as the XSLT current node. Based on that, the parent nodes are looked at. That groups of parent nodes becomes the context as the XPath is evaluated, step by step. The next step is the predicate. And so the filter is applied.
There are thirteen axes in XPath. Given a node, these axes indicate all other nodes that bear a particular 'relationship'. These could refer to a context node. In the example, above, it was provided by the current nodeset in the XSLT, to begin evaluation of the XPath expression. As the expression is evaluated, that XPath context changes, sometimes from a different axis in the next location step or predicate. Just to mention all 13 axes:
Two are unique, not like the other eleven. The attribute axis refers just to the attributes of a particular element. And the namespace axis lists all namespaces that are available to a particular element. It can be a lot. That doesn't mean the element is part of any namespace, unless a default is specified. Rather, a namespace prefix must be explictly used on that XML element. But that's covered, elsewhere. [Something to note, however. Using a default namespace, specified say in the root node of the XML, can make it impossible to reference specific elements, and specifically when using XPath. So an explicit prefix is always needed, if you're going to use namespaces. A default namespace sort of 'hides' nodes from XPath. It might be best to avoid default namespaces, if you can (though this is another of those 'teething' problems likely solved in the next version of XPath).]
It's a bit meaningless. It's just an example. But for the seven elements under image, this returns the same value of 150, every time. This slash indicates the next level down, in this example, the child (or subnode); all the elements under the image element. That's the child:: axis, for this type of node. The slash is more precisely, again - the location step operator. It's a left to right operator between sub-clauses, or location steps, and changing the 'context' as it goes. Parentheses can be used to group various parts of the XPath expression. But, in another sense, one might think that the parent axis is unnecessary, here. Image slash should really mean everything under the image element, correct? And the answer is, yes. The child axis is actually redundant, here. The child axis is the - default. A shorthand notation is simply to omit it. And so image slash asterick should pick up every element under image. But it doesn't, because of the - context node. Let's rewrite it:
If you substitute - "parent::" - for the - ../ - here, then you have the same XPath expression. It's yet another shorthand notation. But, if you entirely remove the parent axis, then the only place that modified expression will return a value - the width value of 150 - is for the root element, and no other. Without the 'double-dot', 'superior directory', parent axis, the expression would be evaluated on the child axis, which is the default (if no other axis is specified). So for each current node sent to start off the XPath expression, each time through the loop, then - "image/" - is not only the same as "image/child::", but importantly is also - "child::image/child::". And there's the problem. You needed the parent axis to begin one step 'up', since the child axis was being used, anyway, as default. So for all nodes under root, image is either a 'sibling', or a superior node. No other element from the XML source, other than the root element (not the XPath 'document element'), can see an image element under it. There's another way to look at the default. The single period or dot refers to the context node. Put a single slash, and nothing else, after it - ./ - and you have a relative path which is the same thing as the child axis, next step down, from the context node. (Putting an asterick, at the end, gets all elements on that child axis - ./*.) The double-dot shorthand, instead, looks to the next level up. One level only. So at the root, it shouldn't cause an error, but won't get any returned value. But given this example XML source document, for the image element, itself, and also file, and body, and externalLink, XPath is going up one level, to the root element, and then looking from there, specifically, one level down (child axis), for the image element, and then that width element and its value underneath (which then for everything but the root node, it won't find). Simple enough. But yet again, the reason it doesn't work for elements under, file, or elements under image, itself, is that the slash is just one level, just the immediate child axis. One level only. As the XSLT goes through the XML document, if the current context is a node under the file element, say, then one step up is going to be the file element, itself, and XSLT won't find the image element by then going one step down.
And that raises the question, of course, what is the difference between these dot and slash path steps, and the use of axes? Again, they're abbreviations - shorthand - for just a couple of the axes. The single slash, again, is the one step down, and for the child axis, if no other axis is specified. If there's nothing to the left of the slash, then it's assumed the step down is from the very top of the document itself - namely, the root node (the 'document element'), always an absolute location path. If it's an absolute path - / - then the context node is the first child of the root, if the XPath expression is just that step operator, the slash. But it's one level only. The double slash can go more than one level down. And double slash is called the - recursive descent operator. Put a dot in front of it, for example - .// - and it will start at the current context, and then evaluate left to right whatever is specified after the - ".//". So a slash is like the child axis. And double-dot is like a parent. And the double-slash 'recursion' might be like a descendant axis. So these should work, identically:
To be accurate, the double-slash is like the descendant-or-self axis. And if you omit the dot from the second select, above, then you'll get that width 150 value for every element from the XML source. As an absolute path, the expression would return exactly the same thing, every time. Again, if you put nothing at the left of the slash, or the double slash abbreviation, then it's assumed that the context is the root node. [You'll see "node types" mentioned, just below. It's been used, in passing, already. And it's explained in more detail, just further on. The root node, for example, is particular type of XPath node.]
XPath has different sorts of, nodes. The built-in nodeset function, node(), returns various node types, as a node-set. The, name(), function gives the name of XML elements. It's most of the time a shorthand equivalent of - local-name(). However, a namespace changes that. If a namespace prefix is applied to an element or attribute, in the XML document, then it is called a - qualified name - or QName. Name() then returns the entire QName. Say the namespace prefix is, "ms", and it's used on an element, "elone". Name() then returns - ms:elone. But local-name() returns only - elone - which is called the local part of the QName.
And there's another node for the element's text, itself a sub-node of the element (that is, on the element's child axis), which is retrieved with the function - text(). There are seven types of nodes in an XPath 'infoset', the internal XPath tree structure. The node of type, root, is not even found in the original XML, but is created by XPath.
So, yet again, the namespace is kind of the sometimes confusing special case, mentioned elsewhere. (The namespace-uri() function is used to identify any namespace actually associated with the element and the namespace axis reports all namespaces that could be used for that element.) As for attributes, the element is always the parent node for its attributes, in XPath. It's not the reverse. Attributes are not on the child:: axis of the element node. The, at sign, is the shorthand for the attribute:: axis. The asterick, again, is every node allowed for that axis. So if the entire XPath expression is - @* - then it returns the node-set of all attributes for that element node. Let's take another look at a slightly modified version of the XML, in this example. - Go -. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||