QR code

Xembly, an Assembly for XML

pets xml

badge

I use XML in almost every one of my projects. And, despite all the fuss about JSON/YAML, I honestly believe that XML is one of the greatest languages ever invented. Also, I believe that the beauty of XML reveals itself when used in combination with related technologies.

For example, you can expose your data in XML and render it for the end-user using XSL stylesheet.

Another example would be when you validate the same data, before rendering, to ensure that the structure is correct. You can do this with the XSD schema. Alternatively, you can pick specific data elements from the entire document by using XPath queries.

Essentially, these three technologies, XSL, XSD schema and XPath, are what makes XML so powerful.

However, there can be times when XML falls short. For instance, imagine you have an existing document that needs to be modified just slightly. For example, let’s use the following:

<accounts>
  [...]
  <acc id='34'>
    <name>Jeffrey</name>
    <balance>305</balance>
  </acc>
  <acc id='35'>
    <name>Walter</name>
    <balance>50090</balance>
  </acc>
  [...]
</accounts>

The above code represents a list of accounts. Each account has its own id and several child elements. In our example, we need to find the account belonging to Jeffrey and increase its balance by 500. How would we do this?

Well, there are a few possible solutions:

  • SAX-parse the document, change the balance and save the stream;
  • DOM-parse it, find the element with XPath, change the value and then print it;
  • apply a parametrized XSL stylesheet;
  • apply XQuery small script to make changes

All of these methods have their own drawbacks. However, all of them have one particular problem in common—they are very verbose. With each of the above methods, you need at least a page of code to perform this rather simple operation. Furthermore, if the logic of the operation becomes more complex, the amount of needed code grows much faster than you may expect.

Simply put, XML lacks a tool for primitive data manipulations within a document. Perhaps, it is this shortcoming that makes XML unpopular with some.

Anyway, here is a tool I created a few month ago: Xembly. It is an imperative language with a few simple directives and resembles Assembly in style. Thus, the name - Xembly. With Xembly, there are no loops, conditions or variables - just a sequence of directives with arguments.

Let’s create a simple example. Say, for instance, we want to add a new account number 36 to our list document. The code would look like:

XPATH '/accounts';
ADD 'account';
ATTR 'id', '36';
ADD 'name';
SET 'Donny';
UP;
ADD 'balance';
SET '3400';

The above should be intuitively clear, but I’ll explain just in case. First, the XPATH directive points us to the element found by the “/accounts” XPath query. This will be our root element. We assume here that it exists in the document. Therefore, if it is absent, our Xembly script will fail with a runtime exception.

Next, the ADD directive on line 2 creates a new XML element without any children or attributes. Then, the ATTR directive sets an attribute for this element. The code then adds the new child element name and sets its text value to "Donny" using the SET directive. Finally, we move our pointer back to account element using UP, add the balance child element and set its value to "3400".

Our balance changing task can be expressed in Xembly with the following code:

XPATH '/accounts/account[name="Jeffrey"]/balance';
XSET '. + 500';

The XSET directive sets the element text value, similar to SET, but calculates it beforehand using the provided XPath expression . + 500.

Xembly performs all manipulations through DOM. Consequently, Xembly can be implemented inside any language that has a built-in DOM implementation.

In the meantime, there is only one implementation of Xembly language—in Java. Here is how it works:

Iterable<Directive> directives = new Directives()
  .xpath("/accounts")
  .add("account")
  .attr("id", "36")
  .add("name").set("Donny").up()
  .add("balance").set("3400");
new Xembler(directives).apply(document);

In this snippet, I’m using a supplementary script builder, Directives, which enables generation of directives in a fluent way. Then, I use Xembler class, which is similar to “assembler,” to apply all specified directives to the document object of class org.w3c.dom.Document.

Additionally, Xembly can be used to build XML documents from scratch and as a replacement for traditional DOM building. A quick example:

System.out.println(
  new Xembler(
    new Directives().add("html")
      .add("head")
      .add("title")
      .set("Hello, world!")
  ).xml()
);

The above snippet produces the following output:

<html>
  <head>
    <title>Hello, world!</title>
  </head>
</html>

For me, this appears to be more simple and compact.

As usual, your bug reports and suggestions are always welcomed. Please send to GitHub issues.

sixnines availability badge   GitHub stars