This is an AMP version of the article, its original content can be found here.
Xembly, an Assembly for XML
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:
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
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
to our list document. The code would look like:
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.
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
Our balance changing task can be expressed in Xembly with the following code:
XSET directive sets the element text value, similar to
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:
In this snippet, I'm using a supplementary script builder,
enables generation of directives in a fluent way. Then, I use
which is similar to "assembler," to apply all specified directives
document object of class
Additionally, Xembly can be used to build XML documents from scratch and as a replacement for traditional DOM building. A quick example:
The above snippet produces the following output:
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 :)