Powered by SmartDoc

Hello World

Now, let's begin with the "HelloWorld" example.

First, an XML document for the HelloWorld example is shown in list[hello.xml].

hello.xml
<?xml version="1.0" ?>
<!DOCTYPE greeting SYSTEM "hello.dtd">

<greeting to="xmluser@xml.gr.jp" from="asami@zeomtech.com">
  <title>hello</title>
  <message>Welcome to Relaxer world</message>
</greeting>

List[hello.rlx]is a RELAX module that describes the structure of such an XML document.

hello.rlx
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "relaxCore.dtd">
<module>

  <interface>
    <export label="greeting"/>
  </interface>

  <elementRule role="greeting">
    <sequence>
      <element name="title" type="string" />
      <element name="message" type="string" />
    </sequence>
  </elementRule>

  <tag name="greeting">
    <attribute name="to" required="true" type="string"/>
    <attribute name="from" required="true" type="string"/>
  </tag>

</module>

From the RELAX module, let's generate a Java program for handling hello.xml.

In preparation, we have to generate relaxCore.dtd in the current directory (figure[Setup]); this DTD is referenced by RELAX modules.

Setup
C:\tmp>relaxer -setup

Now, we are ready to generate Java classes. (figure[Generation])

Generation
C:\tmp>relaxer hello.rlx

Relaxer silently generates Java classes.

Although it is rather lengthy, the entire source code is shown below: (list[Greeting.java])

The size of this source code does not mean that Relaxer generates redundant codes. To the contrary, mapping from XML documents valid against the RELAX module to Java objects and vice versa requires every line of this source code.

In other words, even if you do not use Relaxer, you have to develop programs equivalent to this source code. Such routine or tedious programming is innevitble if you do not use Relaxer and write programs by yourself.

Programs of this size are very likely to contain bugs, even when the programs are actually very simple. Automatic code generation is much safer, since it avoids careless mistakes.

Greeting.java
import org.w3c.dom.*;

/**
 * <b>Greeting</b> is generated by Relaxer based on hello.rlx.
 * This class is derived from:
 * 
 * <!-- for programmer
 * <elementRule role="greeting">
 *   <sequence>
 *     <element name="title" type="string"/>
 *     <element name="message" type="string"/>
 *   </sequence>
 * </elementRule>
 * 
 * <tag name="greeting">
 *   <attribute name="to" required="true" type="string"/>
 *   <attribute name="from" required="true" type="string"/>
 * </tag>
 * -->
 * <!-- for javadoc -->
 * <pre> &lt;elementRule role="greeting"&gt;
 *   &lt;sequence&gt;
 *     &lt;element name="title" type="string"/&gt;
 *     &lt;element name="message" type="string"/&gt;
 *   &lt;/sequence&gt;
 * &lt;/elementRule&gt;
 * &lt;tag name="greeting"&gt;
 *   &lt;attribute name="to" required="true" type="string"/&gt;
 *   &lt;attribute name="from" required="true" type="string"/&gt;
 * &lt;/tag&gt;
 * </pre>
 *
 * @version hello.rlx (Tue Jun 13 18:27:49 JST 2000)
 * @author  Relaxer 0.9.2b (by ASAMI@Yokohama)
 */
public class Greeting implements java.io.Serializable {
    private String to;
    private String from;
    private String title;
    private String message;

    /**
     * Creates a <code>Greeting</code>.
     *
     */
    public Greeting() {
    }

    /**
     * Creates a <code>Greeting</code> by the Stack <code>stack</code>
     * that contains Elements.
     * This constructor is supposed to be used internally
     * by the Relaxer system.
     *
     * @param stack
     */
    public Greeting(RStack stack) {
        setup(stack);
    }

    /**
     * Creates a <code>Greeting</code> by the Document <code>doc</code>.
     *
     * @param doc
     */
    public Greeting(Document doc) {
        setup(doc.getDocumentElement());
    }

    /**
     * Creates a <code>Greeting</code> by the Element <code>element</code>.
     *
     * @param element
     */
    public Greeting(Element element) {
        setup(element);
    }

    /**
     * Initializes the <code>Greeting</code> by the Document <code>doc</code>.
     *
     * @param doc
     */
    public void setup(Document doc) {
        setup(doc.getDocumentElement());
    }

    /**
     * Initializes the <code>Greeting</code> by the Element <code>element</code>.
     *
     * @param element
     */
    public void setup(Element element) {
        init(element);
    }

    /**
     * Initializes the <code>Greeting</code> by the Stack <code>stack</code>
     * that contains Elements.
     * This constructor is supposed to be used internally
     * by the Relaxer system.
     *
     * @param stack
     */
    public void setup(RStack stack) {
        setup(stack.popElement());
    }

    /**
     * @param element
     */
    private void init(Element element) {
        RStack stack = new RStack(element);
        to = URelaxer.getAttributePropertyAsString(element, "to");
        from = URelaxer.getAttributePropertyAsString(element, "from");
        title = URelaxer.getElementPropertyAsString(stack.popElement());
        message = URelaxer.getElementPropertyAsString(stack.popElement());
    }

    /**
     * Creates a DOM representation of the object.
     * Result is appended to the Node <code>parent</code>.
     *
     * @param parent
     */
    public void makeElement(Node parent) {
        Document doc;
        if (parent instanceof Document) {
            doc = (Document)parent;
        } else {
            doc = parent.getOwnerDocument();
        }
        Element element = doc.createElement("greeting");
        int size;
        URelaxer.setAttributePropertyByString(element, "to", to);
        URelaxer.setAttributePropertyByString(element, "from", from);
        URelaxer.setElementPropertyByString(element, "title", title);
        URelaxer.setElementPropertyByString(element, "message", message);
        parent.appendChild(element);
    }

    /**
     * Gets the String property <b>to</b>.
     *
     * @return String
     */
    public final String getTo() {
        return (to);
    }

    /**
     * Sets the String property <b>to</b>.
     *
     * @param to
     */
    public final void setTo(String to) {
        this.to = to;
    }

    /**
     * Gets the String property <b>from</b>.
     *
     * @return String
     */
    public final String getFrom() {
        return (from);
    }

    /**
     * Sets the String property <b>from</b>.
     *
     * @param from
     */
    public final void setFrom(String from) {
        this.from = from;
    }

    /**
     * Gets the String property <b>title</b>.
     *
     * @return String
     */
    public final String getTitle() {
        return (title);
    }

    /**
     * Sets the String property <b>title</b>.
     *
     * @param title
     */
    public final void setTitle(String title) {
        this.title = title;
    }

    /**
     * Gets the String property <b>message</b>.
     *
     * @return String
     */
    public final String getMessage() {
        return (message);
    }

    /**
     * Sets the String property <b>message</b>.
     *
     * @param message
     */
    public final void setMessage(String message) {
        this.message = message;
    }

    /**
     * Tests if a Element <code>element</code> is valid
     * for the <code>Greeting</code>.
     *
     * @param element
     * @return boolean
     */
    public static boolean isMatch(Element element) {
        String tagName = element.getTagName();
        if (!"greeting".equals(tagName)) {
            return (false);
        }
        RStack target = new RStack(element);
        Element child;
        child = target.popElement();
        if (child == null) {
            return (false);
        }
        if (!"title".equals(child.getTagName())) {
            return (false);
        }
        child = target.popElement();
        if (child == null) {
            return (false);
        }
        if (!"message".equals(child.getTagName())) {
            return (false);
        }
        if (!target.isEmptyElement()) {
            return (false);
        }
        return (true);
    }

    /**
     * Tests if elements contained in a Stack <code>stack</code>
     * is valid for the <code>Greeting</code>.
     * This mehtod is supposed to be used internally
     * by the Relaxer system.
     *
     * @param stack
     * @return boolean
     */
    public static boolean isMatch(RStack stack) {
        Element element = stack.peekElement();
        if (element == null) {
            return (false);
        }
        return (isMatch(element));
    }

    /**
     * Tests if elements contained in a Stack <code>stack</code>
     * is valid for the <code>Greeting</code>.
     * This method consumes the stack contents during matching operation.
     * This mehtod is supposed to be used internally
     * by the Relaxer system.
     *
     * @param stack
     * @return boolean
     */
    public static boolean isMatchHungry(RStack stack) {
        Element element = stack.peekElement();
        if (element == null) {
            return (false);
        }
        if (isMatch(element)) {
            stack.popElement();
            return (true);
        } else {
            return (false);
        }
    }
}

If necessary, we generate a DTD (figure[DTD generation]) from the RELAX module. This DTD can be used by validating XML processors or DTD-aware XML editors.

DTD generation
C:\tmp>relaxer -dtd hello.rlx

List[hello.dtd]shows the generated DTD.

hello.dtd
<!-- Generated by Relaxer 0.7 -->
<!-- Sat Mar 11 10:46:37 JST 2000 -->

<!ELEMENT greeting (title, message)>
<!ATTLIST greeting to CDATA #REQUIRED>
<!ATTLIST greeting from CDATA #REQUIRED>

<!ELEMENT message (#PCDATA)>

<!ELEMENT title (#PCDATA)>

Finally, we develop an appliation using the generated Java classes. Here JAXP is used as the XML API.

HelloWorld.java
import java.io.*;
import java.net.URL;
import java.net.MalformedURLException;
import javax.xml.parsers.*;
import org.w3c.dom.*;

public class HelloWorld {
    public static void main(String[] args) throws Exception {
	URL url = resolveURL(args[0]);
	DocumentBuilderFactory factory
	    = DocumentBuilderFactory.newInstance();
	factory.setValidating(true);
	DocumentBuilder builder = factory.newDocumentBuilder();
	Document doc = builder.parse(url.toString());
	Greeting greeting = new Greeting(doc);
	System.out.println("To      : " + greeting.getTo());
	System.out.println("From    : " + greeting.getFrom());
	System.out.println("Title   : " + greeting.getTitle());
	System.out.println("Message : " + greeting.getMessage());
    }

    public static URL resolveURL(String name) throws MalformedURLException {
	try {
	    return (new URL(name));
	} catch (MalformedURLException e) {
	}
	return (new File(name).toURL());
    }
}

We can easily map an XML document to Java objects by providing the Document, which is created by JAXP, to the constructor of the Greeting object. Relaxer makes this mapping so straightforward. If Relaxer was not used, a lot of tedious programming on top of DOM would be required.

This program is executed as follows. Observe that the contents of hello.xml is successfully converted into a Java object, Greeting.

Execution of the application
C:\tmp>java HelloWorld hello.xml
To      : xmluser@xml.gr.jp
From    : asami@zeomtech.com
Title   : hello
Message : Welcome to Relaxer world