jOOX and XSLT. An XML love story, continued


jOOX - a jQuery port to Java The somewhat functional way of thinking involved with jOOX’s XML manipulation cries for an additional API enhancement simply supporting XSLT. XSL transformation has become quite a standard way of transforming large amounts of XML into other structures, where normal DOM manipulation (or jOOX manipulation) becomes too tedious. Let’s have a look at how things are done in standard Java

Example input:

<books>
  <book id="1"/>
  <book id="2"/>
</books>

Example XSL:

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

    <!-- Match all books and increment their IDs -->
    <xsl:template match="book">
        <book id="{@id + 1}">
            <xsl:apply-templates/>
        </book>
    </xsl:template>

    <!-- Identity-transform all the other elements and attributes -->
    <xsl:template match="@*|*">
        <xsl:copy>
            <xsl:apply-templates select="*|@*"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Verboseness of XSL transformation in Java

The standard way of doing XSL transformation in Java is pretty verbose – as just about anything XML-related in standard Java. See an example of how to apply the above transformation:

Source source = new StreamSource(new File("increment.xsl"));
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(source);
DOMResult result = new DOMResult();
transformer.transform(new DOMSource(document), result);

Node output = result.getNode();

Drastically decrease verbosity with jOOX

With jOOX, you can write exactly the same in much less code:

Apply transformation:
// Applies transformation to the document element:
$(document).transform("increment.xsl");

// Applies transformation to every book element:
$(document).find("book").transform("increment.xsl");

The result in both cases is:

<books>
  <book id="2"/>
  <book id="3"/>
</books>

SQL incompatibilities: NOT IN and NULL values


This is something where many hours of debugging have been spent in the lives of many SQL developers. The various situations where you can have NULL values in NOT IN predicates and anti-joins. Here’s a typical situation:

with data as (
  select 1 as id from dual union all
  select 2 as id from dual union all
  select 3 as id from dual
)
select * from data
where id not in (1, null)

What do you think this will return? Well, since “dual” indicates an Oracle database, you might say: “an empty result set”. And you would be right for Oracle. In fact, you would be right for any of these databases:

  • DB2
  • Derby
  • H2
  • Ingres
  • Oracle
  • Postgres
  • SQL Server
  • SQLite
  • Sybase

BUT! You would be wrong for any of these ones:

  • HSQLDB
  • MySQL
  • Sybase ASE

Why the discrepancy?

Intuitively, you’d say that all the big ones treat NULL specially in NOT IN predicates, and it is easy to understand, why:

-- This predicate here...
id not in (1, null)

-- Could be seen as equivalent to this one:
id != 1 and id != null

There’s no id that fulfills the above predicate id != null (not even null itself), hence an empty result set. MySQL is known for some strong abuse of SQL standards compliance, so it’s not surprising that they tweaked this syntax as well.

But wait!

HSQLDB 2.0 is one of the most standards-compliant databases out there, could they really have gotten it wrong? Let’s consider the standard: SQL 1992, chapter 8.4 <in predicate>:

<in predicate> ::=
   <row value constructor>
      [ NOT ] IN <in predicate value>

<in predicate value> ::=
   <table subquery>
      | <left paren> <in value list> <right paren>

<in value list> ::=
   <value expression> { <comma> <value expression> }...

 

And then, further down:

2) Let RVC be the <row value constructor> and 
   let IPV be the <in predicate value>.

3) The expression
     RVC NOT IN IPV

   is equivalent to
     NOT ( RVC IN IPV )

4) The expression
     RVC IN IPV

   is equivalent to
     RVC = ANY IPV

 

So in fact, this can be said:

ID NOT IN (1, NULL) is equivalent to
NOT (ID IN (1, NULL)), equivalent to
NOT (ID = ANY(1, NULL)), equivalent to
NOT (ID = 1 OR ID = NULL), equivalent to
NOT (ID = 1) AND NOT (ID = NULL), which is always UNKNOWN

Conclusion

It looks for once, that HSQLDB 2.0 is not standards-compliant in that evaluating the expression inside NOT() before applying NOT() has a different outcome from transforming NOT() into a normalised boolean expression, and then evaluating the expression. For SQL developers, all of this can just mean:

Keep NULL out of NOT IN predicates or be doomed!

CSS selectors in Java


CSS selectors are a nice and intuitive alternative to XPath for DOM navigation. While XPath is more complete and has more functionality, CSS selectors were tailored for HTML DOM, where the document content is usually less structured than in XML.

Here are some examples of CSS selector and equivalent XPath expressions:

CSS:   document > library > books > book
XPath: //document/library/books/book

CSS:   document book
XPath: //document//book

CSS:   document book#id3
XPath: //document//book[@id='3']

CSS:   document book[title='CSS for dummies']
XPath: //document//book[@title='CSS for dummies']

 

This becomes more interesting when implementing pseudo-selectors in XPath:

CSS:   book:first-child
XPath: //book[not(preceding-sibling::*)]

CSS:   book:empty
XPath: //book[not(*|@*|node())]

 

A very nice library that allows for parsing selector expressions according to the w3c specification is this “css-selectors” by Christer Sandberg:

https://github.com/chrsan/css-selectors

The next version of jOOX will include css-selector’s parser for simpler DOM navigation. The following two expressions will hold the same result:

Match match1 = $(document).find("book:empty");
Match match2 = $(document).xpath("//book[not(*|@*|node())]");

Use Xalan’s extension functions natively in jOOX


jOOX - a jQuery port to Java jOOX aims at increased ease of use when dealing with Java’s rather complex XML API’s. One example of such a complex API is Xalan, which has a lot of nice functionality, such as its extension namespaces. When you use Xalan, you may have heard of those extensions as documented here:

http://exslt.org

These extensions can typically be used in XSLT. An example is the math:max function:

<!-- Source -->
<values>
   <value>7</value>
   <value>11</value>
   <value>8</value>
   <value>4</value>
</values>

<!-- Stylesheet -->
<xsl:template match="values">
   <result>
      <xsl:text>Maximum: </xsl:text>
      <xsl:value-of select="math:max(value)" />
   </result>
</xsl:template>

<!-- Result -->
<result>Maximum: 11</result>

But in fact, math:max can be used in any type of XPath expression, also the ones that are directly created in Java. Here’s how you can do this:

Document document = // ... this is the DOM document

// Create an XPath object
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();

// Initialise Xalan extensions on the XPath object
xpath.setNamespaceContext(
  new org.apache.xalan.extensions.ExtensionNamespaceContext());
xpath.setXPathFunctionResolver(
  new org.apache.xalan.extensions.XPathFunctionResolverImpl());

// Evaluate an expression using an extension function
XPathExpression expression = xpath.compile(
  "//value[number(.) = math:max(//value)]");
NodeList result = (NodeList) expression.evaluate(
  document, XPathConstants.NODESET);

// Iterate over results
for (int i = 0; i < result.getLength(); i++) {
  System.out.println(result.item(i).getTextContent());
}

jOOX is much more convenient

The above is pretty verbose. With jOOX, you can do exactly the same, but with a lot less code:

Document document = // ... this is the DOM document

// jOOX's xpath method already supports Xalan extensions
for (Match value : $(document).xpath(
    "//value[number(.) = math:max(//value)]").each()) {
  System.out.println(value.text());
}

jOOX answers many Stack Overflow questions


jOOX - a jQuery port to Java When you search for Stack Overflow questions regarding XML, DOM, XPath, JAXB, etc, you could very often answer them simply with an example involving jOOX. Take this question extract for example:

Goal

My goal is to achieve following from this ex xml file :

<root>
    <elemA>one</elemA>
    <elemA attribute1='first' attribute2='second'>two</elemA>
    <elemB>three</elemB>
    <elemA>four</elemA>
    <elemC>
        <elemB>five</elemB>
    </elemC>
</root>

to produce the following :

//root[1]/elemA[1]='one'
//root[1]/elemA[2]='two'
//root[1]/elemA[2][@attribute1='first']
//root[1]/elemA[2][@attribute2='second']
//root[1]/elemB[1]='three'
//root[1]/elemA[3]='four'
//root[1]/elemC[1]/elemB[1]='five'

jOOX answer

The above can be achieved quite simply with jOOX (compared to the other answers to the question involving XSLT, SAX, DOM, etc):

List<String> list = $(document).xpath("//*[not(*)]").map(new Mapper<String>() {
  public String map(Context context) {
    return $(context).xpath() + "='" + $(context).text() + "'";
  }
}});

This will produce

/root[1]/elemA[1]='one'
/root[1]/elemA[2]='two'
/root[1]/elemB[1]='three'
/root[1]/elemA[3]='four'
/root[1]/elemC[1]/elemB[1]='five'

It is an “almost” solution to the OP’s problem, jOOX does not (yet) support matching/mapping attributes. Hence, attributes will not produce any output. This will be implemented in the near future, though.

See the full answer and question here:

http://stackoverflow.com/questions/4746299/generate-get-xpath-from-xml-node-java/8943144#8943144

Java 8 will have some support for unsigned integers


This seemed to be good news at first. An announcement by Oracle’s Joe Darcy claiming that Java will finally have *some* support for unsigned integers:

http://blogs.oracle.com/darcy/entry/unsigned_api

This will only be added on an API level, though. Not on a language level including all the expected features:

  • Primitive types
  • Wrapper types
  • Arithmetics
  • Casting rules
  • Boxing / Unboxing

A very “light” implementation of what could be expected… In the mean time, if you do need wrapper types, feel free to download (and contribute) to jOOU:

http://code.google.com/p/joou/

See also my previous blog post about jOOU:

Java’s missing unsigned integer types

jOOX and JAXB


jOOX - a jQuery port to Java jOOX has been awfully quiet lately due to increased development focus in jOOQ. Nevertheless, the jOOX feature roadmap is full of promising new features. Unlike its inspiration jquery, jOOX is positioning itself in the Java world, where many XML API’s already exist. One of the most important XML APIs in Java is JAXB, a very simple means of mapping XML to Java through annotations (see also my blog stream on the subject of Annotatiomania™).

Let’s have a look at this small XML document

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer id="13">
    <age>30</age>
    <name>Lukas</name>
</customer>

Typically, we would write a Java class like this to map to the above XML document:

@XmlRootElement
public class Customer {
    String name;
    int age;
    int id;

    public String getName() {
        return name;
    }

    @XmlElement
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    @XmlElement
    public void setAge(int age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    @XmlAttribute
    public void setId(int id) {
        this.id = id;
    }
}

And then, we would marshal / unmarshal the above using the following code snippet:

JAXB.marshal(new Customer(), System.out);
Customer c = JAXB.unmarshal(xml, Customer.class);

JAXB and jOOX

This is very neat and convenient. But it gets even better when JAXB is used along with jOOX. Have a look at the following piece of code:

// Use the $ method to wrap a JAXB-annotated object:
$(new Customer());

// Navigate to customer elements in XML:
String id   = $(new Customer()).id();
String name = $(new Customer()).find("name").text();

// Modify the XML structure, and unmarshal it again into 
// a JAXB-annotated object:
Match match = $(new Customer());
match.find("name").text("Peter");
Customer modified = match.unmarshalOne(Customer.class);

Check back soon on jOOX for new features!