Posts

Using accumulators to number items in a streamable way

Both in XSLT 1 and 2 you can use the powerful xsl:number instruction to count and number nodes. Of course, that instruction is also supported in XSLT 3 , however, if you want to use xsl:number with streaming then you will find that the streamability of that instruction is rather restricted:   xsl:number  can be used for formatting of numbers supplied directly using the  value  attribute, and also for numbering of nodes in a non-streamed document, but it cannot be used for numbering streamed nodes On the other hand, you will see in this article that using accumulators you can write a stylesheet to count and number nodes in XSLT 3 in a way that works with both streaming and non-streaming. As an example let's take a recent post on StackOverflow that wants to count and number the row and col elements in the input sample and transform it to a flat structure with the row  and col index as attributes on a data element: Using accumulators we can continue to use pa

Fun(ctional programming) with fold-left and transform

Over on StackOverflow someone asked how to apply an XSLT 1.0 stylesheet for merging two XML documents to all XML files in a directory . The approach there in the question as well as the answer is to use a shell script to run the stylesheet with Saxon on two files, then merge the result with a third file and so on. However, given that since XPath 3.1 we have the uri-collection function  to process a sequence of files and that XPath 3.1 even offers a transform function to perform a transformation directly in XSLT/XPath I thought it should also be possible to solve the problem completely in XSLT 3.0. Additionally the algorithm to process a sequence of input files, applying the merge transformation repeatedly to each file, accumulating the result, looked like an opportunity to use the fold-left function supported also in XSLT 3.0 since being included in the XPath 3 functions and operators specification. The original XSLT 1.0 stylesheet takes a primary input document and a with par

Using xsl:evaluate and the path() function to merge data from two documents with the same structure

On Stackoverflow there was a question to merge two documents with the same XML structure by copying text data from elements in a secondary input document to empty elements in the main input. I think this can be nicely done by using the path() function on empty elements together with the xsl:evaluate instruction (that is new in XSLT 3.0) to simply select and copy the text data from the secondary input document <xsl:template match="*[not(has-children())]"> <xsl:copy> <div class="merged"> <xsl:evaluate context-item="$doc2" xpath="path() || '/text()'"></xsl:evaluate> </div> </xsl:copy> </xsl:template> Full gist is The posted stylesheet works fine with Saxon 9.7 and later editions supporting xsl:evaluate (PE and EE) and with current versions of Altova XMLSpy/Raptor.

Extracting sub trees of a document using snapshot()

In this post I will explore how the new snapshot function in XSLT 3.0 makes life easier with tasks like extracting sub trees from a document, for instance to split up a file into several, each containing a sub tree from the original file. So let's assume we have some input data as follows: and we want to split it up into several documents, each containing a page element in its sub tree, for instance: With XSLT 2.0 we would have to reconstruct the sub tree a page element is contained in, now with XSLT 3.0's snapshot function it is as easy as: So we simply process each page element and in the matching template we create a result document containing the sub tree of the page by using         <xsl:result-document href="pages/page{position()}.xml">             <xsl:copy-of select="root(snapshot())"/>         </xsl:result-document> It is also easy to adapt the stylesheet to work with streaming , to make our apply-templates