Monday, January 05, 2009

Going crazy with XSL and Xalan

Recently I spent some time transforming one XML to another with an XSD and I was going crazy!

So let's start:

Passing parameters to the XSD

In the XSD write for instance <xsl:param name="fileName"></xsl:param> to access the parameter and in Java you do xmlTransformer.getTransformer().setParameter("fileName", "test"); You then can refer to the parameter with $filename

Calling Java methods from the XSD
  1. Write a static Java method which does what you want, e.g. public static String getFileMd5Hash(String path) {...}
  2. Declare the class containing those methods in the header of the XSD as a new namespace:
    xmlns:md5="xalan://com.mycompany.myclass"
    exclude-result-prefixes="md5 xalan">
  3. Call the method with <xsl:value-of select="md5:getFileIdMd5Hash($fileName)"> $filename is accessing the filename parameter declared in the previous method -- you can also have void or use the name of a node

Labels: , ,

Wednesday, December 10, 2008

Mythbuster: String and Stringbuilder in Java

In this new series I will go over some of the surprising facts of Java. It often starts with "You would think..." but at the end I lost the argument -- so here's the first one:

Let's start with this example of concatenating Strings (see http://stackoverflow.com/questions/47605/java-string-concatenation)

public class test {

public static void main(String[] args) {

String c = "c";

String a = "a";

String b = "b";

long start = System.currentTimeMillis();

for (long i = 0; i <>

c = c.concat(b);

}

long end = System.currentTimeMillis();

System.out.println(end - start);

start = System.currentTimeMillis();

for (long i = 0; i <>

c += b;

}

end = System.currentTimeMillis();

System.out.println(end - start);

start = System.currentTimeMillis();

StringBuilder sb = new StringBuilder(c);

for (long i = 0; i <>

sb.append(b);

}

int test = sb.toString().length();

end = System.currentTimeMillis();

System.out.println(end - start);

}

}

The output is the following:

C:\tmp>java test

296

5016

0

Now let's assume that we don't create new Strings every iteration and use code more like:

public class StringBuffer {

/**

* @param args

*/

public static void main(String[] args) {

String c = "c";

String a = "a";

String b = "b";

long start = System.currentTimeMillis();

for (long i = 0; i <>

c = a.concat(b);

}

long end = System.currentTimeMillis();

System.out.println(end - start);

start = System.currentTimeMillis();

for (long i = 0; i <>

c = a + b;

}

end = System.currentTimeMillis();

System.out.println(end - start);

start = System.currentTimeMillis();

for (long i = 0; i <>

c = new StringBuilder(a).append(b).toString();

}

// int test = sb.toString().length();

end = System.currentTimeMillis();

System.out.println(end - start);

}

}

With results:

15

63

15

What should we learn?

The arguments brought forward in (http://saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=get_topic&f=15&t=001714) doesn't really hold -- and yes, despite the "+" being internally converted to a StringBuilder still sucks.


But what about the surprising result with concat and the StringBuilder being par in the second example. That's really surprising.

My theory is that the biggest computational cost is instantiating a new object as seen in comparison to the two examples. (a+= a+b will make a new temporary String holding the result of a+b and then assign that whereas a.concat doesn't do that in the second example) You would think that the compiler/jvm would be able to reuse the objects internally for speed but it doesn't.

I would really prefer to use Strings in all cases (and I can live with saying concat instead of "+" though it's silly) because the immutability oft the String is a huge plus when it comes to concurrent programming. But as long as the performance in instatiating is that bad we might be stuck with the StringBuilder and a harder time making things concurrent.

Labels: ,