Question

I have a Subversion changelog in xml format, created with

svn log http://svnurl -r {2014-01-01}:{2014-05-01} --xml > changelog.xml

This gives me an XML file with

<?xml version="1.0" encoding="UTF-8"?>
<log>
<logentry
   revision="1234">
<author>foo</author>
<date>2014-02-14T13:19:30.288981Z</date>
<msg>Commit by foo</msg>
</logentry>
<logentry
   revision="1235">
<author>bar</author>
<date>2014-02-14T13:57:54.506257Z</date>
<msg>Commit1 by bar</msg>
</logentry>
<logentry
   revision="1236">
<author>bar</author>
<date>2014-03-14T13:57:54.506257Z</date>
<msg>Commit2 by bar</msg>
</logentry>
</log>

I would like to transform this to a HTML file:

<html>
<body>
<h2>Change log by author</h2>
<ul>
  <li><h3>foo</h3>
    <ul>
      <li>Commit by foo</li>
    </ul>
  </li>
  <li><h3>bar</h3>
    <ul>
      <li>Commit1 by bar</li>
      <li>Commit2 by bar</li>
    </ul>
  </li>
</ul>
</body>
</html>

This is what I came up with after a couple of hours of googling and stackoverflowing (no previous xml knowledge):

<xsl:stylesheet version="2.0" 
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<html xmlns="http://www.w3.org/1999/xhtml">
    <body>
        <h2>Change log</h2>
        <ul>
            <xsl:template match="/">
                    <xsl:for-each-group select="log/logentry" group-by="author">
                        <li><h3><xsl:value-of select="author"/></h3>
                            <ul>
                                <xsl:for-each select="current-group()">
                                    <li><xsl:value-of select="msg"/></li>
                                </xsl:for-each>
                            </ul>
                        </li>
                    </xsl:for-each-group>
            </xsl:template>
        </ul>
    </body>
</html>
</xsl:stylesheet>

I tested this with XML Notepad but unfortunately I get no output. Also Internet Explorer and Chrome don't transform the file. What's the obvious thing that I'm missing here?

EDIT: I dumped Microsoft XML Notepad and installed a 30 day evaluation version of Altova Missionkit. With that, and while following an example about The Muenchian Method I found on http://www.jenitennison.com/xslt/grouping/muenchian.html, I came up with this:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:key name="changelog-by-author" match="logentry" use="author" />
 <xsl:template match="log">
    <xsl:for-each select="logentry[count(. | key('changelog-by-author', author)[1]) = 1]">
                <xsl:sort select="author" />
                <h2><xsl:value-of select="author" /></h2>
                <ul>
                    <xsl:for-each select="key('changelog-by-author', author)">
                        <xsl:sort select="msg" />
                        <li><xsl:value-of select="msg" /></li>
                    </xsl:for-each>
                </ul>
            </xsl:for-each>    
 </xsl:template>
</xsl:stylesheet>

The resulting HTML is now what I was looking for.

What wasn't in my original question, but what I would like to add, is the revision number. I'll add that when I find it.

Was it helpful?

Solution

It's not working in the browsers because of lack of support for XSLT 2.0. As of this date, Internet Explorer and Chrome don't yet have native support for XSLT 2.0. For it towork in these browsers you will have to use Muenchian grouping in XSLT 1.0 to group your log-entries, since XSLT 1.0 doesn't support for-each-group.

Besides that, your transformation is incorrect because the HTML tags are outside the <xsl:template>. If you place them inside the template it will work (in a XSLT 2.0 compatible processor):

<xsl:stylesheet version="2.0" ... >
    <xsl:template match="/">
    <html >
        <body> ... </body>
    </html>
    </xsl:template>
</xsl:stylesheet>

An alternative way of doing the transformation is to use literal result elements. In this case you don't need a full XSLT template. You should place the XSLT namespace and version before you use the XSL tags in your document:

<html xsl:version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <body>
        <h2>Change log</h2>
        <ul>
            <xsl:for-each-group select="log/logentry" group-by="author">
                <li><h3><xsl:value-of select="author"/></h3>
                    <ul>
                        <xsl:for-each select="current-group()">
                            <li><xsl:value-of select="msg"/></li>
                        </xsl:for-each>
                    </ul>
                </li>
            </xsl:for-each-group>
        </ul>
    </body>
</html>

OTHER TIPS

I totally ditched Windows and I'm now on Linux. For future reference, this is how I transformed the XML file as a bash oneliner. I'm posting it here because I searched on StackOverflow and couldn't find either any good questions or any good anwers.

java -jar ~/Downloads/SaxonHE9-5-1-6J/saxon9he.jar \
    changelog.xml changelogbyauthor.xsl | tidy -ic -o changelog.html
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top