JavaEnterprise JavaHow XSL and XML Help in Java's Conditional Compilation

How XSL and XML Help in Java’s Conditional Compilation

This article requires that the reader is already familiar with Java and XML. I strongly recommend that you have a solid understanding of Java and XML fundamentals before you read this article. Please, do not consider this to be a study guide; this shows how a few technologies could be used with each other.

Before I describe ways that XSL and XML could help us solve certain problems, it would be desirable to define what problems we have. Conditional compilation is a rather extensive concept. In the context of this article, with the meaning “conditional compilation,” we will have an opportunity to compile a project at once with some different variants and/or versions, depending on a used key-argument. To understand what we are talking about, C/C++ programmers can recollect, for example, instructions of #define and #ifdef preprocessors. Such directives exist in many languages, but not in Java.

When could these directives be used? As mentioned above, when we need to compile different versions of a project just changing in value, or tracing or debugging. It goes without saying that nowadays numerous IDEs provide different features and possibilities in code debugging. But still, there are many applications where such “easy” debugging is necessary, for a couple of reasons. As a real-life example, it could be complex JSP or Servlet, which we need to debug only with a special IDE; that’s not an easy task. It would be much easier to use such directives to output values that we need to trace, rather than to buy, install, and learn how to use some external software applications (IDE).

Let’s take a look at such a tracing example with this next piece of code:

...
public ... proceedTransaction(...) {
  ...
    System.out.println(" start, value of argument is " + xxx);
    xxx = otherObject.someOtherMethod(....);
    System.out.println(" stop, value of argument is " + xxx);
    ...
  }
  ...

As you can see, the code is very easy and typical. We need to grab and see some variable values before and after executing some external method. Okay, everything works, and we do not need to see this temporary debug info, and we need to remove System.out.println() manually. It is inconvenient, especially if we remember that this debugging will be required once again; that usually occurs. It is certainly possible to not delete a line, and simply to close it into comments. But, this needs to be done manually—once we do not need it, and once we have to use it again. In a word: It would be very desirable to write something like this in Java:

...
public ... proceedTransaction(...) {
  ...
#ifdef DEBUG
      System.out.println(" start, value of argument is " + xxx);
    #endif
        xxx = otherObject.someOtherMethod(....);
    #ifdef DEBUG
      System.out.println(" stop, value of argument is " + xxx);
    #endif
    ...
  }
  ...

But, that’s impossible. Java doesn’t have such directives because Java has no built-in preprocessor. However, we can put our Java programs into an XML document, and, by using the necessary style tables with the help of help of an XSL processor, transform them into compiled Java applications. XML stands for Extensible Markup Language—a simple, very flexible text format derived from SGML. Originally designed to meet the challenges of large-scale electronic publishing, XML is also playing an increasingly important role in the exchange of a wide variety of data on the Web and elsewhere. XSL stands for Extensible Stylesheet Language—a language for creating a style sheet that describes how XML data is to be presented to the user. XSL specifies the styling of an XML document by using XSLT to describe how the document is transformed into another XML document that uses the formatting vocabulary. XSLT (the last ‘T’ stands for ‘Transformations’) is a language for transforming XML documents into other XML documents. XSLT is designed for use as part of XSL.

I have no doubt that it would be easier to understand this with example, so we will start with it right now. For example, we have this code:

1:  // OurDemocode.java
2:  public class OurDemocode {
3:    public static void main(String[] arg) {
4:      int r = 1;
5:      System.out.println("Before cycle result is " + r); 
6:      for (int i = 1; i <= 4; i++) {
7:        r = r * i;
8:        System.out.println("r = " + r + ", i = " + i);
9:      }
10:      System.out.println("After cycle result is " + r); 
11:    }
12:  }

The code is pretty easy. It just calculates the value of r four times, and then shows its value before and after this calculation. Line 8 is our debug line. We use it to see how te cycle is working and which value we have at each step. But, at the end, we don’t need it because it’s enough to have only a report in lines 5 and 12.

Now, let’s convert our program into an XML document. It will look like this:

1:  <?xml version="1.0" encoding="utf-8" ?>
2:  <prep:root xmlns_prep="OurDemocode.java.xml"> <![CDATA[
3:  // OurDemocode.java.xml
4:  public class OurDemocode {
5:    public static void main(String[] arg) {
6:      int r = 1;
7:      System.out.println("Before cycle result is " + r); 
8:      for (int i = 1; i <= 4; i++) {
9:        r = r * i;
10:    // <-- ]]> <prep:debug> <![CDATA[
11:        System.out.println("r = " + r + ", i = " + i);
12:   // --> ]]> </prep:debug> <![CDATA[
13:      }
14:      System.out.println("After cycle result is " + r); 
15:    }
16:  }
17:  // ]]> </prep:root>

We have the root element root. It has three affiliated elements: the block of the text, debug element and, again, the block of text. In turn, the debug element has one affiliated element: the block the text. All elements belong to the space of names prep (reduction from preprocessor). Blocks of text are limited to pairs of ” ” signs—this protects from being interpreted during their maintenance as XML marking by the XML processor. The names of the root and debug elements are chosen anyway, as well as the space of names.

Further, it is necessary to receive information from our newly created OurDemocode.java.xml file, which we will compile. For this purpose, we will create two XSL-style tables of styles. The first one will be used to transform our document, so that line line 11 of OurDemocode.java.xml (the same one as line 8 of OurDemocode.java file) will remain in the generated Java file, and the other style table will cut off this line. I think that it will be fair to call the first XLS-style table version1.xsl and next one version2.xml. The code for these style tables is here:

version1.xsl

1:  <?xml version="1.0" ?>
2:  <xsl:stylesheet version="1.0"
     xmlns_xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns_prep="OurDemocode.java.xml">
3:  <xsl:output method="text"/>
4:  <xsl:output omit-xml-declaration="yes"/>
5:  <xsl:output encoding="utf-8"/>
6:  <xsl:template match="/">
7:    <xsl:apply-templates />
8:  </xsl:template>
9:  <xsl:template match="*|@*|text()">
10:    <xsl:copy>
11:      <xsl:apply-templates select="*|@*|text()"/>
12:    </xsl:copy>
13:  </xsl:template>
14:  </xsl:stylesheet>

version2.xls

1:  <?xml version="1.0" ?>
2:  <xsl:stylesheet version="1.0"
     xmlns_xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns_prep="OurDemocode.java.xml">
3:  <xsl:output method="text"/>
4:  <xsl:output omit-xml-declaration="yes"/>
5:  <xsl:output encoding="utf-8"/>
6:  <xsl:template match="/">
7:    <xsl:apply-templates />
8:  </xsl:template>
9:  <xsl:template match="text()">
10:    <xsl:choose>
11:    <xsl:when test="name(following-sibling::*[1])='prep:debug'">
13:    <xsl:copy-of select="substring(., 0, string-length(.)-7)"/>
                                      /***</xsl:when>
14:    <xsl:when test="name(..)='prep:debug'">
15:    <xsl:copy-of select="substring(., 0,
                                      string-length(.)-7)"/>
                                      ***/</xsl:when>
16:    <xsl:otherwise>
17:    <xsl:copy-of select="."/>
18:    </xsl:otherwise>
19:    </xsl:choose>
20:  </xsl:template>
21:  </xsl:stylesheet>

There are some moments where it is necessary to pay close attention to the drawing up of any style table intended for use in our preprocessor:

  • All XML elements will be removed.
  • Lines will be cut off from the original document.
  • Encodings used in both documents need to be equal.
  • After using style tables, the output files will have the same number of lines as in the original document. (It’s useful to locate a mistake in case we get a compiler error.)

Okay. Now, when we have all the code ready, we need to find an XML processor. We will use Xalan-J. Xalan-J is an XSLT processor used to transform XML documents into HTML, text, or other XML document types. It implements XSLT 1.0 and XPath 1.0. It can be used from the command line, in an applet or a Servlet, or as a module in another program. You will need to download and install a recent copy of Xalan-J from its official site: http://xml.apache.org/xalan-j/.

To execute all this stuff, we need to run the next command. (Or, that easily could be integrated with the help of Ant. However, it already goes beyond the scope of this article.)

java org.apache.xalan.xslt.Process -in OurDemocode.java.xml
                                   -xsl version1.xsl 
                                   > OurDemocode.java

This will create OurDemocode.java with our debug string active, and this one:

java org.apache.xalan.xslt.Process -in OurDemocode.java.xml
                                   -xsl version2.xsl
                                   > OurDemocode.java

will create OurDemocode.java with the debug line commented.

Thus, with the help of a pair of additional tools, we were able to add an opportunity to use our own instructions and only change style tables. The given XSL files are the elementary variants of such tables.

© Olexiy Prokhorenko
http://www.7dots.com/resume/

Co-author: Alexander Prohorenko

Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.
Get the Free Newsletter!
Subscribe to Developer Insider for top news, trends & analysis
This email address is invalid.

Latest Posts

Related Stories