Enhydra之XMLC的使用

错误和疑问请发到zy.wang@263.net 

XMLCEnhydra中表现层的核心技术,XMLC是一个为动态网站内容开发使用的模版生成器,它完全基于xml/domjava标准。它提供了一个从静态htmlxml模板文件生成动态内容的java对象的机制。这个对象就把模版文件DOM化了,我们可以通过java/dom来操作这个java对象,从而实现动态的web内容显示。运用XMLC,我们完全可以把显示逻辑和商业逻辑完全的分开而不会再出现html文件中夹杂程序代码的情况,在html文件中你不用放入任何的java代码,这在在aps/jsp/php中是不可想象的,我们可以专心开发程序,界面丢给美工好了。所以接触到这个东西,我对嵌入网页的脚本就再也提不起兴趣了--有人要拿砖头了:)。好了让我们开始吧!

 

一、理解DOM概念

 

我们都知道xml/html文件有着树状的层次结构,并且它的模型可以用某种面向对象的程序语言(例如java)来表现。w3c把这种xml/html对象模型的标准称为文档对象模型(DOM),它是基于xml的一种标准。举个例子:

对于如下html代码

 

<TABLE>

<TR>

<TD ID=”cellOne”>张三</TD>

<TD ID=”cellTwo”>李四</TD>

</TR>

<TR>

<TD ID=”cellThree”>王五</TD>

<TD ID=”cellFour”>赵六</TD>

</TR>

</TABLE>

 

 

我们可以看见了一棵的DOM树(如下图),TABLE为树根,然后从树根出来时TR到最末端TD。节点连接的上个节点是父节点,连接的下层节点是子节点。每个标记是一个树的节点。某些每个节点有自己的属性,例如TABLE会有背景色、宽度等等属性。w3c定义了这些html对象节点的对象和接口的标准,enhydraapi就遵循这些标准或者使用其api,所以在enhydra我们可以控制这些dom对象节点的属性操作。

 

举个例子,我们要设置上面的表格中张三这个格的背景色为红色的话,可以这么做

HTMLTableCellElement cellOne = theDocument.getElementCellOne();

cellOne.setBgColor(“red”);

 

HTMLTableCellElement和方法setBgColor是从w3cjava包得到的,而getElementCellOne则是xmlc为我们提供的。可以看到,xmlc创建了访问dom树结点的方法。xmlc从模版文件中生成getElementxxx()的方法来返回对应于模版文件ID="xxx"节点的java对象。然后用这个对象的方法,我们可以操作对象对应的文档节点的属性。

 

二、创建模版文件

1、  在这里我们先要介绍一下xmlc模版文件是怎样的?

 

html文件中,标记spandiv只是用来提供给css样式表,除此之外浏览器对这两个标记并不处理,因此xmlcspan用于动态生成一段字,div则用来动态生成任何东西,比如生成表格和文字图片的混合树。另外,如果你想控制某个html节点,你可以在任何一个html标记添加id

 

2、  一个例子

 

我们来看一个静态html文件:hello.html

 

<HTML>
<HEAD>
    <TITLE>Hello, World</TITLE>
</HEAD>
<BODY BGCOLOR=#FFFFFF TEXT="#000000">
<H1>Hello, World</H1>
This is a text of XMLC, showing how one can change text
located in SPAN tags.  Text outside of those tags and not within
another tag with an id attribute cannot be changed.
</BODY>
</HTML>
 

 

我们想在程序运行的时候动态改变TITLEBODY的内容,相应的模版就如下

 

<HTML>
<HEAD>
    <TITLE id="title">Hello, World</TITLE>
</HEAD>
<BODY BGCOLOR=#FFFFFF TEXT="#000000">
<H1>Hello, World</H1>
<SPAN id="para1">This is a text of XMLC, showing how one can change text 
located in SPAN tags.</SPAN>  Text outside of those tags and not within 
another tag with an id attribute cannot be changed.
</BODY>
</HTML>
 

 

红色部分就是加入的模版标记,用浏览器看一下,和没加标记的效果是一样的。

 

三、使用xmlc编译模版文件

       有了模版文件,现在就要编译它了。

模版编译是把html/xml转化成对应DOM树的java对象的过程,这个通过xmlc这个程序来完成。它的使用非常的简单,用法如下:

 

enhydra.jar加入CLASSPATH

unix

export CLASSPATH=<enhyra_root>/lib/enhydra.jar:.

windows

set CLASSPATH=<enhydra_root>/lib/enhydra.jar

 

a)

 

然后使用xmlc命令

语法如下:

xmlc -参数 模版文件.html

 

主要的参数有:

       -class                    生成的全类名例如:xxx.xxx.classname

       -keep                   保留生成的java源文件

       -sourceout            生成的java源程序的根路径

       -html:encoding     这个比较重要,设置成你的文件编码,如GB2312

       其他一些参数请参考Enhydra得文档

b)

 

使用jbuilder+khelp

 

       Enhydra提供了支持Jbuilder的开发插件,只要在安装完EnhydraJbuilder后,安装Khelp就可以了。在Khelp下使用xmlc就更简单了。在菜单wiizards中选择xmlc compiler…,

在弹出的对话框中我们可以看到选项设置,如下图,设置好选项后,我们在selections中把模版文件选入,然后编译就可以了。

 

 

四、使用xmlc生成的java对象

      察看生成的代码hello.java

 

/*

 ************************************

 * XMLC GENERATED CODE, DO NOT EDIT *

 ************************************

 */

import org.w3c.dom.*;

import org.enhydra.xml.xmlc.XMLCUtil;

import org.enhydra.xml.xmlc.XMLCError;

import org.enhydra.xml.xmlc.dom.XMLCDomFactory;

 

public class hello extends org.enhydra.xml.xmlc.html.HTMLObjectImpl {

    /**

     * Field that is used to identify this as an XMLC

     * generated class.  Contains an reference to the

     * class object.

     */

    public static final Class XMLC_GENERATED_CLASS = hello.class;

 

    /**

     * Field containing CLASSPATH relative name of the source file

     * that this class was generated from.

     */

    public static final String XMLC_SOURCE_FILE = "nullhello.html";

 

    /**

     * Get the element with id para1.

     * @see org.w3c.dom.html.HTMLElement

     */

    public org.w3c.dom.html.HTMLElement getElementPara1() {

        return $elementpara1;

    }

    private org.w3c.dom.html.HTMLElement $elementpara1;

 

    /**

     * Get the value of text child of element para1.

     * @see org.w3c.dom.Text

     */

    public void setTextPara1(String text) {

        XMLCUtil.getFirstText($elementpara1).setData(text);

    }

 

    /**

     * Get the element with id title.

     * @see org.w3c.dom.html.HTMLTitleElement

     */

    public org.w3c.dom.html.HTMLTitleElement getElementTitle() {

        return $elementtitle;

    }

    private org.w3c.dom.html.HTMLTitleElement $elementtitle;

 

    /**

     * Create document as a DOM and initialize accessor method fields.

     */

    public void buildDocument() {

        XMLCDomFactory domFactory = org.enhydra.xml.xmlc.dom.XMLCDomFactoryCache.getFactory("org.enhydra.xml.xmlc.dom.DefaultHTMLDomFactory");

        Document document = domFactory.createDocument(null, null);

        setDocument(document);

 

        domFactory.setErrorChecking(document, false);

 

        Node $node0, $node1, $node2, $node3;

        Element $elem0, $elem1, $elem2;

        Attr $attr0, $attr1, $attr2;

 

        $elem0 = document.getDocumentElement();

        $elem1 = document.createElement("HEAD");;

        $elem0.appendChild($elem1);

       

        $elem2 = document.createElement("TITLE");;

        $elem1.appendChild($elem2);

       

        $elementtitle = (org.w3c.dom.html.HTMLTitleElement)$elem2;

        $attr2 = document.createAttribute("id");

        $elem2.setAttributeNode($attr2);

       

        $node3 = document.createTextNode("title");;

        $attr2.appendChild($node3);

       

        $node3 = document.createTextNode("Hello, World");;

        $elem2.appendChild($node3);

       

        $elem1 = document.createElement("BODY");;

        $elem0.appendChild($elem1);

       

        $attr1 = document.createAttribute("bgcolor");

        $elem1.setAttributeNode($attr1);

       

        $node2 = document.createTextNode("#FFFFFF");;

        $attr1.appendChild($node2);

       

        $attr1 = document.createAttribute("text");

        $elem1.setAttributeNode($attr1);

       

        $node2 = document.createTextNode("#000000");;

        $attr1.appendChild($node2);

       

        $elem2 = document.createElement("H1");;

        $elem1.appendChild($elem2);

       

        $node3 = document.createTextNode("Hello, World");;

        $elem2.appendChild($node3);

       

        $elem2 = document.createElement("SPAN");;

        $elem1.appendChild($elem2);

       

        $elementpara1 = (org.w3c.dom.html.HTMLElement)$elem2;

        $attr2 = document.createAttribute("id");

        $elem2.setAttributeNode($attr2);

       

        $node3 = document.createTextNode("para1");;

        $attr2.appendChild($node3);

       

        $node3 = document.createTextNode("This is a text of XMLC, showing how one can change text located in SPAN tags.");;

        $elem2.appendChild($node3);

       

        $node2 = document.createTextNode(" Text outside of those tags and not within another tag with an id attribute cannot be changed.");;

        $elem1.appendChild($node2);

       

 

        domFactory.setErrorChecking(document, true);

 

    }

 

    /**

     * Recursize function to do set access method fields from the DOM.

     * Missing ids have fields set to null.

     */

    protected void syncWithDocument(Node node) {

        if (node instanceof Element) {

            String id = ((Element)node).getAttribute("id");

            if (id.length() == 0) {

            } else if (id.equals("para1")) {

                $elementpara1 = (org.w3c.dom.html.HTMLElement)node;

            } else if (id.equals("title")) {

                $elementtitle = (org.w3c.dom.html.HTMLTitleElement)node;

            }

        }

    }

 

    /**

     * Default constructor.

     */

    public hello() {

        buildDocument();

    }

 

    /**

     * Constructor with optional building of the DOM.

     *

     * @param buildDOM If false, the DOM will not be built until

     * buildDocument() is called by the derived class.  If true,

     * the DOM is built immediatly.

     */

    public hello(boolean buildDOM) {

        if (buildDOM) {

            buildDocument();

        }

    }

 

    /**

     * Copy constructor.

     * @param src The document to clone.

     */

    public hello(hello src) {

        setDocument((Document)src.getDocume