XML is increasingly used to store data in Java applications. This article describes how XML can be extended to incorporate behavior, using the author's open source scripting language Simkin.
But why would you want to have behavior stored within XML? I'll illustrate by describing what led me to develop Simkin in the first place.
Imagine you're working on an adventure game: the game is divided into scenes, and each scene contains a number of characters. A natural representation would be to have Java Scene and SceneObject classes, storing each scene in an XML file.
<scene name="OwlWood"> <object name="Owl"/> </scene>
This is a scene in the Owl Wood, The wood contains an owl.
The game requires that characters be visible at different times during the action, so we might add a visibility property.
<object name="Owl" visible="false"/>
It would be good to make visibility dependent on something else; perhaps the result of a method call.
<object name="Owl" visible="isOwlVisible()"/>
We need some glue to evaluate
Java code could find the matching method, which it would assume to
return a boolean, by introspection. It would be even nicer to be able
to write expressions like
<object name="Owl" visible="not have_visited_owl_wood and not owl_spoken"/>
Now we have variables
"owl_spoken", and a simple expression syntax using
not. We also need more Java code: an
expression evaluator and a way of storing or retrieving values.
It turns out that the game requires that the owl has to say one thing if it's the first time the player has seen it, and something else the second time. This requirement takes us beyond the need for a simple expression evaluator into the realms of program logic.
In pseudo code, we want something like the following to be called when the player enters the scene:
if num_visits=0 then play("FirstVisit.au") else play("NextVisit.au") num_visits=num_visits+1
There is no standard way of embedding this kind of script within XML, although there are two basic approaches: first, use XML tags for keywords; second, embed a script within the text between tags.
There aren't any standards for using XML tags for behavior, although common ways are emerging. Here's how we might represent the pseudo code:
In Simkin I chose to use the second approach. Here's the same code in Simkin:
I find this style more readable, and it has the advantage that the rules for character encoding within PCDATA sections are more relaxed than for attribute values.
In either case you now need Java code to parse and interpret the statements, as well as evaluate expressions and access variables. In the case of Simkin I decided to develop an Interpreter class, using JavaCC to develop a parser.
Once the interpreter has parsed the script, it executes the statements one by one. The interpreter uses Java introspection to find methods and fields within Java objects.
I wanted the script to be able to call other Simkin functions and
Java methods using the same syntax. This makes it easy to move
subroutines into or out of Java as required. In the example above,
play might have started life as Java method, but become a
Simkin wrapper method.
To achieve this, the interpreter uses introspection to find a method, unless an object implements a special interface called Executable, in which case it delegates the responsibility of finding the method to the object itself. This means an object could first look for a Simkin method with the matching name.
The example above shows the utility of script access to variables. Simkin supports 4 kinds of variables:
I found Simkin very useful when developing my adventure game, "The Animals of Farthing Wood". I developed a small amount of generic game code, which was then used by a team of 3 scripters to create the logic of the whole adventure.
You can obtain the Simkin interpreter free from the Simkin web site.
Simon Whiteside is an experienced software architect and developer, using Java and other languages such as C++.
Return to ONJava.com.
Copyright © 2009 O'Reilly Media, Inc.