Example of XSL-transforming in ADF applications – downloading Excel (CSV) files from ADF Web Applications

11

One of our recent projects based on Oracle ADF (JSP, Struts, ADF BC and ADF Binding Framework on top of an Oracle Database) had as one of its requirements the ability to download certain sets of data in Excel-file format (basically a Comma Separated Values file). In this post I discuss how the ADF Binding Framework and the ADF Business Components Model can be used to import model-data as XML into a JSP and more specifically into JSTL-XML tags. It then shows how you can import a simple XSL-T Stylesheet into this JSP to have the XML data from the Model transformed in a CSV format. A sample project can be downloaded.

Note: although this post gives a fine example I believe of how to use the ViewObject writeXML method through the ADF Binding Framework to get hold of data in XML Document in a JSP page and use JSTL XML tags to perform a transformation, it is by no means the best way to render csv-files. Producing csv-files can be done in a much easier way, I will demonstrate in a post soon to be published. So use this post to understand how an XML Document can be retrieved from ADF and transformed in the JSP, but not in order to produce csv-files! In yet another post I will show to use the method demonstrated in this article for rendering SVG objects, a more to the point application of this technique.

The method for getting hold of the Model-data in XML format is largely based on the exchange I had with Steve Muench. The article proposes an alternative to for example the use of JSTL’s SQL tags to select data that is then transformed into XML Document variables within a JSP. Those tags completely bypass the ADF Binding Framework and even the ADF BC Business Service. The approach followed in this post is completely in line with ADF. We can make use of the writeXML() method on the ViewObject. This method returns an XML Document with the data from the current VO Row as well as all of its details through the ViewLinks defined for the ViewObject, for as many levels as is required.

The demo project: EMP and DEPT

As usual I have chosen EMP and DEPT (the standard SCOTT schema) as my example. I will construct a simple Web Application (JSP, Struts) using JDeveloper 10.1.2. My Model project will contain two ViewObjects, DeptView and EmpView, with a ViewLink between them (Dept is the Source, Emp the Destination). I have created these ADF Business Components in the Model project from a SCOTT_LOCAL connection that links to the SCOTT schema in my local database. From the New Gallery I have picked Business Tier, Business Components, Business Components from Tables and selected the EMP and DEPT table from this connection.

Next, I have edited the ViewObject DeptView: I have added a transient attribute DeptXml of type org.w3c.dom.Document. I had the wizard generate the DeptViewRowImpl class. In that class, I have edited the code for the getDeptXml method:

  public Document getDeptXml() {

    HashMap h = new HashMap();
    h.put("nl.amis.empdept.model.DeptView",
          new String[]{"Deptno",
                       "Dname",
                       "Loc",
                       "EmpView"});
    h.put("nl.amis.empdept.model.EmpView",
          new String[]{"Empno",
                       "Ename",
                       "Sal",
                       "Job",
                       "Hiredate"});
    Node n = writeXML(XMLInterface.XML_OPT_ALL_ROWS,h);
    Document d = n.getOwnerDocument();
    n = ((XMLDocument)d).adoptNode(n);
    d.appendChild(n);
    return (Document)d;

  }

The ViewController project

In the struts-config.xml visual editor, I drag and drop a new DataPage to the canvas. I double click and go to the JSP editor; I call the JSP deptCsvExcel.jsp . Next, I drag and drop the DeptView’s DeptXML datacontrol to the JSP. This will create the required data binding in the page’s UI Model (aka Binding Container). Then I remove the <c:out value="${bindings.DeptXml}"/> from the JSP. Well actually, I remove everything and replace it with:

&lt;%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%&gt;&lt;%@ taglib uri="http://java.sun.com/jstl/xml" prefix="x"%&gt;&lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%&gt;
&lt;%@ page contentType="application/vnd.ms-excel" %&gt;&lt;% response.setHeader("Content-disposition","attachment; filename=" + "employees.csv"); %&gt;
&lt;c:set var="voxml" value="${bindings.DeptXml.attributeValue}"/&gt;
&lt;c:import var="xslt" url="DeptEmp.xsl" /&gt;
&lt;x:transform xml="${voxml}" xslt="${xslt}" /&gt;

In this JSP, I get hold of the XML Document that I get offered from the DeptXml data control on the DeptView in the page variable voxml. I then import the XSLT stylesheet DeptEmp.xsl in another page-scope variable xslt and transform voxml with xslt. Note that in the beginning of the JSP I have set the mime-type of the JSP to application/vnd.ms-excel and the file-type that is displayed in the Save As dialog in the Browser to employees.csv. Note: in my application I had to remove all linefeeds from the JSP in order to prevent unwanted empty rows from appearing in the CSV-file!

The XSL-T stylesheet I used is very straightforward:

&lt;?xml version="1.0"?&gt;
&lt;xsl:stylesheet version = "1.0" 	xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"&gt;
&lt;xsl:output method="text"/&gt;
&lt;xsl:strip-space elements = "gazetteer"/&gt;
&lt;xsl:template match="/"&gt;
&lt;xsl:for-each select="DeptViewRow/EmpView/EmpViewRow"&gt;
&lt;xsl:text/&gt;&lt;xsl:value-of select="normalize-space(Ename)"/&gt;,&lt;xsl:text/&gt;
&lt;xsl:value-of select="normalize-space(Job)"/&gt;,&lt;xsl:text/&gt;
&lt;xsl:value-of select="normalize-space(Hiredate)"/&gt;,&lt;xsl:text/&gt;
&lt;xsl:value-of select="normalize-space(Sal)"/&gt;
&lt;xsl:text disable-output-escaping = "yes" &gt;
&lt;/xsl:text&gt;
&lt;/xsl:for-each&gt;
&lt;/xsl:template&gt;
&lt;/xsl:stylesheet&gt;

I then went back to the Struts-Config editor and created a second datapage – runDownloadCsv and runDownloadCsv.jsp. I drag and dropped DeptView onto this page as ReadOnly Form. I dragged it again, as Navigation Buttons. This gives me a simple webpage that shows the current department and allows me to browse through the set of departments with Next/Previous and First/Last buttons.

I returned to the struts-config editor and added a PageLink from the runDownloadCsv data page (runDownloadCsv.jsp) to the other dataPage (dataPage1 or deptCsvExcel.jsp). This created a link in the runDownloadCsv.jsp that starts the second JSP – which means it starts the download and automatic opening of Excel.

When I run the JSP runDownloadCvs.jsp, I get the following situation in the browser:

I have navigated to Department 20 and now I click on the Download CSV link:

Click on Open. Excel is started and displays the document. The Excel document contains the Employee data for the Employees in the current department.

Important: to have the XML JSTL tags function correctly, I have to set a Java runtime option on the Runner tabsheet in the Project Properties dialog for the View Controller project: -Dorg.xml.sax.driver=oracle.xml.parser.v2.SAXParser (in the textbox labeled Java Options).

Download the Sample Workspace for Oracle 10g JDeveloper 10.1.2: CsvExcelAdfDemo.zip

Note: The above is useful primarily as example of using writeXML() on the ViewObject to publish an XML Document, bind it to a JSP and transform it using JSTL XML tags. If all you want to do is publish csv files, there is a much easier way, using plain DataControls based on ViewObject attributes – no XML involved. The JSP would look as follows to produce a CSV file for the employees in the selected department:

&lt;%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>&lt;%@ taglib uri="http://java.sun.com/jstl/xml" prefix="x"%>&lt;%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
&lt;%@ page contentType="application/vnd.ms-excel" %>&lt;% response.setHeader("Content-disposition","attachment; filename=" + "employees.csv"); %>
&lt;c:forEach var="Row" items="${bindings.EmpView2.rangeSet}">
&lt;c:out value="${Row['Ename']}"/>,&lt;c:out value="${Row['Job']}"/>,&lt;c:out value="${Row['Hiredate']}"/>,&lt;c:out value="${Row['Sal']}"/>
&lt;/c:forEach>

remove all linefeeds, except the one after <c:out value="${Row['Sal']}"/>

Resources

See Steve Muench’s article in response to my initial questions: Questions on Exposing XML via Transient Attribute. It all started with one of Steve’s Not Yet Documented ADF Sample Applications:

Using ViewObject writeXML and JSTL XML Tag Library – Illustrates how to use the ViewObject writeXML() method to produce a multi-level XML message for an HR schema-based data model having Departments -> EmployeesInDepartment -> DirectReports->DirectReportJobHistory with a second detail collection under Departments of Deparments -> EmployeesJobHistory. This XML document is then set as a request attribute so that the JSTL XML library can render the multi-level information using XPath expressions. The sample contains both Struts and Model 1 examples (requires the HR schema).

A very useful article on creating an XSLT for transforming to a CSV file format: Conversion of XML to CSV – An XSLT example by Peter Burden

Share.

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director for Fusion Middleware. Consultant, trainer and instructor on diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, BPM, ADF, Java in various shapes and forms and many other things. Author of the Oracle Press book: Oracle SOA Suite 11g Handbook. Frequent presenter on conferences such as JavaOne, Oracle OpenWorld, ODTUG Kaleidoscope, Devoxx and OBUG. Presenter for Oracle University Celebrity specials.

11 Comments

  1. Hi,

    I am much impressed by going throught your blog. I am novice in XSLT.

    Kindly send me the code for Converting XML Data to Excel using XSLT Stylesheet.

    Thanks in Advance,

  2. This is good document for understanding the conversion of jsp data to excel sheet.
    regards
    afzal

  3. Uploading csv –> database can basically be done by this strategy.

    1. Read the csv line by line using a BufferedReader object and a StringReader object.
    2. For each line, search for the separator character (, or ; or whatever you are using) by using the split method of String. This method splits a given String (the read String) around matches of a given regular expression: the separator character. The splitted String objects are stored in a String array.
    3. Finally, while looping over the String array, insert the column values into the database table, using either plain JDBC or your favorite object-relational mapping framework.
    4. Commit the transaction, clean-up resources, etc.

  4. Nice example.
    Do you have an example of uploading a csv file and save the contents to the database?

    Thanks.

  5. I am converting XML to CSV file,At the time of transformation I am getting CR-LF character as “square box” in CSV file which i don’t want? What should i do for that?

    Kindly help ASAP.

  6. Sonal Mehta on

    To remove this problem, please remove method=”POST” from your form tag , if u r using it.

  7. Manikandan on

    Hi,

    I am facing one problem while downloading .csv file in Struts.
    Download option window is appearing 2 times. Once i clicked “Open” button in first window, 2nd window is appearing imm’ly.
    If i click “Open” button in 2nd window, then only i am able to open csv file.
    Can you pls help reg this problem?

    Thanks,
    Manikandan

  8. Note: although this post gives a fine example I believe of how to use the ViewObject writeXML method through the ADF Binding Framework to get hold of data in XML Document in a JSP page and use JSTL XML tags to perform a transformation, it is by no means the best way to render csv-files. Producing csv-files can be done in a much easier way, I will demonstrate in a post soon to be published. So use this post to understand how an XML Document can be retrieved from ADF and transformed in the JSP, but not in order to produce csv-files! In yet another post I will show to use the method demonstrated in this article for rendering SVG objects, a more to the point application of this technique.

  9. Note: although this post gives a fine example I believe of how to use the ViewObject writeXML method through the ADF Binding Framework to get hold of data in XML Document in a JSP page and use JSTL XML tags to perform a transformation, it is by no means the best way to render csv-files. Producing csv-files can be done in a much easier way, I will demonstrate in a post soon to be published. So use this post to understand how an XML Document can be retrieved from ADF and transformed in the JSP, but not in order to produce csv-files! In yet another post I will show to use the method demonstrated in this article for rendering SVG objects, a more to the point application of this technique.

  10. Pingback: » Much better way of producing CSV (Excel) Files from ADF WebApplications