XMLC チュートリアル:動的コンテンツの生成

内容

  1. <SPAN> タグとid属性の使い方
  2. サンプルHTMLページ
  3. 構成されたDocument Object Model (DOM)
  4. 生成されるJavaクラス
  5. マニピュレーション(Manipulation) Java クラスからの利用法
  6. 生成されるHTML
  7. ノード(Node)の追加

<SPAN>タグとid属性の使い方

本章では、静的なHTMLテンプレートファイルから動的なHTMLページを生成するのに、XMLCをどの様に使用するのかを説明します。 静的なHTMLテンプレートはHTML生成ツールで作成されて変更されるかもしれないですが、それらを操作するコードは完全に別のファイルの中に保たれます。これは非常に役に立つものです。
プログラマとデザイナーは、XMLCベースのプロジェクト上で、今までには出来なかった方法により協力する事が出来ます。 一方がもう片方の仕事の完了を急がす必要がありません。

最初の2つのXMLCがカバーする特徴は、最も一般的に使用されるものです。 これらは有効ですが あまり利用されていないHTML4.0要素であるHTMLテンプレートのid属性と<SPAN>タグでマークアップすることを必要とします。これらの2つの要素は、HTML4.0準拠のHTML構築ツールで作成出来るかもしれません。

id属性は、HTMLタグに名前付けする事で、それらをXMLCから見つけ出す事が出来る様にする為に利用します。 一度タグへの参照が設定されると、W3C DOM Javaクラスと提携して処理をするXMLCは、与えられたタグタイプへの適切なアクセス方法を提供します。 即ち、HTMLヘッダーは、 HTMLヘッダーにあったアクセス方法を持つ事になります。

然しながら、 HTMLタグにアクセスする方法を持っている事だけでは十分で無いかもしれません。 もし、HTML文書の中へ動的にテキストのビットを生成したいと望む場合はどうでしょうか? この場合は、<SPAN>タグを使用します。 望みえるテキストの変更は、<SPAN>タグによって対処します。 また、最初の<SPAN>タグにはid属性がある事にも注意してください。

XMLCに入力する為に作成されるHTMLファイルは、HTMLデザインツールにより作成されると思いますが、全てのデザインツールがHTML4.0をサポートしていない事に注意してください。 古いデザインツールを使う場合は、<SPAN>タグを直接追加出来ないかもしれません。 然しながら、多くのデザインツールは、新規、または、サポート外のタグを追加する機能を持っています。

全てのid属性は、HTML文書中においてユニークな名前が与えられていないければならない事にも注意してください。 それらの名前は、Java変数名(またはJava変数名の一部)として使用されますので、正当なJava識別子でもなければいけません。 正当なJava識別子は、 大文字小文字を意識し、アルファベット文字、 アンダースコープ(‘_')またはドル記号('$')で始じまっていないといけません。 その後に続く文字には、数字('0-9')も利用出来ます。 当然、Java識別子にはJavaリザーブドワードを使ってはいけません。(例: 'abstract' や 'boolean'など)

これらのコンセプトを説明するためのサンプル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>

まずは、このHTML文書の内容にXMLCが効率的な方法でアクセスする事が出来る様に、いくつかのマイナーチェンジをしてみましょう。 XMLCは、他のタグの用途の邪魔にはならない正当なHTML/XMLマークアップ法に従っている事に注意してください。 HTMLブラウザは、解釈出来ない、または利用出来ないタグや属性を無視する事を要求されています。


<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>

"header1"という名前のid属性をヘッダーに追加し、テキストの一部を<SPAN>タグで囲いました。 次に、それらのマイナー変更は、文書のその変更部分への操作を可能にするJavaコードをXMLCが生成する為のものである事を説明します。

構成されたDocument Object Model (DOM)

XMLCは、文書のDOMを見るためのコマンドラインオプションを持っています。


$ $ENHYDRA/output/bin/xmlc -dump hello.html

最初の(id属性や<SPAN>タグを追加していない)HTMLページのDOMを見ると、HTMLを表現したお馴染みの構造である事がわかります。


DOM hierarchy:
    BasicHTMLDocument
        BasicHTMLHtmlElement: html
            BasicHTMLHeadElement: head
                BasicHTMLTitleElement: title
                    BasicText: text=Hello, World
            BasicHTMLBodyElement: body: bgcolor='#FFFFFF' text='#000000'
                BasicHTMLHeadingElement: h1
                    BasicText: text=Hello, World
                BasicText: text=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.

2つ目のHTMLページのDOMを見ると、いくつかの見事な追加記述に気が付きます。


DOM hierarchy:
    BasicHTMLDocument
        BasicHTMLHtmlElement: html
            BasicHTMLHeadElement: head
                BasicHTMLTitleElement: title: id='title'
                    BasicText: text=Hello, World
            BasicHTMLBodyElement: body: bgcolor='#FFFFFF' text='#000000'
                BasicHTMLHeadingElement: h1
                    BasicText: text=Hello, World
                BasicHTMLElement: span: id='para1'
                    BasicText: text= This is a text of XMLC, showing how one 
                               can change text located in SPAN tags.
                BasicText: text= Text outside of those tags and not within 
                           another tag with an id attribute cannot be changed.

DOMは、ヘッダーの為のidを表示しています。 文章テキストが2つの部分に分けれている事にも気が付くと思います。 <SPAN>タグの外部の断片は、BasicText要素として従来と同様に表されています。 けれども、<SPAN>の内側の部分は、idを含み、BasicTextで構成されるBasicHTMLElement要素を持っています。

それでは次に、id付けされたそれらの要素に何が起こるかを生成されたJavaコードで見てみましょう。

生成されるJavaクラス

Javaソースコードを保持(訳注:このオプションを指定しないと、.classファイルを生成後にXMLCが削除してしまう)したい時は、xmlcに“-keep"コマンドラインオプションを指定します:


$ $ENHYDRA/output/bin/xmlc -keep hello.html

このオプションは、コンパイルされたJavaクラスファイル('hello.class')とソースコードファイル('hello.java')の両方を生成します。

上記の例のHTMLファイルから生成されるJavaクラスにより、idまたは<SPAN>で名前付けされた個々の要素にアクセス出来ます。

貴方がまだJavaにそれほど親しんでいない場合は、少し奇妙に見えるかもしれませんが心配しないでください。 重要な部分の説明はします。次の'hello.java'ファイルの内容を見てください。


/*
 ************************************
 * XMLC GENERATED CODE, DO NOT EDIT *
 ************************************
 */
import org.w3c.dom.*;
import com.lutris.xml.xmlc.XMLCUtil;
public class hello extends com.lutris.xml.xmlc.html.HTMLObject {
    private static Document protoDocument;
    org.w3c.dom.html.HTMLTitleElement $elementtitle;
    org.w3c.dom.html.HTMLElement $elementpara1;
    static private void initProtoDom() {
        Node $node0, $node1, $node2, $node3;
        Element $elem0, $elem1, $elem2;
        Attr $attr0, $attr1, $attr2;

        com.docuverse.dom.DOM $$dom = new com.docuverse.dom.DOM();
        com.docuverse.dom.html.HTMLFactory $$factory = new com.docuverse.dom.html.HTMLFactory();
        $$dom.setFactory($$factory);
        protoDocument = (Document)$$factory.createDocument($$dom, "HTML");
        
        $elem0 = protoDocument.createElement("html");
        protoDocument.appendChild($elem0);
        
        $elem1 = protoDocument.createElement("head");
        $elem0.appendChild($elem1);
        
        $elem2 = protoDocument.createElement("title");
        $elem1.appendChild($elem2);
        
        $attr2 = protoDocument.createAttribute("id");
        $attr2.setValue("title");
        $elem2.setAttributeNode($attr2);
        
        $node3 = protoDocument.createTextNode("Hello, World");
        $elem2.appendChild($node3);
        
        $elem1 = protoDocument.createElement("body");
        $elem0.appendChild($elem1);
        
        $attr1 = protoDocument.createAttribute("text");
        $attr1.setValue("#000000");
        $elem1.setAttributeNode($attr1);
        
        $attr1 = protoDocument.createAttribute("bgcolor");
        $attr1.setValue("#FFFFFF");
        $elem1.setAttributeNode($attr1);
        
        $elem2 = protoDocument.createElement("h1");
        $elem1.appendChild($elem2);
        
        $node3 = protoDocument.createTextNode("Hello, World");
        $elem2.appendChild($node3);
        
        $elem2 = protoDocument.createElement("span");
        $elem1.appendChild($elem2);
        
        $attr2 = protoDocument.createAttribute("id");
        $attr2.setValue("para1");
        $elem2.setAttributeNode($attr2);
        
        $node3 = protoDocument.createTextNode(" This is a text of XMLC, showing how one can change text located in SPAN tags.");
        $elem2.appendChild($node3);
        
        $node2 = protoDocument.createTextNode(" Text outside of those tags and not within another tag with an id attribute cannot be changed.");
        $elem1.appendChild($node2);
        
    }

    static {
        initProtoDom();
    }

    public hello() {
        super(protoDocument);
        $elementtitle = (org.w3c.dom.html.HTMLTitleElement)this.getElementById("title");
        $elementpara1 = (org.w3c.dom.html.HTMLElement)this.getElementById("para1");
    }

    /**
     * Get the value of element title.
     * @see org.w3c.dom.html.HTMLTitleElement
     */
    public org.w3c.dom.html.HTMLTitleElement getElementTitle() {
        return $elementtitle;
    }
    
    /**
     * Get the value of element para1.
     * @see org.w3c.dom.html.HTMLElement
     */
    public org.w3c.dom.html.HTMLElement getElementPara1() {
        return $elementpara1;
    }
    
    /**
     * Get the value of text child of element para1.
     * @see org.w3c.dom.Text
     */
    public void setTextPara1(String str) {
        XMLCUtil.getFirstText($elementpara1).setData(str);
    }

}

最初に、生成されたクラスがcom.lutris.xml.xmlc.html.HTMLObjectをエクステンズ(extends)しているという事に気が付きます。 その(HTMLObject)クラスを見ると、多くの役に立つメソッドを提供している抽象(abstract)クラスである事にも気が付くと思います。
生成されたクラスはその抽象的なクラスをエクステンズ(extends)する為、それらの役に立つメソッドのすべてを手に入れる事が出来ます。 他のHTML要素の為の取得メソッド(Get methods)として、 getApplets(), getImages(), getLinks(), getForms(), getAnchors()等も存在します。 これらのメソッドは、HTMLCollection型のオブジェクトを返します。その型についてはここでは言及はしませんので、読者のみなさんが調査してください。

次に、赤色に設定されたテキストについて気が付きます。 これらのメソッドは、どんなHTMLObjectでも(訳者追加:マークアップされた要素や<SPAN>へのアクセスをメソッドにより)利用可能にするために拡張されます。 id属性を与えた全てのHTML要素のためにgetElement*メソッドが、与えられている事に注意してください。 また、タグで囲んだテキストの全ての部分へのgetElement*とsetText*メソッドもあります。

生成されたJavaクラスには、次の目的のgetElement*メソッドがあります:

また、 setElement* メソッドは、: id属性を持つどのタグの場合でも、それら個々に結び付くgetElement*メソッドは、type.org.w3c.dom.html.HTMLElement(または そのサブクラス)オブジェクトを返します。 実際に、全てのタイプのタグは、このインターフェースのそれ自身のサブクラスを持ちます。 org.w3c.dom.html.HTMLTitleElementのJavadocをみると、"title"という私たちのHTMLページタイトルを操作するために呼び出すことが出来る全てのメソッドを閲覧する事が出来ます。

同様に、タグで囲ったテキストは、getElementPara1()と名づけられたメソッドをもっており、getElementPara1()はorg.w3c.dom.html.HTMLElementオブジェクトを返します。

<SPAN>のためのsetText*メソッドは、他のタグによって厳密に囲まれていないテキストを参照する場合に必要です。 すなわち、<SPAN>タグは、 パラグラフタグ("<p>")のサブセットを参照する事になります。 XMLCは、(こういった状況においても)必要なメソッドを生成出来る様にする為の手がかりとして<SPAN>タグを使います。
(訳注:<p>タグは、それを閉じる</p>タグとペアで使われない場合が多い為<SPAN>タグが必要になるという事を言っていると思われます。)

マニピュレーションJavaクラスの使い方

ここまでで、HTML文書を表現するJavaクラスを手に入れました。 HTMLタイトルとある特殊な識別化をされたテキスト("para1")の値を変更するメソッドも手に入れました。
今度は、このクラスを利用するためのJavaクラスが必要です。 この新しいクラスをマニピュレーション(manipulation)クラスと呼びます。
このクラスは、次の責任を持っています。 <TITLE>タグにid属性を与えましたので、それを変更する事が出来ます。 <SPAN>タグの内部のテキストの変更も望んでいます。
Javaマニピュレーションクラスは、それらの変更と最終的なページを出力(print)をする事が出来る以下の様なクラスになります。:


import org.w3c.dom.html.*;
public class hello_creator {

    public static void main (String[] args) {

        // Create an instance of the HTML page object.
        hello hello = new hello();

        // Get a reference to the header and change it.
        HTMLTitleElement title = hello.getElementTitle();
        title.setText("Hello, New World!");

        // Change some text within the <SPAN> tags.
        hello.setTextPara1("We changed this!");

        // Print out the results.
        System.out.print( hello.toString() );

    }

}

ご覧の様に、この例はコマンドラインから実行する事が出来て、STDOUTへの出力をするだけの簡単なクラスです。

生成されるHTML

ここまでに、2つのJavaクラスを手に入れました。それらは、HTMLテンプレートを表すクラスと最終的な動的HTMLページを生成するクラスです。
さあ、マニピュレーションクラスをコンパイルして、実行してみましょう。 この為のコマンドは、マニピュレーションクラスをコンパイルして実行する、以下の様なものになるでしょう:


$ javac hello_creator.java
$ java hello_creator

ページクラスのtoString()メソッドが最終的に呼ばれた時、ユーザが見る事になるHTMLを生成します。
次のコードは、上の例によって作成されるHTMLページです:


<HTML>
<HEAD>
    <TITLE>Hello, New World!</TITLE>
</HEAD>

<BODY BGCOLOR=#FFFFFF TEXT="#000000">

<H1>Hello, World</H1>

We changed this!  Text outside of those tags and not within
another tag with an id attribute cannot be changed.

</BODY>
</HTML>

実際に生成されるHTMLが上に示された形式ではないことに注意してください。 というのも、実際には、タグの間には、改行も空白も含まれていません。 この形式は、ネットワーク転送と機械構文解析の両方にとっては最も効率的ですが、人間が読むのは困難です。
読み易さからの便宜上、上記のコードでは見やすいフォーマットに変更しています。
(訳注:見易くする為に上記のコードでは、改行や空白を入れているという事)

ノード(Node)の追加

さあ、ここで少し深く入ってみましょう。
貴方が、<SPAN>タグのコンテンツをハイパーリンクかHTMLヘッダーを含んだ何らかのテキストと置き換えたいと考えたとしましょう。
これは、HTMLノードを作成し、次にそれを正しい場所に挿入する事によって簡単に出来ます。

この例は、Enhydraメーリングリストで生まれ、Mark Diekhansによって回答が出されました。

もし、<span id="replaceme"> Replace Me with some text </span> を例えば<h1> Hello World <h1> <A HREF=Welcome.po> Welcome Page </A>のように置き換えたい場合、 XMLCが生成したDOM DocumentオブジェクトにHTMLを追加する為に、貴方は、新しいDOM要素オブジェクトを生成しそのオブジェクトを親要素の子供として追加しないといけません。 これを行うには、DOM文書のcreateElement() メソッドを使用してください。
以下に、(テストしていない)コードを示します。


HTMLObject htmlObj = new HelloHTML();

// Construct head
HTMLHeadingElement head = htmlObj.createElement("h1");
Text headText = htmlObj.createText("Hello World");
head.appendChild(htmlTest);

// Construct anchor
HTMLAnchorElement anchor = htmlObj.createElement("a");
anchor.setHref("Welcome.po");
Text anchorText = htmlObj.createText("Welcome Page");
anchor.appendChild(anchorText);

// Replace contents of id-labeled node.
Element replace = htmlObj.getElementReplaceme();
Element parent = replace.getParent();

// Start with the last new child so we can use insertBefore
parent.replaceChild(anchor, replace);
parent.insertBefore(head, anchor);