MK. DC. BR. MB. et al
This section lists, in various forms, lots of things that can't be done with XSLT as it is today (Sept 2000)
MK. DC. BR. MB. et al
> I want to get the value of a variable whose name is equal to the value > of the "id" attribute found in the current node.
You can't. There is no way in XSLT of constructing XPath expressions (e.g. variable references) at run-time.
MK. DC. BR. MB. et al
>how to change variable values ?
No - this is not possible.
When XSL was being designed, this question came up frequently. It was decided that the advantages of having a side-effects free language (i.e. without the ability to change the value of variables once the stylesheet has gone through the parser) outweighed the annoyance of old school programmers (who are used to changing the value of variables).
[DC: a small clarification, xsl variables are not "compile time constants" they do not get their values at compile/parse time, as normally they get their values at the time a template is applied to a node in the source tree, at run time. But once bound, their value doesn't change, and the scope of the binding does not extend beyond the current template.]
Basically, if you parse once and only once, and ban any changes to the stylesheet, you will get (in theory) much faster processing.
MK. DC. BR. MB. et al
> How can I get the entities definitions from an XML file (inside the > <!DOCTYPE [...> element) and put it into the XML file > resulting from my XSLT transformation ?
You can't, I'm afraid: XSLT operates on the tree derived from parsing the XML source and expanding all entity definitions, so the XSLT processor has no idea where the entity definitions or entity references were.
>Is it possible to output binary characters from an XSLT transformation?
Unfortunately the only characters you can output are characters allowed in XML, and this excludes all characters in the C0 group except TAB, CR, and LF.
 should be rejected by the XML parser before XSL gets a chance to do anything with it.
MK. DC. BR. MB. et al
> I want to construct a well-formed html document using a poorly formed > html fragment at the top, a poorly formed but complementary html > fragment at the bottom, and a well-formed html fragment in the middle. > > Can I do this?
XSLT is not the tool for this job. Generating output as a series of pasted-together text is something that ASP, PHP, CFML, etc are better suited for.
MK. DC. BR. MB. et al
Can I do conditional include ><xsl:choose> > <xsl:when test="$country='GUFRA'"> > <xsl:include href="GUFRA.xsl"/> > </xsl:when> > <xsl:otherwise> > <!--Define here what to do if no country specified.--> > </xsl:otherwise> ></xsl:choose> >
The short answer is you can't do it, the nearest you can get is to use modes. Alternatively, consider generating the stylesheet dynamically before applying it. xsl:include is a compile-time facility, like #include in C.
MK. DC. BR. MB. et al
> Can I do this? > > <xsl:template name="header"> > <html> > <body> > </xsl:template> > > <xsl:template name="footer"> > </body> > </html> > </xsl:template>
No way! XSLT is about generating trees, not about generating tags. Generating an element such as a <body> element is an atomic operation, it can't be split into two halves.
MK. DC. BR. MB. et al
> Can I do this? > <Name>Jack & Jill</Name>
This isn't XML data! XML can't include a free-standing "&", it has to be written as "&".
MK. DC. BR. MB. et al
Other oddments from Mike. You can't do
- conditional include |
- calling a template whose name is decided at run-time |
- apply-templates using a mode decided at run-time |
- discovering whether a document exists before calling the document() function |
- deciding the sort key at run-time |
Come to think of it, it's interesting how many of the restrictions are things you can do at compile time but not at run-time!
MK. DC. BR. MB. et al
> <xsl:template match="Tag"> > <xsl:param name="temp_name"/> > <xsl:call-template name="{$temp_name}"/> > </xsl:template> > > This does not work. Is there a way to call templates dynamically?
No, calling a template whose name is decided at run-time in not on.
MK. DC. BR. MB. et al
Can I create a two column table from unsorted data
No, You can store the sorted list in a variable of type result-tree-fragment without difficulty, as your code shows, but if you want to do further processing on it you have to convert the r-t-f to a node-set, which can't be done in standard XSLT. Saxon, xt, and MSXML3, however, provide mechanisms to do this.
MK. DC. BR. MB. et al
It is not possible to parametrize the <xsl:import> or <xsl:include> elements.
Kay, pg. 120:
“"Attribute value templates are never allowed for attributes of top-level elements. This ensures that the values are known before the source document is read, and are constant for each run of the stylesheet."” Thus you cannot, say, pass the href attribute value in as a parameter, because run-time assignment of that value is not allowed.
MK. DC. BR. MB. et al
you can't have any variable reference in the match attribute of a template.
First para, 5.3 of xslt spec. E.g. you can't have
<xsl:template match="p[. = $head-types]">(Ken H adds Although XT accepts the above, it is one of the areas where error checking is not fully implemented.)
In general in XSLT you can't use variables to contain expressions, patterns, or parts thereof, you can only use them to hold strings, numbers, node-sets, and booleans.
You can probably use count="*[name()=$element]", if you're careful about namespaces. <xsl:number> is the one place in XSLT where variables can be used within a predicate that forms part of a pattern.
MK. DC. BR. MB. et al
> I would have thought that this XSL would do the trick: > > <xsl:number level="any" count="preceding::t/@attr" > from="ancestor::body/section"/> >
The "count" attribute must be a pattern, and patterns cannot use the precedng axis. Similarly from is a pattern and cannot use the ancestor acis.
MK. DC. BR. MB. et al
Can I create PDF output with Msxml ?
No
MK. DC. BR. MB. et al
> <xsl:apply templates select="mynode" mode="$myparam">
This is a syntax error and the processor should reject it. The mode attribute is required to be a QName.
It's a shame that the language doesn't allow the mode to be selected at run-time, but it doesn't.
MK. DC. BR. MB. et al
> I'm trying to use the value of a parameter as the select value of an > xsl:sort element.
You can't
<xsl:sort select="$param"/>means "sort by the value of the parameter", which, since the parameter has the same value for every member of the node-set, is the same as saying don't sort at all. There is no way in standard XSLT of saying "sort by the value of the XPath expression represented by the string value of $param". You can do this in Saxon by writing
<xsl:sort select="saxon:evaluate($param)"/>.If $param is always an element name, and if you are careful about namespaces, you can do it in standard XSLT by writing
<xsl:sort select="*[name()=$param]"/>
MK. DC. BR. MB. et al
> When I query the doc root node for "//", the parser will report that it is > an "Incomplete XPath statement".
you can't end an xpath with / (or //) you have to have the final step specified. It's invalid because it doesn't match any of the productions of the XPath grammar as defined in the W3C XPath 1.0 Recommendation. (The grammar says what expressions are allowed, and by implication anything else isn't).
>Why would the attributes not be processed in document order? If they are >not, how can this be forced?
The term "document order" doesn't apply to a particular element's attributes. Order doesn't matter with attributes;
<test color="red" age="2"/>and
<test age="2" color="red"/>are the same to an XML parser.
What kind of app are you creating output for that cares about attribute order? It's not a conformant XML parser, and I've never heard of an HTML application (browser or otherwise) that cared about attribute order.
MK. DC. BR. MB. et al
Can I apply templates with dynamic mode? I have multiple templates that handle <tag> and I would like to choose witch template to invoke by supplying mode from the command line. <xsl:apply-templates select="tag" mode="{$m}"/>
No, like dynamic names in call-template this is a Frequently Requested Feature. The only real workaround is an xsl:choose instruction that lists the possible options.
The XSLT recommendation states that attribute value templates can only be applied to xsl attributes if explicitply stated so ( http://www.w3.org/TR/xslt#attribute-value-templates ) - and the mode attribute definition ( http://www.w3.org/TR/xslt#modes ) does not mention it
Evan Lenz
The XPath data types are as follows: string, number, node-set, boolean. XSLT adds an additional data type called the result tree fragment (whose days are numbered, as the next version of XSLT will likely do away with it). There is no XPath data type that corresponds to an XPath expression. Likewise, there is no eval() function that will let you evaluate a string as an XPath expression. I believe the rationale behind this was to enable pre-compilation of XPath expressions as well as compile-time recognition of ill-formed expressions.
The first thing to remember is that XSLT variables do not store XPath expressions; instead, they always store one of the above five data types. In your case, the strings you've included each correspond to an XPath expression that would return a node-set. Thus, ultimately, you'll want your variable to contain a node-set, rather than a string. You only need one variable, rather than also an intermediate one containing an expression, which is impossible (except as a dumb string). But I see why you are attempting this. You need to conditionally determine which node-set to select as the value of your variable. The problem with this is that conditional processing is done using XSLT element instructions. As soon as you begin talking about having elements as children of xsl:variable, you've lost the chance to map the variable's value to a node-set, because an xsl:variable that contains anything will always be an RTF, as you correctly point out. (But you don't want an RTF, even if it's converted to a node-set, because it won't be converted to the node-set you're thinking of, but to a node-set containing only one node, the root node of that tree, instead of a node-set containing multiple NOTES elements). Thus, you must figure out a way to achieve the node-set you're looking for by using XPath alone and no XSLT instructions. I succeeded in doing this by adapting an example from Mike Kay's book, page 551. Try this:
Source:
<TABLE> <NOTES TEMPLATE="foo">1</NOTES> <NOTES TEMPLATE="bar">2</NOTES> <NOTES>3</NOTES> <NOTES>4</NOTES> <NOTES TEMPLATE="bar">5</NOTES> <NOTES TEMPLATE="foo">6</NOTES> <NOTES>7</NOTES> </TABLE>
Stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:param name="filter_template"/> <xsl:variable name="filtered_notes" select="//TABLE/NOTES[$filter_template and @TEMPLATE=$filter_template] | //TABLE/NOTES[not($filter_template)]"/> <xsl:template match="/"> <xsl:for-each select="$filtered_notes"> <xsl:copy-of select="."/> </xsl:for-each> </xsl:template> </xsl:stylesheet>
The XPath expression contains the union of both node-sets, one of which will always be empty, depending on whether filter_template was assigned or not, and the other of which will contain either all the NOTES elements or only those that have a certain TEMPLATE attribute value.
Here are the results after assigning no value, "foo", and "bar", respectively.
C:\>saxon test.xml test.xsl <?xml version="1.0" encoding="utf-8" ?><NOTES TEMPLATE="foo">1</NOTES><NOTES TEM PLATE="bar">2</NOTES><NOTES>3</NOTES><NOTES>4</NOTES><NOTES TEMPLATE="bar">5</NO TES><NOTES TEMPLATE="foo">6</NOTES><NOTES>7</NOTES>
C:\>saxon test.xml test.xsl filter_template=foo <?xml version="1.0" encoding="utf-8" ?><NOTES TEMPLATE="foo">1</NOTES><NOTES TEM PLATE="foo">6</NOTES>
C:\>saxon test.xml test.xsl filter_template=bar <?xml version="1.0" encoding="utf-8" ?><NOTES TEMPLATE="bar">2</NOTES><NOTES TEM PLATE="bar">5</NOTES>
It seems rather limited, but in this case it works! Enjoy.
Mike Kay adds, simply:
You can't do this in standard XSLT, all XPath expressions must be explicit "at compile time"
Mike Kay
Never use curly braces inside an XPath expression, and never use anything inside an <xsl:value-of> instruction: it must be empty.
David Carlisle
> select="/docstructure/define[@id='{@defined}']"/> > This tests the id attribute against the string '{@defined}'
but you want to test against the defined attribute of the current node which is select="/docstructure/define[@id=current()/@defined]"/>
You _never_ use { } in an xpath expression.
Andrew Kimball
An error was reported: > Expected token 'eof' found '['. //-->[<-- ancestor::sidebar[1]]
Because of a loophole in the spec, .[ancestor::sidebar[1]] is not a valid XPath expression. The July release allowed this syntax, but for the September release I tightened MSXML's conformance.
Use self::node()[ancestor::sidebar[1]] instead.
Wendell Piez adds
.[ancestor::sidebar[1]] expands to
self::node()[ancestor::sidebar[1]]
which translates into English as
"Are you a node with an ancestor sidebar that's your first sidebar ancestor?"
This could be simplified as
ancestor::sidebar[1]
which translates as
"Do you have an ancestor named sidebar that's the first sidebar ancestor?"
But of course, if there are any sidebar ancestors, there's a first one: why not just ask
ancestor::sidebar "Do you have any sidebar ancestors?"
Now, you may actually mean
ancestor::*[1][self::sidebar]
which is XPath for
"Is your first ancestor element a sidebar?"
Or even better:
parent::sidebar
"Do you have a parent 'sidebar'?"
It could turn up as a gotcha anytime. "No predicates after abbreviated steps . or .."
So .[ancestor::sublist[1]] should be rejected by a conforming processor.
Andrew explains the loophole in the rec
The loophole exists in the XPath BNF:
[4] Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep [12] AbbreviatedStep ::= '.' | '..'
The AbbreviatedStep may not have a predicate after it, unlike a regular NodeTest Step. I can't think of a reason why this shouldn't be allowed, so I assume it was an oversight by the W3C committee. Maybe it will be fixed in Errata or in a future version of XPath.
Michael Kay
> following::{.XXX/YYY/ZZZ}
yet another creative attempt at making XSLT generate XPath expressions dynamically. It can't be done (except with the saxon:evaluate() extension).
Michael Kay
> <xsl:param name="@ident"/>
Saxon extends the things you can do at run-time considerably, compared to the XSLT standard, but declaring variables whose name is decided at run-time is definitely out of bounds!
A lot of people seem to thing of variables as textual substitution macros. They aren't. It can only be a matter of time before someone tries:
<xsl:$declare name="x" select="y"/> with $declare set to "variable" or "param"
Mike Kay
Is there any way to choose which file to include in my XSL file (using xsl:import, xsl:include, or anything else)? I am looking for the fastest/best possible way to include one of approximately 40 files at runtime, based on my XML, i.e., the name of the file I want would be in the XML stream.
Mike answers. The basic processing model of XSLT (like many other languages!) is that it builds and compiles the stylesheet before it starts reading the input data. If you want to construct a stylesheet whose contents depend on the input data then you'll need to do this in a separate transformation step.
Mike Kay
Does xsl have any regular expression compatible functions?
No, it doesn't. It's on the requirements list for 2.0
David Carlisle
No. Some systems give an extension function to get this, otherwise you need to pass it in as a parameter.
Michael Kay
> Is it possible to include a parameter inside of a xsl:include element? > > Something like: > > <xsl:include href="$something/sub/file.xsl"/>
No. xsl:include is a compile-time facility, not run-time.