1

Hello and thank you for reading this question:

I am studying Enterprise Architecture Patterns and I have implemented the Transform View one:

Java: Implementing Transform View pattern, to convert XML to HTML with an XSL file

First, in the first 10 slides, I will describe what have I learnt, then an example taken from books and finally the approach I have tryed to implement it by myself, and the doubts I have with the Java code:

I have studied how is it described in UML, an example would be, (images taken from teacher's lessons):

We have an album which is read and then converted to an intermediate format and then it is being process in a generic way:

enter image description here

In more details if we have a Shop Page, each Order would have Line Items and those being transformed to our format file: Order First Stage. Then the generated Table with its rows would being translated to the HTML without knowing where it comes from:

enter image description here

So then it means that the controller creates our order first stage, our format file. Then, we get the Order Data and the Line Item data to create our new Table with its Rows. After that the Controller creates the Second Stage, which gets the Table and Row, and add them both to response HTML:

enter image description here

The reason we are interested in learning this pattern, is because of it is a handy way to convert in a single spot all our web app's style:

enter image description here

In the previous slide we see how we would only need to change Second Stage XSL file to display a new style in all our app's pages.

In deep, we could interchange whatever new XSL and thus app's styles we would like to put in production:

enter image description here

As an example extracted from books, here we see an album:

enter image description here

So the First Stage XSL would convert album's XML tags to an intermediate format, with has more generic tags like: screen, table, row...

enter image description here

After the above transformation the output XML would be:

enter image description here

In addition as we are interested in process the generic XML using a single spot the Second Stage:

enter image description here

After all the previous steps we eventually need to implement the logic in Java, and as the example gives us a clue it would look like:

enter image description here

So then, I tried the following:

First here we have the XML which represents ficticious pupils' info:

<?xml version="1.0"?>
<ALUMNO>
    <NOMBRE>Luis</NOMBRE>
    <APELLIDO1>Navarro</APELLIDO1>
    <APELLIDO2>Morote</APELLIDO2>
    <ASIGNATURAS>
        <ASIGNATURA>PR4</ASIGNATURA>
        <NOTA>5</NOTA>
        <ASIGNATURA>BD2</ASIGNATURA>
        <NOTA>8</NOTA>
        <ASIGNATURA>IR</ASIGNATURA>
        <NOTA>10</NOTA>
    </ASIGNATURAS>
</ALUMNO>

Then we do the First Stage XSL to convert pupils' tags in an intermediate file format:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet 
    xmlns:xsl=
    "http://www.w3.org/1999/XSL/Transform" 
    version="1.0"
>

    <xsl:template match="ALUMNO">
        <table>
            <xsl:apply-template/>
        </table>
    </xsl:template>

    <xsl:template match="NOMBRE">
        <firstCell>
            <xsl:apply-templates/>
        </firstCell>
    </xsl:template>

    <xsl:template match="APPELLIDO1">
        <secondCell>
            <xsl:apply-templates/>
        </secondCell>
    </xsl:template>

    <xsl:template match="APPELLIDO2">
        <thirdCell>
            <xsl:apply-templates/>
        </thirdCell>
    </xsl:template>


    <xsl:template match="ASIGNATURA">
        <fourthCell>
            <xsl:apply-templates/>
        </fourthCell>
    </xsl:template>

    <xsl:template match="NOTA">
        <fifthCell>
            <xsl:apply-templates/>
        </fifthCell>
    </xsl:template>



</xsl:stylesheet>

After the previous step, we process with the Second Stage the generic tags to style the way we want, as a table:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet 
    xmlns:xsl=
    "http://www.w3.org/1999/XSL/Transform" 
    version="1.0"
>

    <xsl:template match="/">
        <html>
            <head>
                <title>LISTA DE ALUMNOS</title>
            </head>
            <body bgColor="black" text="white">
                <table>
                    <tr>
                        <th colspan="4">Nombre</th>
                        <th colspan="3">Primer apellido</th>
                        <th colspan="3">Segundo apellido</th>
                        <th colspan="2">Asignatura</th>
                        <th colspan="2">Nota</th>
                    </tr>
                    <xsl:apply-templates />
                </table>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="table">
        <tr>
            <td colspan="4">
                <xsl:value-of select="firstCell" />
            </td>
            <td colspan="3">
                <xsl:value-of select="secondCell" />
            </td>
            <td colspan="3">
                <xsl:value-of select="thirdCell" />
            </td>
            <td colspan="2">
                <xsl:value-of select="fourthCell" />
            </td>
            <td colspan="2">
                <xsl:value-of select="fifthCell" />
            </td>
        </tr>
    </xsl:template>


    <xsl:template match="firstCell">
        <P>
            <B>Nombre: </B>
            <TR>
                <xsl:apply-templates/>
            </TR>
        </P>
    </xsl:template>

    <xsl:template match="fourthCell">
        <h1>Aginatura: </h1>
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:template match="fifthCell">
        <h2>Nota: </h2>
        <xsl:apply-templates/>
    </xsl:template>

    <xsl:output method="html"/>

</xsl:stylesheet>

Now here arrives our doubt: How could we transform the Result of transforming the original XML with the First Stage's XSL, using the Second Stage's XSL to output our desired HTML?.

I have tried:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package frontController;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

/**
 *
 * @author YonePC
 */
@WebServlet(name = "AlumnosCommand", urlPatterns = {"/AlumnosCommand"})
public class AlumnosCommand extends FrontCommand {

    /**
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code>
     * methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

    }

// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

    @Override
    public void process(HttpServletRequest request) {
        try {

            TransformerFactory factory = TransformerFactory.newInstance();
            StreamSource xslFirstStage = new StreamSource(new File("C:\\Users\\YonePC\\Videos\\ASAPLICACIONCURSOSPRACTICA1\\src\\java\\frontController\\FirstStageAlumnos.xsl"));
            StreamSource xslSecondStage = new StreamSource(new File("C:\\Users\\YonePC\\Videos\\ASAPLICACIONCURSOSPRACTICA1\\src\\java\\frontController\\Alumnos.xsl"));
            Transformer firstTransformer = factory.newTransformer(xslFirstStage);
            Transformer secondTransformer = factory.newTransformer(xslSecondStage);

            StreamSource xml = new StreamSource(new File("C:\\Users\\YonePC\\Videos\\ASAPLICACIONCURSOSPRACTICA1\\src\\java\\frontController\\Alumnos.xml"));
            PrintWriter writer = response.getWriter();
            Result result = new StreamResult(writer);


            OutputStream afterFirstStage = new FileOutputStream("C:\\Users\\YonePC\\Videos\\ASAPLICACIONCURSOSPRACTICA1\\src\\java\\frontController\\afterFirstStage.xsl");
            firstTransformer.transform(xml, new StreamResult(afterFirstStage));
            secondTransformer.transform(afterFirstStage, xslSecondStage);
            writer.println(writer.toString());

        } catch (IOException ioe) {
            ioe.printStackTrace();
        } catch (TransformerException te) {
            te.printStackTrace();

        }
    }

}

As the IDE says when we use Transformer.transform() first parameter should be a Source and second a StreamSource.

Here the IDE says: incompatible types: cannot convert OutputStream to Source.

enter image description here

Could you help me please?

I have also read to do it by myself: How to convert XML to HTML using XSLT in Java

http://www.javased.com/index.php?api=javax.xml.transform.Result

Yone
  • 2,064
  • 5
  • 25
  • 56

1 Answers1

1

If you want to work with an intermediary file then of course you need to close that output stream after the first transformation and open a new StreamSource on the file you have created to be then used as the input for the second transformation.

With the JAXP and SAX based Transformers you can however avoid the use of an intermediary file and simply set up some handlers (https://docs.oracle.com/javase/8/docs/api/javax/xml/transform/sax/SAXTransformerFactory.html) e.g.

TransformerHandler tfh = (SAXTransformerFactory)transformerFactory.newInstance().newTransformer(new StreamSource("second.xsl"));
tfh.setResult(new StreamResult("finalOutput.xml"));

firstTransformer.transform(inputSource, new SAXResult(tfh));
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110