Let's see a little more complicated example.
In this tutorial, we use the following grammar, which describes a structure of files and directories. The special mark-ups peculiar to RelaxNGCC are red.
<?xml version="1.0" encoding="utf-8"?> <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes" xmlns:c="http://www.xml.gr.jp/xmlns/relaxngcc"> [1] <c:java-import> import java.util.Set; import java.util.HashSet; </c:java-import> <start c:class="sample2"> [2] <c:java-body> public Set hiddenfiles; </c:java-body> <element name="files"> <ref name="file-or-dir" c:alias="child"/> [3] <c:java>hiddenFiles = new HashSet(child.hiddenFiles);</c:java> </element> </start> [4] <define name="file-or-dir" c:class="FileOrDir"> <c:java-body> public Set hiddenFiles; </c:java-body> <c:java>hiddenFiles = new HashSet();</c:java> <oneOrMore> <choice> <element name="file"> <attribute name="name"> <text c:alias="filename"/> [5] <c:java>if(filename.startsWith(".")) hiddenFiles.add(filename);</c:java> </attribute> </element> <element name="directory"> <attribute name="name"><text/></attribute> <ref name="file-or-dir" c:alias="content"/> [6] <c:java>hiddenFiles.add(content.hiddenFiles);</c:java> </element> </choice> </oneOrMore> </define> </grammar>
This grammar allows files element as the root and arbitrary number of directory and file elements under the files element. Also it allows directory element under directory element.
Now, let's suppose that we want to collect files that begin with a period (in Unix convention, it means "hidden" attribute). Additionaly, suppose that our interest is not directory tree but file names.
Then, explanations of each part are following.
[1] The content of java-import element is copied besides the main class definition of Java. If your code within java element or java-body element[5] requires classes in external packages, you should write import declarations using java-import element. Note that java-import elements under the root grammar element affect all generated code and they under a start or define element affect only the corresponding class to the element.
[2] The content of java-body element is copied into the class definition of Java. By using this, you can add bodyary methods and data members to the generated class. In this sample, the java-body element declares a data member hiddenFiles for storing the file names.
[3] The java element defines an action to be executed when a corresponding part of the input XML instance comes. In this example, initialize hiddenFiles when the files element ends.
[4] Since RelaxNGCC generates one Java class per a start block or a define block, RelaxNGCC generates 2 files from this grammar. The names of the classes are specified with c:class attribute for each start and define element. Especially the c:class attribute for the define element is mandatory because the name "file-or-dir" is not valid for a name of Java class.
[5] At this location, the file name is added if it begins with a period to the hiddenFiles collection.
[6] This is also java element, but be careful that the code fragment of Java refers to the previous define block with an alias attribute. If you add an alias attribute to a ref element, the Java object accessed by the given alias is a object corrsponding to the define block. In this example, the instance content refers to FileOrDir object.
After you compile and execute the generated code, the hiddenFiles member will contain all file names that begins with a period in the input XML instance. The main() method generated by RelaxNGCC may be helpful for understanding test procedure.
Relaxer and RelaxNGCC is same at the point of generating Java source code from a given grammar. But, if you use Relaxer for the case of this tutorial, you may have to traverse the object model includes a directory tree and collect file names that begins with a period. On the other hand, RelaxNGCC is more efficient for this purpose because it obtains the collection through one path via SAX interface.
However, there are some features supported by only Relaxer such as a conversion from Java object into XML instance. It is important to select more suitable tool according to your purpose.