xslt and things it can't do
1. | Things you cant do in XSLT | |||||
This section lists, in various forms, lots of things that can't be done with XSLT as it is today (Sept 2000) | ||||||
2. | XPATH expression from variable | |||||
> 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. | ||||||
3. | Change the value of a variable. | |||||
>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. | ||||||
4. | Moving entities from input file to output file | |||||
> 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. A recent addition to the field of processing is this from Andrew. Lets you pass them through, though they do need post processing | ||||||
5. | Non well formed HTML input | |||||
> 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. | ||||||
6. | Conditional Include | |||||
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. | ||||||
7. | Generate opening tags only | |||||
> 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. | ||||||
8. | Ampersand | |||||
> 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 "&". | ||||||
9. | Other oddments from Mike. | |||||
Other oddments from Mike. You can't do
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! | ||||||
10. | Call templates dynamically | |||||
> <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. | ||||||
11. | Two column table from unsorted data | |||||
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. | ||||||
12. | Parametrize the xsl:import or xsl:include | |||||
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. | ||||||
13. | Variable reference in the match attribute of a template. | |||||
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. | ||||||
14. | Numbering | |||||
> 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 preceeding axis. Similarly from is a pattern and cannot use the ancestor axis. | ||||||
15. | PDF output with Msxml | |||||
Can I create PDF output with Msxml ? No, not directly, but see my print page for how you can use any XSLT engine to produce XSL-FO, from which you can produce PDF. | ||||||
16. | Select mode by variable value | |||||
> <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. | ||||||
17. | Using a parameter as the select value of a sort | |||||
> 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]"/> | ||||||
18. | Double slash as an XPATH statement | |||||
> 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. | ||||||
19. | Apply templates with dynamic mode | |||||
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 explicitly 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 | ||||||
20. | Storing xpath expressions in a vaiable | |||||
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" | ||||||
21. | xsl:value-of and avts | |||||
Never use curly braces inside an XPath expression, and never use anything inside an <xsl:value-of> instruction: it must be empty. | ||||||
22. | Using xsl-attributes for apply-template select | |||||
> 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. | ||||||
23. | No predicates after abbreviated steps | |||||
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. | ||||||
24. | Dynamic name/value pairs on URL using following axis | |||||
> 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). | ||||||
25. | Parameter name decided at runtime | |||||
> <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" | ||||||
26. | Runtime include of a stylesheet | |||||
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. | ||||||
27. | Regex string function | |||||
Does xsl have any regular expression compatible functions? No, it doesn't. It's on the requirements list for 2.0 | ||||||
28. | Can I get the current document URL from within XSLT | |||||
No. Some systems give an extension function to get this, otherwise you need to pass it in as a parameter. | ||||||
29. | Can I use a parameter in xsl:include | |||||
> 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. | ||||||
30. | Can I test whether a variable has been defined | |||||
Can anyone please tell me how to test whether a variable has been defined? There is no such test. Variables in XSLT have scope based on their appearance in the stylesheet not on runtime behaviour, so there would be no point to such a test, you always know whether the variable is defined or not. | ||||||
31. | Apply imports on a named template | |||||
> Is there a way to do the equivalent of <xsl:apply-imports/> on a named > template? No, there isn't. | ||||||
32. | Dynamic stylesheet selection | |||||
> is it possible to choose one stylesheet or another based on input Not on input to XSL (it's too late by then) but of course your wrapper API might allow such a thing. > A subquestion of that is: is it possible to select different output > types depending on input Not in standard XSLT 1.0 but in the 1.1 proposals the attributes to xsl:output become AVT's so can be changed on the fly. However for the case you mention: > for a certain XML document, I > want to output XML, but for others, I want to output HTML. All you need do is not specify an output type, then if the top level result element is html (any case) it will default to html output type, otherwise it will use xml. | ||||||
33. | Does XSLT handle characters less than x0020 hex | |||||
>It seems to me that XSLT does not handle characters with reference less >than 0020(hex). I am using LotusXSL with Xalan and Xerces. > >Please have a look at my following example, " " is parsed but not >"f". Did I overlook something that causes such problem. Something rather basic. These characters are not valid in an XML document: Character Range [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */ Therefore you can't expect XSLT processors to handle them. | ||||||
34. | Can XSLT Remove DOCTYPE | |||||
> I cant find anyway XSLT can be > used to remove <!DOCTYPE.... > tags from input files. XSLT should never see these, since they are not part of the XPath data model. They are not intended for the application to see, anyway; they are for the XML parser's benefit. XSLT operates on parsed XML documents, not the raw input. For the same reason, character and entity references are not accessible from within XPath/XSLT. Jeni adds And just to spell out the implication of this... it means that if you copy an XML document using XSLT, then the copy of that document will not include the DOCTYPE declaration. So in effect, you can use XSLT to 'remove' the DOCTYPE declaration from a document with just one template: <xsl:template match="/"> <xsl:copy-of select="." /> </xsl:template> There may be other differences between the two documents because the DTD is missing - the generated document may have extra attributes because of default attributes within the DTD, and it will not have any entities aside from the built-in ones. But logically it will be the same document. | ||||||
35. | Defaulted attributes vs included attributes | |||||
> How can I specify that <xsl:copy-of select="@*" /> should NOT select and > copy default attributes (from the DTD) into the result document? > > I want only the attributes that are present in the instance (source > document). XSLT/XPath make no distinction between defaulted attributes and attributes actually declared in your instance, so you can't. | ||||||
36. | Can I specify the encoding with a variable value. | |||||
Can I use <xsl:output method="html" encoding="$charEncoding"/> you can't do that: you have to fix the output encoding. The XSLT 1.1 proposal would have allowed encoding="{$charEncoding}"/> but otherwise you may have to use a processor specific extension to allow that. | ||||||
37. | Can I nest elements within attributes | |||||
> I have the following code in my XSL file. > > <img name="<xsl:value-of select="."/>" src="arrow.gif"/> XML doesn't allow elements to be nested within attributes. You need an attribute value template: <img name="{.}" src="arrow.gif"/> | ||||||
38. | xmlns in an attribute | |||||
You can't. The namespace URI is conceptually part of the element name and you can't use xsl:copy if you want to change the name. You need to use <xsl:element name="local-name()" namespace="kjhgkjgkg"> ie generate a name with the local name from the source, and the new namespace URI. | ||||||
39. | Execution order | |||||
No. XSLT template rules follow an event-based processing model. A template rule says "if X is encountered, do this". The order of processing is determined by the order of events, not the textual order of the rules. There's one exception: if you have two template rules that match the same "event" (i.e. the same node in the source document), it's technically an error, but the processor can resolve the ambiguity by choosing the rule that comes last in the stylesheet.
Nothing done by a stylesheet ever affects the source tree. Templates write new nodes to the result tree, without changing the source tree. | ||||||
40. | Obtain the name of the xsl document. | |||||
No. Pass it as xsl:param. | ||||||
41. | Conditional Include | |||||
The answer is that it can't be done. As in most other programming languages, you can't change the code of the program based on the data that it reads at run-time. | ||||||
42. | document() only writes once? Is there no update? | |||||
xsl:result-document doesn't update a file, it creates a new file, overwriting any previous file at the same location. You aren't allowed to use the same URI more than once, or to use the URI of an input document, but Saxon doesn't currently detect these errors. The "no-side-effects" rule for XSLT applies to xsl:result-document just as much as to any other instruction. If you were allowed to update the same file several times, the results would depend on order of execution, which is taboo. > The word "last" is a give-away: you are making assumptions about the order of execution. > It's not a good idea to think of the end-tag </result-document> representing an instruction. But what is actually happening is that each time you evaluate the <xsl:result-document> instruction, the relevant file is being overwritten. Your example shows that you have incorrect assumptions about the document() function as well. If you call the document() function multiple times, you get the same node back each time. You can't use result-document to write a file, and then document() to read it back in. This is exactly like trying to update variables. | ||||||
43. | Check for links to same page in xsl-fo | |||||
No way in standard XSLFO. Recommended approaches are using a two-stage-approach or doing layout estimation in a stage before FO layout (usually XSLT). Neither is particularly attractive in general but may work fine for a narrow enough class of FO documents. | ||||||
44. | Include, with include file name from XML input | |||||
The answer is that it can't be done. As in most other programming languages, you can't change the code of the program based on the data that it reads at run-time. | ||||||
45. | Adding Tags? | |||||
Whenever anyone mentions the word "tag" in connection with xslt (which happens most days:-) it's almost always a sign that the design thinking is wrong, XSLT can not access the tags in the source document, and it can't directly generate tags in the result. XSLT inputs a node tree (typically but not always generated by an XML parser reading tags in an XML file) and generates a result tree, which might (it's an optional feature of an XSLT system) be linearised back to an XML file using tags as a final stage (conceptually) after the transformation. But the transformation itself just concerns trees. Node trees don't contain markup, so don't have tags, and you can't have half a node, so you can never insert a closing tag anywhere, in particular you can't insert one at the location of this comment. The way to put a group of nodes as child elements of another node is to first create the wrapper node <foo> then inside that select all the elements that should go in the group </foo> | ||||||
46. | displaying characters | |||||
These characters are not legal in XML 1.0, so they can't be present in the input or output of an XSLT transformation. | ||||||
47. | Read the XML declaration using XSL | |||||
The xml declaration is not represented in the XML Infoset -- therefore, it is not accessible to XPath and XSLT. Similarly, important parts of the DTD are also lost (such as the content model of elements), the exact lexical representation that was used for any empty element, the order of attributes in the source xml document, whether a namespace was declared on an element or was inherited. So, in brief, this is something belonging to the category "Irrelevent/Cannot be done in XSLT due to nonexistent information". |