xmlxsltxml-parsingxml-namespacessaxon

Sort entries in an XML file using Saxon 12.9 and an XSLT 3.0 stylesheet


I'm trying to sort entries in an XML file using Saxon, Saxon:sort and an XSLT 3.0 stylesheet.

I need to sort the nodes by the date in the <blogger:filename> field, which has the date as part of a URL, i.e. /2011/01/post.html. The date sort can be ascending or descending.

One issue is a result of my efforts to use sort: "Error reported by XML parser: The element type "xsl:stylesheet" must be terminated by the matching end-tag". I have an end tag, but it's obviously incorrect.

Here is a fiddle: https://martin-honnen.github.io

My input.xml file:

 <?xml version='1.0' encoding='utf-8'?>
    <feed xmlns='http://www.w3.org/2005/Atom' xmlns:blogger='http://schemas.google.com/blogger/2018'>
      <id>tag:blogger.com,1999:blog-17477</id>
      <title>Test Blog</title>
    
      <entry>
        <id>tag:blogger.com,1999:blog-17477.post-670855911</id>
        <blogger:type>POST</blogger:type>
        <blogger:status>LIVE</blogger:status>
        <author>
          <name>Author</name>
          <uri></uri>
          <blogger:type>BLOGGER</blogger:type>
        </author>
        <title>Title Title</title>
        <content type='html'>Content Content Content Content Content</content>
        <blogger:metaDescription/>
        <blogger:created>2011-01-05T16:33:59.731Z</blogger:created>
        <published>2011-01-06T12:32:00.001Z</published>
        <updated>2011-01-06T12:32:00.138Z</updated>
        <blogger:location/>
        <category scheme='tag:blogger.com,1999:blog-17477683' term='News'/>
        <blogger:filename>/2011/01/a-post.html</blogger:filename>
        <link/>
        <enclosure/>
        <blogger:trashed/>
      </entry>
    

<entry>
        <id>tag:blogger.com,1999:blog-17477.post-670855911</id>
        <blogger:type>POST</blogger:type>
        <blogger:status>LIVE</blogger:status>
        <author>
          <name>Author</name>
          <uri></uri>
          <blogger:type>BLOGGER</blogger:type>
        </author>
        <title>Title Title</title>
        <content type='html'>Content Content Content Content Content</content>
        <blogger:metaDescription/>
        <blogger:created>2011-01-05T16:33:59.731Z</blogger:created>
        <published>2011-01-06T12:32:00.001Z</published>
        <updated>2011-01-06T12:32:00.138Z</updated>
        <blogger:location/>
        <category scheme='tag:blogger.com,1999:blog-17477683' term='News'/>
        <blogger:filename>/2011/01/z-post.html</blogger:filename>
        <link/>
        <enclosure/>
        <blogger:trashed/>
      </entry>

    <entry>
        <id>tag:blogger.com,1999:blog-17477.post-670855911</id>
        <blogger:type>POST</blogger:type>
        <blogger:status>LIVE</blogger:status>
        <author>
          <name>Author</name>
          <uri></uri>
          <blogger:type>BLOGGER</blogger:type>
        </author>
        <title>Title Title</title>
        <content type='html'>Some Content Content</content>
        <blogger:metaDescription/>
        <blogger:created>2022-01-05T16:33:59.731Z</blogger:created>
        <published>2022-01-06T12:32:00.001Z</published>
        <updated>2022-01-06T12:32:00.138Z</updated>
        <blogger:location/>
        <category scheme='tag:blogger.com,1999:blog-17477683' term='News'/>
        <blogger:filename>/2022/03/post.html</blogger:filename>
        <link/>
        <enclosure/>
        <blogger:trashed/>
      </entry>
    
    <entry>
        <id>tag:blogger.com,1999:blog-17477.post-670855911</id>
        <blogger:type>POST</blogger:type>
        <blogger:status>LIVE</blogger:status>
        <author>
          <name>Author</name>
          <uri></uri>
          <blogger:type>BLOGGER</blogger:type>
        </author>
        <title>Title Title</title>
        <content type='html'>Content Content Content Content Content</content>
        <blogger:metaDescription/>
        <blogger:created>2012-01-05T16:33:59.731Z</blogger:created>
        <published>2012-01-06T12:32:00.001Z</published>
        <updated>2012-01-06T12:32:00.138Z</updated>
        <blogger:location/>
        <category scheme='tag:blogger.com,1999:blog-17477683' term='News'/>
        <blogger:filename>/2012/06/apost.html</blogger:filename>
        <link/>
        <enclosure/>
        <blogger:trashed/>
      </entry>
    
    </feed>

stylesheet.xml:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xpath-default-namespace="http://www.w3.org/2005/Atom"
xmlns:blogger='http://schemas.google.com/blogger/2018'
exclude-result-prefixes="#all">

<xsl:mode on-no-match="shallow-copy"/>

    <xsl:template match="entry[blogger:filename]">
              <xsl:apply-templates select="blogger:filename">
        <xsl:sort select="blogger:filename" order="descending" />
                </xsl:apply-templates>            
  </xsl:template>
    
<xsl:output indent="yes"/><xsl:strip-space elements="*"/>

</xsl:stylesheet>

Solution

  • I suppose you want to do:

    <xsl:stylesheet version="3.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xpath-default-namespace="http://www.w3.org/2005/Atom"
    xmlns:blogger='http://schemas.google.com/blogger/2018'>
    <xsl:output indent="yes"/>
    
    <xsl:mode on-no-match="shallow-copy"/>
    
    <xsl:template match="/feed">
        <xsl:copy>
            <xsl:copy-of select="id, title"/>
            <xsl:apply-templates select="entry">
                <xsl:sort select="blogger:filename" order="descending" />
            </xsl:apply-templates>            
        </xsl:copy>
    </xsl:template>  
    
    </xsl:stylesheet>