An XSLT problem statement

I have an interesting problem statement. Have a look at the xml below:
(test.xml)

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <table>
        <row>
            <title>Mr</title>
            <forename>John</forename>
            <surname>Smith</surname>
        </row>
        <row>
            <title>Dr</title>
            <forename>Amy</forename>
            <surname>Jones</surname>
        </row>
        <family>Big Bears</family>
    </table>
    <table>
        <row>
            <title>Mrs</title>
            <forename>Santha</forename>
            <surname>Abraham</surname>
        </row>
        <row>
            <title>Miss</title>
            <forename>William</forename>
            <surname>Abraham</surname>
        </row>
        <family>Little Bears</family>
    </table>
    <table>
        <row>
            <title>Mr</title>
            <forename>Jim</forename>
            <surname>Smith</surname>
        </row>
        <row>
            <title>Mr</title>
            <forename>John</forename>
            <surname>Johnson</surname>
        </row>
        <row>
            <title>Mr</title>
            <forename>Johannsen</forename>
            <surname>Smith</surname>
        </row>
        <row>
            <title>Ms</title>
            <forename>Bert</forename>
            <surname>Smith</surname>
        </row>
        <row>
            <title>Ms</title>
            <forename>James</forename>
            <surname>Smithson</surname>
        </row>
        <family>Middle Bears</family>
    </table>
</root>

Now I want each entry in the table tag in a separate html table such that each row within the table tag creates a separate html row within the html table. The twist in the requirement is that separate html tables should be created for all row entries within a table tag that have the same surname. For example in the last table
entry Jim, Johannsen and Bert share the Smith surname so they will be placed within a separate html table while John and James will be placed in their own separate html tables as their surnames differ from each other and also with “Smith”.
Here is the xsl that will do exactly that:
(mytest.xsl)

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    <xsl:apply-templates select="//root/table" />
    <xsl:template match="table">
        <xsl:variable name="familynamevar" select="family/text()" />
        <xsl:for-each
            select="row[not(surname/text()=preceding-sibling::row/surname/text())]">
            <xsl:variable name="surnamevar" select="surname/text()" />
            <xsl:call-template name="family-surname">
                <xsl:with-param name="familynamevar" select="$familynamevar" />
                <xsl:with-param name="surnamevar" select="$surnamevar" />
            </xsl:call-template>
        </xsl:for-each>
    </xsl:template>
    <xsl:template name="family-surname">
        <xsl:param name="familynamevar" />
        <xsl:param name="surnamevar" />
        <table border="1" width="100%">
            <tr>
                <td colspan="3">
                    <B>
                        <xsl:value-of select="$familynamevar" />
                        -
                        <xsl:value-of select="$surnamevar" />
                    </B>
                </td>
            </tr>
            <xsl:for-each
                select="//root/table[family/text() = $familynamevar]/row[surname/text()=$surnamevar]">
 
                <tr>
                    <td width="10%">
                        <xsl:value-of select="title/text()" />
                    </td>
                    <td width="40%">
                        <xsl:value-of select="forename/text()" />
                    </td>
                    <td width="50%">
                        <xsl:value-of select="surname/text()" />
                    </td>
                </tr>
 
            </xsl:for-each>
        </table>
        <br />
    </xsl:template>
</xsl:stylesheet>

The java class that does this work is:

package transform;
 
import java.io.*;
// Import for XML
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
 
public class TestClass {
    public static StringBuffer getContent(BufferedInputStream in, String xsl)
            throws Exception {
        try {
            TransformerFactory tFactory = null;
            Transformer transformer = null;
            tFactory = TransformerFactory.newInstance();
            transformer = tFactory.newTransformer(new StreamSource(xsl));
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            transformer.transform(new StreamSource(in), new StreamResult(baos));
            // Output content
            StringBuffer buf = new StringBuffer();
            buf.append(baos.toString());
            baos.close();
            return buf;
        } catch (Exception e) {
            System.out.println("Exception in getContent");
            e.printStackTrace();
            return null;
        }
    }
 
    public static void main(String args[]) {
        BufferedInputStream xmlStream = null;
        /*
         * Open the files and initialize streams
         */
        try {
            // xml input file hard coded
            FileInputStream xmlFile = new FileInputStream("test.xml");
            xmlStream = new BufferedInputStream(xmlFile);
        } catch (Exception ex) {
            System.exit(-1);
        }
        String xsl = "mytest.xsl";// transformation xsl file hard coded
        StringBuffer output = null;
 
        try {
            output = getContent(xmlStream, xsl);
        } catch (Exception ex) {
            System.out.println("Exception during parsing");
        }
        try {
            // html output file hard coded
 
            PrintWriter out = new PrintWriter(new BufferedWriter(
                    new FileWriter("finally.html")));
            out.write(output.toString(), 0, output.toString().length());
            out.flush();
            out.close();
        } catch (Exception ex) {
            System.out.println("Exception during processing output stream");
        }
    }
}

Compile TestClass.java in transformer package. Run it, you get an output html that looks something like this:
(finally.html)

<table border="1" width="100%">
<tr>
<td colspan="3"><b>Big Bears –  Smith</B></td>
</tr>
<tr>
<td width="10%">Mr</td>
<td width="40%">John</td>
<td width="50%">Smith</td>
</tr>
</table>
<table border="1" width="100%">
<tr>
<td colspan="3"><b>Big Bears –  Jones</B></td>
</tr>
<tr>
<td width="10%">Dr</td>
<td width="40%">Amy</td>
<td width="50%">Jones</td>
</tr>
</table>
<table border="1" width="100%">
<tr>
<td colspan="3"><b>Little Bears –  Abraham</B></td>
</tr>
<tr>
<td width="10%">Mrs</td>
<td width="40%">Santha</td>
<td width="50%">Abraham</td>
</tr>
<tr>
<td width="10%">Miss</td>
<td width="40%">William</td>
<td width="50%">Abraham</td>
</tr>
</table>
<table border="1" width="100%">
<tr>
<td colspan="3"><b>Middle Bears –  Smith</B></td>
</tr>
<tr>
<td width="10%">Mr</td>
<td width="40%">Jim</td>
<td width="50%">Smith</td>
</tr>
<tr>
<td width="10%">Mr</td>
<td width="40%">Johannesen</td>
<td width="50%">Smith</td>
</tr>
<tr>
<td width="10%">Ms</td>
<td width="40%">Bert</td>
<td width="50%">Smith</td>
</tr>
</table>
<table border="1" width="100%">
<tr>
<td colspan="3"><b>Middle Bears –  Johnson</B></td>
</tr>
<tr>
<td width="10%">Mr</td>
<td width="40%">John</td>
<td width="50%">Johnson</td>
</tr>
</table>
<table border="1" width="100%">
<tr>
<td colspan="3"><b>Middle Bears –  Smithson</B></td>
</tr>
<tr>
<td width="10%">Ms</td>
<td width="40%">James</td>
<td width="50%">Smithson</td>
</tr>
</table>

big_bears
Of course the output html could look better. Try your hand at html in the xsl file if you prefer a more decorated outlook.

Get the source code here XSLT_example

About cuppajavamattiz
Matty Jacob - Avid technical blogger with interests in J2EE, Web Application Servers, Web frameworks, Open source libraries, Relational Databases, Web Services, Source control repositories, ETL, IDE Tools and related technologies.

Comments are closed.

%d bloggers like this: