Converting an XML to an HTML using XSLT with Xalan

Xalan is an Apache implementation of the W3C recommendations for XSL transformations, XSLT. XSLT allows you to transform xml documents in an HTML, another XML or whatever format you desire.

Download Xalan at http://xml.apache.org/xalan-j/index.html.

You can apply an XSL to an XML document with command line. Make sure xalan.xml is in your classpath before trying out this example. It will create an HTML file (check it out!) from an XML.

  
  java org.apache.xalan.xslt.Process -in customers.xml -xsl customers.xsl -out customers.html

customers.xml (!!remove the space between ? and xml):

<? xml version="1.0"?>
<!DOCTYPE customers SYSTEM "customers.dtd">
 
<customers>
   <customer id="cust1">
      <name>Joris Van den Bogaert</name>
      <address>
         <addressline1>Handelskaai 3</addressline1>
         <zip>1000</zip>
         <location>Brussels</location>
         <country>BE</country>
      </address>
      <address>
         <addressline1>A. Dewitstraat 50</addressline1>
         <zip>3078</zip>
         <location>Meerbeek</location>
         <country>BE</country>
      </address>
   </customer>
  
   <customer id="cust2">
      <name>Alicia Kolesnikova</name>
      <address>
         <addressline1>Handelskaai 3</addressline1>
         <zip>1000</zip>
         <location>Brussels</location>
         <country>BE</country>
      </address>
   </customer>
</customers>

customers.dtd:

<!ELEMENT customers (customer*)>
<!ELEMENT customer (name, address+)>
<!ELEMENT address (addressline1, addressline2, zip, location, country)>
 
<!ELEMENT name (#PCDATA)>
 
<!ELEMENT addressline1 (#PCDATA)>
<!ELEMENT addressline2 (#PCDATA)>
<!ELEMENT zip (#PCDATA)>
<!ELEMENT location (#PCDATA)>
<!ELEMENT country (#PCDATA)>
 
<!ATTLIST customer
   id NMTOKEN #REQUIRED
>

customers.xsl (!!remove the space between ? and xml):

<? xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
 
<xsl:template match="customers">
<html>
   <head><title>Customers</title></head>
   <body>
      <h1>Customers</h1>
      <table border="1">
         <th>Customer ID</th>
         <th>Name</th>
         <th>Addresses</th>
     
         <xsl:apply-templates/>
 
      </table>
   </body>
</html>
</xsl:template>
 
<xsl:template match="customer">
   <tr>
      <td><xsl:value-of select="@id"/></td>
      <td><xsl:value-of select="name"/></td>
 
      <td><xsl:apply-templates select="address"/></td>
   </tr>
</xsl:template>
 
<xsl:template match="address">
   <xsl:value-of select="addressline1"/>
   <xsl:if test="string(addressline2) != string('')">
      &#160;<xsl:value-of select="addressline2"/>
   </xsl:if>,
   <xsl:value-of select="zip"/>&#160;<xsl:value-of select="location"/> 
   [<xsl:value-of select="country"/>]<br/>
</xsl:template>
 
</xsl:stylesheet>

Programmatically creating a DOM tree

Main.java:

import org.w3c.dom.*;
 
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.dom.DOMSource;
  
public class Main
{
   public static void main(String []args) {
      Document doc;
  
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.newDocument();
  
         Element customers = doc.createElement("customers");
         Element customer = doc.createElement("customer");
         Element name = doc.createElement("name");
         Element address = doc.createElement("address");
         Element addressline = doc.createElement("addressline");
         Element zip = doc.createElement("zip");
         Element location = doc.createElement("location");
         Element country = doc.createElement("country");
 
         name.appendChild(doc.createTextNode("Joris Van den Bogaert"));
         addressline.appendChild(doc.createTextNode("Handelskaai 3"));
         zip.appendChild(doc.createTextNode("1000"));
         location.appendChild(doc.createTextNode("Brussels"));
         country.appendChild(doc.createTextNode("BELGIUM"));
          
         customer.setAttribute("id", "cust1");
         customer.appendChild(name);
         address.appendChild(addressline);
         address.appendChild(zip);
         address.appendChild(location);
         address.appendChild(country);
         customer.appendChild(address);
 
         customers.appendChild(customer);
 
         doc.appendChild(customers);
  
         TransformerFactory tf = TransformerFactory.newInstance();
         Transformer transformer = tf.newTransformer();
         transformer.transform(new DOMSource(doc), new StreamResult(System.out));
 
      }
      catch(Exception e) {
         e.printStackTrace();
      }
 
   }  
}

outputs (cust.xml):

<? xml version="1.0" encoding="UTF-8"?>
<customers><customer id="cust1"><name>Joris Van den Bogaert</name>
<address><addressline>Handelskaai 3</addressline><zip>1000</zip>
<location>Brussels</location><country>BELGIUM</country></address>
</customer></customers>

Writing out a DOM tree to System.out

You can do this using the XSLT transform package. In XSLT, it is called an identity transform when the transformation is generating the source without any changes.

The following example programmatically creates a DOM tree and uses the Transformer class to output it to System.out.

Main.java:

import org.w3c.dom.*;
 
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.dom.DOMSource;
  
public class Main
{
   public static void main(String []args) {
      Document doc;
  
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.newDocument();
  
         Element customers = doc.createElement("customers");
         Element customer = doc.createElement("customer");
         Element name = doc.createElement("name");
 
         name.appendChild(doc.createTextNode("Joris Van den Bogaert"));
         customer.appendChild(name);
         customers.appendChild(customer);
 
         doc.appendChild(customers);
  
         // use the XSLT transformation package to output the DOM tree we just created
         TransformerFactory tf = TransformerFactory.newInstance();
         Transformer transformer = tf.newTransformer();
         transformer.transform(new DOMSource(doc), new StreamResult(System.out));
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

outputs:

<?xml version="1.0" encoding="UTF-8"?>
<customers><customer><name>Joris Van den Bogaert</name></customer></customers>

Writing out a DOM subtree to System.out

You can use the XSLT Transformer class to do this.

Here’s an example.

Test.xml

<?xml version="1.0" encoding="UTF-8"?>
<message>
   <content>Hello World!</content>
   <destinations>
      <dest>jmsqueue:myjmsqueue</dest>
      <dest>file:/home/filequeue</dest>
      <dest>123.30.230.90</dest>
   </destinations>
</message>

Main.java:

import org.w3c.dom.*;
 
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.dom.DOMSource;
  
import java.io.*;
 
public class Main
{
   public static void main(String []args) {
      Document doc;
  
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(new File("test.xml"));
 
         NodeList nodeList = doc.getElementsByTagName("destinations");
         Node node = nodeList.item(0);
  
         // use the XSLT transformation package to output the subtree destinations
         TransformerFactory tf = TransformerFactory.newInstance();
         Transformer transformer = tf.newTransformer();
         transformer.transform(new DOMSource(node), new StreamResult(System.out));
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

outputs:

<?xml version="1.0" encoding="UTF-8"?>
<destinations>
      <dest>jmsqueue:myjmsqueue</dest>
      <dest>file:/home/filequeue</dest>
      <dest>123.30.230.90</dest>
   </destinations>

Getting the attributes of an XML Node

Use a NamedNodeMap. The following example shows you how to print out all elements for the tag customer.

customer.xml (!!remove the space between ? and xml):

<? xml version="1.0" encoding="UTF-8"?>
<customers>
   <customer id="C12345" type="prio1">
      <name>Joris Van den Bogaert</name>
      <address>
         <addressline>Handelskaai 3</addressline>
         <zip>1000</zip>
         <location>Brussels</location>
         <country>BELGIUM</country>
      </address>
   </customer>
</customers>

Main.java:

import org.w3c.dom.*;
 
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.dom.DOMSource;
 
import java.io.*;
   
public class Main
{
   public static void main(String []args) {
      Document doc;
  
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(new File("customer.xml"));
 
         NodeList nodeList = doc.getElementsByTagName("customer");
         Node node = nodeList.item(0);
  
         NamedNodeMap attributes = node.getAttributes();
         for (int i=0; i<attributes.getLength(); i++) {
            Node attribute = attributes.item(i);
            System.out.println(attribute.getNodeName() + " = " + attribute.getNodeValue());
         }
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

outputs:

id = C12345
type = prio1

To get a specific attribute, you can use the method getNamedItem.

Main.java:

import org.w3c.dom.*;
 
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.dom.DOMSource;
 
import java.io.*;
   
public class Main
{
   public static void main(String []args) {
      Document doc;
  
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(new File("customer.xml"));
 
         NodeList nodeList = doc.getElementsByTagName("customer");
         Node node = nodeList.item(0);
  
         NamedNodeMap attributes = node.getAttributes();
 
         Node custId = attributes.getNamedItem("id");
         Node custType = attributes.getNamedItem("type");
         System.out.println("id   = " + custId.getNodeValue());
         System.out.println("type = " + custType.getNodeValue());
         }
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}

Including binary data in an XML

All data in XML need to be characters. So, if you want to store binary data in an XML, you would have to encode it first. One way to do this is with Base64. So, you could have an XML file like the following:

   <binmessage>
      <body type="Base64">base64encodedbytearray</body>
   </binmessage>

For more information, check out this JavaWorld tip.

Turning off DTD validation

As soon as you create the DocumentBuilderFactory, call the method setValidating and set it to false.

Try out following example and set it to true to see the parsing errors.

customers.dtd (!!remove the space between ? and xml):

<? xml version="1.0" encoding="UTF-8"?>
<!ELEMENT customer (name, addresses+, email)+ >
<!ATTLIST customer custid CDATA #REQUIRED>
 
<!ELEMENT name (#PCDATA)>
 
<!ELEMENT addresses (addline1, addline2, zip, location, state)>
<!ELEMENT addline1 (#PCDATA)>
<!ELEMENT addline2 (#PCDATA)>
<!ELEMENT zip (#PCDATA)>
<!ELEMENT location (#PCDATA)>
<!ELEMENT state (#PCDATA)>
 
<!ELEMENT email (#PCDATA)>

customers.xml (!!remove the space between ? and xml):

<? xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE customers SYSTEM "customers.dtd">
<customers>
   <customer id="C12345" type="prio1">
      <name>Joris Van den Bogaert</name>
      <address>
         <addressline>Handelskaai 3</addressline>
         <zip>1000</zip>
         <location>Brussels</location>
         <country>BELGIUM</country>
      </address>
   </customer>
</customers>

Main.java:

import org.w3c.dom.*;
  
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
 
import java.io.*;
   
public class Main
{
   public static void main(String []args) {
      Document doc;
  
      try {
         DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
         dbf.setValidating(true);
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.parse(new File("customers.xml"));
      }
      catch(Exception e) {
         e.printStackTrace();
      }
   } 
}