ビュークラスはformatメソッドの引数に渡されたテンプレートに変更を加えてレスポンスとします。テンプレートはfeat.templateパッケージのテンプレートAPIを使って操作します。
// 2番目の引数をnullにするとエンコーディング名をHTMLから取得する HTMLTemplate template = TemplateLoader.load(new File("shop_top_page.html"), null);
formatメソッドの引数で渡されるので、アプリケーションがロードする必要はありません。
public HTMLDocument format(HTMLDocument template, String[] params, ContextAccessor acc) throws Exception { ... }
要素につけられたIDで要素を検索するには、ドキュメントノード(HTMLDocument)または要素ノード(HTMLElement)でfindElementメソッドを使います。
<html><body> <p id="hello">こんにちは</p> </body></html>
try { HTMLElement hello = doc.findElement("hello"); ... } catch(NodeNotFoundException ex) { // ノードが見つからなかったとき ... }
ドキュメントノード、または要素ノードのfindElementByClassメソッドを使うとclass属性で要素の検索ができます。class属性に複数の名前が設定されている場合にも対応しています。
<td> <span class="price number">10,000</span>円 </td>
try { HTMLElement price = cell.findElementByClass("price"); ... } catch(NodeNotFoundException ex) { // ノードが見つからなかったとき ... }
ドキュメントノードのfindメソッドでXPathを使ったノードの検索ができます。
try { HTMLElement title = (HTMLElement)doc.find("/html/head/title"); ... } catch (NodeNotFoundException ex) { // ノードが見つからなかったとき ... }
// すべてのA要素を検索 HTMLNodeList link = doc.select("//a");
feat2.template.NodeSelectorクラスにはgetで始まる名前のメソッドとselectで始まる名前のメソッドがあります。get〜メソッドは単一のノードを、select〜メソッドは複数のノードを返します。
ノードが見つからなかったとき、get〜メソッドはnullを、select〜メソッドは空のリストやマップを返します。
// 顧客名を抽出 HTMLElement body; // body要素 ... HTMLNodeList customerNames = NodeSelector.selectElementsByClass(new NodeTreeIterator(body), "customer-name");
NodeSelectorのメソッドのほとんどはIteratorを引数にとります。HTMLのツリーからノードを見つけ出すにはツリーのノードを順にたどる必要がありますが、NodeTreeIteratorを使うと指定のノードを頂点とするノードツリーをたどることができます。これにより、HTMLツリーの任意の部分ツリーからノードを検索することができます。
// ドキュメントで最初に見つかったtitle要素を返す HTMLELement title = NodeSelector.getTag(new NodeTreeIterator(doc), "title");
NodeListIteratorは指定のノードの兄弟ノードをたどります。
// 表のtr要素を取り出す try { HTMLElement table = doc.findElement("search-results"); HTMLNodeList rows = NodeSelector.selectTags(new NodeListIterator(table.getFirstChild()), "tr"); ... } catch(NodeNotFoundException ex) { ... }
新しい要素を作成するときはfeat2.template.NodeFactoryクラスを使います。NodeFactoryクラスでは要素のほか、ドキュメントノード、テキストノード、注釈ノードも作ることができます。
HTMLElement copyright = NodeFactory.createElement("b", true); copyright.addText("Copyright (C) 2006 ..."); body.addChild(copyright);
ノードをコピーするにはノードのcopyメソッドを使います。引数deepがtrueの場合、ノードツリー全体をコピーします。引数deepがfalseの場合でもオブジェクトのプロパティはディープコピーとなります。copyメソッドが何をコピーするかは下の表を参照してください。
引数deepの値 | 子ノード | 属性 | 親ノードへの参照 | 前の兄弟ノードへの参照 | 次の兄弟ノードへの参照 |
---|---|---|---|---|---|
true | ディープコピー | ディープコピー | コピーしない | コピーしない | コピーしない |
false | コピーしない | ディープコピー | コピーしない | コピーしない | コピーしない |
コピーするノードに要素ノードが含まれている場合は注意が必要です。copyメソッドは要素のID属性もコピーするので、コピーした要素をドキュメントツリーに追加したときにIDが重複してしまう可能性があります。このような場合、ID属性を削除するコードをその都度書かなければなりません。
テンプレートAPIではテキストノードをノードオブジェクトとして意識する必要はあまりないかもしれません。CompositeNodeのメソッドでテキストノードを操作する場合がほとんどです。また、CompositeNodeやHTMLTextのメソッドでテキストを読み書きするとき、HTMLの特殊文字は自動的にエスケープ/アンエスケープされます。
エスケープしないで文字列を追加したい場合は、HTMLTextのsetRowTextメソッドを使います。
ノードをドキュメントツリーから削除するときはHTMLNodeのdetachメソッドを使います。このメソッドはノードを削除するわけではなく、指定ノードの親ノードと兄弟ノードとの関係を断ち切るだけです。参照がなくなればオブジェクトはいつか削除されます。
detachメソッドで切り離したサブツリーは再びドキュメントツリーに追加できます。元のドキュメントツリーだけでなく、どのドキュメントツリーにも追加できます。ただし、同じインスタンスを複数のドキュメントツリーに追加することはできません。
フォームもドキュメントツリー以下の要素の集合でしかないので、ほかの要素と同様に扱うことが可能です。しかし、ドキュメントツリーを直接操作してフォームの値を読み書きするのは非常に面倒です。テンプレートAPIにはフォームの値の読み書きを簡単にするためにfeat2.template.form.Formクラスがあります。
Form form = new Form(formElement);
単一の値をセットする場合。
form.setValue("controlName", "value");
リストやチェックボックスなど、複数の値を許容するコントロールに値をセットする場合。
form.setValues("controlName", new String[] {"tokyo", "kanagawa"});
コントロールに対応したlabel要素の値を設定することができます。input要素のボタンの場合はlabel要素ではなくinput要素のvalue属性が設定されます。
form.setLabel("controlName", "送信");
名前を共有するラジオボタン、チェックボックスの場合は同名のコントロールに対応したlabel要素を一度に指定します。Formクラスでは、名前を共有するコントロールのラベルを個別に設定することはできません。
form.setLabel("controlName", new String[] {"東証", "大証", "名証", "JQ", "HC"});
$Id: template.html,v 1.1 2006/04/25 10:01:56 sugimotokenichi Exp $