Merge and sort multiple XML files using XSL

The problem is to combine and sort multiple XML files with XSL and output valid HTML, view with Firefox> = 3.5 and, if possible, IE> = 7. The answer should be as simple as possible (performance is not important).

A.xml file

<?xml version="1.0"?> <root> <tag>cc</tag> <tag>aa</tag> </root> 

B.xml file

 <?xml version="1.0"?> <root> <tag>xx</tag> <tag>bb</tag> </root> 

Index.xml file

 <?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="merge.xslt"?> <list> <entry>a.xml</entry> <entry>b.xml</entry> </list> 

File merge.xslt

 <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ph="http://ananas.org/2003/tips/photo"> <xsl:output method="html"/> <xsl:template match="list"> <html> <body> <xsl:apply-templates/> </body> </html> </xsl:template> <xsl:template match="entry"> <xsl:for-each select="document(.)/root/tag"> <!-- This will only sort the values of a single file --> <xsl:sort select="." data-type="text" order="ascending" /> - <xsl:value-of select="."/> <br/> </xsl:for-each> </xsl:template> </xsl:stylesheet> 

Current output:

  • aa

  • ss

  • bb

  • xx

Expected Result:

  • aa

  • bb

  • ss

  • xx

+7
source share
1 answer

The solution to this is a very short and easy conversion (absolutely no extension functions are required!):

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:template match="/*"> <html> <ul> <xsl:apply-templates select="document(entry)/*/tag"> <xsl:sort/> </xsl:apply-templates> </ul> </html> </xsl:template> <xsl:template match="tag"> <li><xsl:value-of select="."/></li> </xsl:template> </xsl:stylesheet> 

when this conversion is applied to the provided index.xml file :

 <list> <entry>a.xml</entry> <entry>b.xml</entry> </list> 

required, the correct result is obtained :

 <html> <ul> <li>aa</li> <li>bb</li> <li>cc</li> <li>xx</li> </ul> </html> 

, and it displays in any browser as :

  • aa
  • bb
  • cc
  • xx

Explanation : This solution uses the power of the standard XSLT document() function. strong> As defined in W3C XSLT 1.0 Recommendation:

When a document function has exactly one argument and the argument is node-set, the result is the union, for each node into the node-set argument, of the result of calling the document function with the first argument - this is the string value of node

This explains the effect of this snippet from our code :

 <xsl:apply-templates select="document(entry)/*/tag"> <xsl:sort/> </xsl:apply-templates> 

What happens here is that the argument to the document() function is the node-set of all entry children of the top element of index.xml . The result is a union of all document nodes.

therefore

 select="document(entry)/*/tag" 

selects all tag elements in all documents specified in index.xml . Then they are sorted (via xsl:sort ), and each element of the already sorted nodelist is processed by the template corresponding to the tag .

+8
source

All Articles