ユーザーの操作に対応したボキャブラリコンポーネントの作成

ユーザーの操作に対応したボキャブラリコンポーネントをXVCDを使用して作成する手順を、簡単な例を示して説明します。

1. このチュートリアルの内容

このチュートリアルでは、ユーザーの操作に対応したボキャブラリコンポーネントをXVCDで開発する作業を、わかりやすさを優先した非常に簡単な例題を使い、順を追って見ていきます。このチュートリアルを実践することで、より使いやすいボキャブラリコンポーネントを作成することができます。

このチュートリアルを実践するために必要な知識や、開発環境の準備については、「XVCDで開発する環境の準備」をご覧ください。また、このチュートリアルを実践する前に、「XVCDによるボキャブラリコンポーネントの作成」を読み終えていることを想定しています。

このチュートリアル内のサンプルコードは、xfy Developer's Toolkit 配布パッケージ内のdoc/samples/developers/tutorial/event_tutorialに収録されています。xfy Developer's Toolkitには、このチュートリアルのほかにも豊富なXVCDサンプルが用意されています。ぜひ、それらのサンプルもご覧ください。

なお、このチュートリアルでは、xfyユーザーエージェントとして、xfy Basic Editionに含まれるxfy Clientを使用します。チュートリアルを進めるときは、xfy Clientでブラウズバーを表示すると便利です。xfy Clientをインストールした直後は、ブラウズバーは表示されていません。ブラウズバーを表示するには、[表示 - ブラウズバー]を選択します。

2. XVCDによるユーザーの操作の処理

ボキャブラリコンポーネントの開発手順を追う前に、ユーザーの操作の処理について、次の点から簡単に説明します。

ユーザーによるキーやマウスの操作は、イベントとしてボキャブラリコンポーネントへ通知されます。このイベントは、XVCDで作成したボキャブラリコンポーネントにはXML文書フラグメントの形式で表されて通知されます。このXML文書フラグメントの内容で発生したイベントの内容を区別できます。イベントのXML文書フラグメントには、プラットフォームイベントの名前空間が使用されています。

通知されたイベントは、 xvcd:action要素で受け取ります。xvcd:action要素のevent属性に処理する対象のイベントを特定するXPath式を記述します。このXPath式を評価し、通知されたイベントのXML文書フラグメントの内容に適合したときに、そのxvcd:action要素の内容に記述された処理が適用されます。XPath式を評価するときのコンテキストノードは、イベントのXML文書フラグメントのルートノードです。

次の章から、実例を使って、XVCDでユーザーの操作を処理する方法を説明します。

3. 使用するXML文書とXVCDの準備

「XVCDによるボキャブラリコンポーネントの作成」では、xfy Clientを使って文字列を表示・編集できることを説明しました。今度は、作成したHelloWorldボキャブラリコンポーネントにさまざまなキーやマウス操作を追加し、XML文書のデータ構造を操作します。この章では、その説明に使用するXML文書とXVCDを用意します。

3.1. XMLデータの定義

まず、表示対象となるXML文書ファイルを用意します。 ここでは、次のXML文書を使用します。

<?xml version="1.0"?>

<hw:document xmlns:hw="http://xmlns.example.com/developer/tutorial/helloworld">
    <hw:message>
        Hello World!
    </hw:message> 
</hw:document>

これは、「XVCDによるボキャブラリコンポーネントの作成」の「2. XML文書の表示」で使用したのと同じXML文書です。そのため、XML文書のデータ構造の説明は省略します。

まだXVCDファイルは作成していませんが、あらかじめこのXML文書に関連付けるXVCDファイルを指定しておきましょう。作成するXVCDのファイル名は、HelloWorld4.xvcdとします。

<?xml version="1.0"?>

<?com.xfy vocabulary-connection href="HelloWorld4.xvcd" ?>
<hw:document xmlns:hw="http://xmlns.example.com/developer/tutorial/helloworld">
    <hw:message>
        Hello World!
    </hw:message> 
</hw:document>

XML文書が作成できたら、HelloWorld4.xmlというファイル名で適切なフォルダに保存します。

3.2. XVCD定義

次に、XVCDによるボキャブラリコンポーネントを作成します。上記のXML文書を表示するためのXVCDは、次のとおりです。

<?xml version="1.0"?>

<xvcd:xvcd
    xmlns:xvcd="http://xmlns.xfy.com/xvcd" 
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:hw="http://xmlns.example.com/developer/tutorial/helloworld"
    version="1.0">

    <xvcd:vocabulary name="HelloWorld4" match="hw:document" call-template="root"/>

    <xvcd:template name="root">
        <html>
            <head>
                <title>HelloWorld example</title>
            </head>
            <body>
                <xvcd:apply-templates select="*"/>
            </body>
        </html>
    </xvcd:template>

    <xvcd:template match="hw:message">
        <p>
            <xvcd:text-of select="."/>
        </p>
    </xvcd:template>
</xvcd:xvcd>

作成したXVCDは、HelloWorld4.xvcdというファイル名で保存します。HelloWorld4.xvcdは、HelloWorld4.xmlと同じフォルダに保存します。

以下の章では、このXVCDにキーボード操作やマウス操作への処理を追加していきます。

4. キー操作によるXML文書データ構造の操作

「XVCDによるボキャブラリコンポーネントの作成」では、メニューからコマンドを呼び出したり、マウスを右クリックしてコンテキストメニューを呼び出す方法を学びました。ここでは、キーボードの操作でXML文書のデータ構造を自由に操作できるようにします。

キーボードの操作はキーイベントで表現されます。キーイベントの処理をXVCDに記述して、キーボードの操作に対応します。

4.1. Enterキーを使ったXML文書フラグメントの追加と分割

まず、Enterキーが押されたときに、XML文書フラグメントを追加したり分割したりする処理を追加しましょう。

4.1.1. データイメージ

まず、XML文書フラグメントを追加したり分割したりするには、データ構造をどのように変化させればよいかを考えてみましょう。ここでは、HelloWorld4.xmlのメッセージを追加したり分割したりすることを考えます。

HelloWorld4.xmlが次のようになれば、メッセージが追加されたことになります。強調文字で表記した箇所が、追加された構造です。

<?xml version="1.0"?>

<?com.xfy vocabulary-connection href="HelloWorld4.xvcd" ?>
<hw:document xmlns:hw="http://xmlns.example.com/developer/tutorial/helloworld">
    <hw:message>
        Hello World!
    </hw:message> 
    <hw:message>
    </hw:message>
</hw:document>

また、HelloWorld4.xmlが次のようになれば、メッセージを分割したことになります。強調文字で表記した箇所が、変更された構造です。

<?xml version="1.0"?>

<?com.xfy vocabulary-connection href="HelloWorld4.xvcd" ?>
<hw:document xmlns:hw="http://xmlns.example.com/developer/tutorial/helloworld">
    <hw:message>
        Hello
    </hw:message>
    <hw:message>
        World!
    </hw:message>
</hw:document>

4.1.2. XVCD定義

XVCDにイベントの処理を追加するには、 xvcd:action要素を使用します。xvcd:action要素は、キャンバス上に表示された変換後文書のノードの子要素として記述します。ここでは変換後文書のノードにXHTMLを使用しているので、html要素の子ノードとしてxvcd:action要素を記述します。

イベントをキャッチするには、xvcd:action要素のevent属性に対象とするイベントを特定するXPath式を記述します。今回は「Enterキーが押されたとき」の処理なので、stroke属性の値にEnterキーを表すENTERが設定された event:key-pressedイベントが対象のイベントです。これを表現したXPath式「event:key-pressed[@stroke='ENTER']」をxvcd:action要素のevent属性に記述します。

ここまでの内容を適用したxvcd:action要素は以下のようになります。

<html>
<!-- 変換後文書のノードはXHTMLなので、html要素にxvcd:action要素を関連付ける -->

    <xvcd:action event="event:key-pressed[@stroke='ENTER']">
        <!-- stroke属性の値がENTERのevent:key-pressedイベントを指定する -->
         ......
    </xvcd:action>

    .....
</html>

イベントをキャッチしたときに行う処理は、xvcd:action要素の内容に記述します。今回はEnterキーが押されたときに、キャレット位置のノードを分割する処理を記述します。キャレット位置を境界としてノードを2つに分割するコマンドインストラクション要素は、 xvcd:splitコマンドインストラクションです。このxvcd:splitコマンドインストラクションをxvcd:action要素の内容に記述します。

xvcd:splitコマンドインストラクションの内容には、要素を分割するときの条件とノードを分割できないときに実行する処理とを記述します。要素を分割するときの条件は、 xvcd:main-elements要素 xvcd:sub-elements要素を使用して記述します。ノードを分割できないときに実行する処理は、 xvcd:default要素を使用して記述します。

Enterキーが押されたときにhw:message要素を分割できるのは、キャレットがhw:message要素のノードにあるときです。このときにキャレット位置のノードを分割するので、xvcd:main-elements要素のtest属性にhw:messageを指定します。ノードを分割できない状態でEnterキーが押されたときはhw:message要素を新しく追加します。この処理のために、xvcd:default要素の内容に xvcd:insertコマンドインストラクションを指定します。

ここまでの内容を適用したユーザー操作イベント定義は以下のようになります。強調文字で表記した箇所が、追加・変更された箇所です。 イベントの記述が追加されたため、XML名前空間宣言にxmlns:event="http://xmlns.xfy.com/event"が追加されていることに注意してください。

<?xml version="1.0"?>

<xvcd:xvcd
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xvcd="http://xmlns.xfy.com/xvcd" 
    xmlns:event="http://xmlns.xfy.com/event"
    xmlns:hw="http://xmlns.example.com/developer/tutorial/helloworld"
    version="1.0">

<!-- =============================================
	Vocabulary
===============================================	-->
    <xvcd:vocabulary name="HelloWorld4" match="hw:document" call-template="root"/>

<!-- =============================================
	Template Rules
===============================================	-->
    <xvcd:template name="root">
        <html>
            <!-- KEY EVENT -->
            <xvcd:action event="event:key-pressed[@stroke='ENTER']">
                <xvcd:split>
                    <xvcd:main-elements test="self::hw:message"/>
                    <xvcd:default>
                        <xvcd:insert
                                ref="xvcd:caret-node()/ancestor-or-self::hw:message[1]"
                                position="after">
                            <hw:message/>
                        </xvcd:insert>
                    </xvcd:default>
                </xvcd:split>
            </xvcd:action>

            <head>
                <title>HelloWorld example</title>
            </head>
            <body>
               <xvcd:apply-templates select="*"/>
            </body>
        </html>
    </xvcd:template>

    <xvcd:template match="hw:message">
        <p>
            <xvcd:text-of select="." filler="[** Enter any text here.]"/>
        </p>
    </xvcd:template>
</xvcd:xvcd>

編集が完了したら、HelloWorld4.xvcdを上書き保存します。

実際にxfy Clientで動作を確かめましょう。次の操作で、HelloWorld4.xmlをxfy Clientで開きます。

  1. xfy Clientを起動します
  2. [ファイル - 開く]を選択します
  3. HelloWorld4.xmlを選択して、[開く]をクリックします

Enterキーを押すと、新しいメッセージを追加したり、メッセージの文字列を分割したりすることができます。

新しいメッセージが追加された
新しいメッセージが追加された
Hello World!が分割された
Hello World!が分割された

4.2. DeleteキーとBackspaceキーを使ったXML文書フラグメントの結合

「Enterキーを使ったXML文書フラグメントの追加と分割」では、Enterキーの入力でXML文書フラグメントを分割したり、追加したりしました。今度は、DeleteキーやBackspaceキーが押されたときにXML文書フラグメントを結合する処理を追加しましょう。

まず、Deleteキーの処理を追加します。連続する2つのノードを結合するコマンドインストラクション要素は、 xvcd:combineコマンドインストラクションです。このxvcd:combineコマンドインストラクションを xvcd:action要素の内容に記述します。xvcd:action要素のevent属性には、stroke属性の値にDeleteキーを表すDELETEが設定された event:key-pressedイベントを表すXPath式「event:key-pressed[@stroke='DELETE']」を記述します。

Deleteキーが押されたときにhw:message要素を結合できるのは、キャレットがhw:message要素のノードにあるときです。このときに、キャレット位置のノードを直後にあるノードと結合するので、 xvcd:main-elements要素test属性にhw:messageを指定します。

ノードを結合できない状態でDeleteキーが押されたときは、選択されている文字列を削除します。削除処理を行うコマンドインストラクション要素は、 xvcd:deleteコマンドインストラクションです。select属性には削除する対象を指定します。削除する対象は選択されている範囲なので、 xvcd:selection-range関数を使用します。

ここまでの内容を適用したユーザー操作イベント定義は以下のようになります。強調文字で表記した箇所が、追加された箇所です。

<?xml version="1.0"?>

<xvcd:xvcd
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xvcd="http://xmlns.xfy.com/xvcd" 
    xmlns:event="http://xmlns.xfy.com/event"
    xmlns:hw="http://xmlns.example.com/developer/tutorial/helloworld"
    version="1.0">

<!-- =============================================
	Vocabulary
===============================================	-->
    <xvcd:vocabulary name="HelloWorld4" match="hw:document" call-template="root"/>

<!-- =============================================
	Template Rules
===============================================	-->
    <xvcd:template name="root">
        <html>
            <!-- KEY EVENT -->
             <xvcd:action event="event:key-pressed[@stroke='ENTER']">
                <xvcd:split>
                    <xvcd:main-elements test="self::hw:message"/>
                    <xvcd:default>
                        <xvcd:insert
                                ref="xvcd:caret-node()/ancestor-or-self::hw:message[1]"
                                position="after">
                            <hw:message/>
                     </xvcd:insert>
                 </xvcd:default>
                </xvcd:split>
            </xvcd:action>

            <xvcd:action event="event:key-pressed[@stroke='DELETE']">
                <xvcd:combine>
                    <xvcd:main-elements test="self::hw:message"/>
                    <xvcd:default>
                        <xvcd:delete select="xvcd:selection-range()"/>
                    </xvcd:default>
                </xvcd:combine>
            </xvcd:action>

            <head>
                <title>HelloWorld example</title>
            </head>
            <body>
               <xvcd:apply-templates select="*"/>
            </body>
        </html>
    </xvcd:template>

    <xvcd:template match="hw:message">
        <p>
            <xvcd:text-of select="." filler="[** Enter any text here.]"/>
        </p>
    </xvcd:template>
</xvcd:xvcd>

続いて、Backspaceキーの処理を追加します。Backspaceキーのイベントを処理するxvcd:action要素を追加します。event属性には、stroke属性の値にBackspaceキーを表すBACK_SPACEが設定されたevent:key-pressedイベントを表すXPath式「event:key-pressed[@stroke='BACK_SPACE']」を記述します。このxvcd:action要素の内容にxvcd:combineコマンドインストラクションを記述します。

Backspaceキーの場合は直前にあるノードと結合すればよいので、xvcd:combineコマンドインストラクションのto属性に結合対象ノードの結合方向を属性値テンプレートで指定します。この場合、beforeを指定します。

また、xvcd:deleteコマンドインストラクションのbackspace属性に文字を削除するときの動作を指定します。この場合、yesを指定します。

ここまでの内容を適用したユーザー操作イベント定義は以下のようになります。強調文字で表記した箇所が、追加された箇所です。

<?xml version="1.0"?>

<xvcd:xvcd
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xvcd="http://xmlns.xfy.com/xvcd" 
    xmlns:event="http://xmlns.xfy.com/event"
    xmlns:hw="http://xmlns.example.com/developer/tutorial/helloworld"
    version="1.0">

<!-- =============================================
	Vocabulary
===============================================	-->
    <xvcd:vocabulary name="HelloWorld4" match="hw:document" call-template="root"/>

<!-- =============================================
	Template Rules
===============================================	-->
    <xvcd:template name="root">
        <html>
            <!-- KEY EVENT -->
             <xvcd:action event="event:key-pressed[@stroke='ENTER']">
                <xvcd:split>
                    <xvcd:main-elements test="self::hw:message"/>
                    <xvcd:default>
                        <xvcd:insert
                                ref="xvcd:caret-node()/ancestor-or-self::hw:message[1]"
                                position="after">
                            <hw:message/>
                     </xvcd:insert>
                 </xvcd:default>
                </xvcd:split>
            </xvcd:action>

            <xvcd:action event="event:key-pressed[@stroke='DELETE']">
                <xvcd:combine>
                    <xvcd:main-elements test="self::hw:message"/>
                    <xvcd:default>
                        <xvcd:delete select="xvcd:selection-range()"/>
                    </xvcd:default>
                </xvcd:combine>
            </xvcd:action>

             <xvcd:action event="event:key-pressed[@stroke='BACK_SPACE']">
                <xvcd:combine to="before">
                    <xvcd:main-elements test="self::hw:message"/>
                    <xvcd:default>
                        <xvcd:delete select="xvcd:selection-range()" backspace="yes"/>
                    </xvcd:default>
                </xvcd:combine>
            </xvcd:action>

            <head>
                <title>HelloWorld example</title>
            </head>
            <body>
               <xvcd:apply-templates select="*"/>
            </body>
        </html>
    </xvcd:template>

    <xvcd:template match="hw:message">
        <p>
            <xvcd:text-of select="." filler="[** Enter any text here.]"/>
        </p>
    </xvcd:template>
</xvcd:xvcd>

編集が完了したら、HelloWorld4.xvcdを上書き保存します。

実際にxfy Clientで動作を確かめましょう。次の操作で、HelloWorld4.xmlをxfy Clientで開きます。

  1. xfy Clientを起動します
  2. [ファイル - 開く]を選択します
  3. HelloWorld4.xmlを選択して、[開く]をクリックします

DeleteキーやBackspaceキーを押すと、文字列を削除したり、ノードを結合したりすることができます。

DELETEキーでノードが結合された
DeleteキーやBackspaceキーでノードを結合する

4.3. キーの組み合わせによるXML文書フラグメントの移動

今度は、Ctrlキーと矢印キーを組み合わせて、ノードを上下に移動させてみましょう。

変換元XML文書内のXML文書フラグメントを指定した位置へ移動するコマンドインストラクション要素は、 xvcd:moveコマンドインストラクションです。このxvcd:moveコマンドインストラクションをコマンド定義内に記述します。コマンド定義は、「XVCDによるボキャブラリコンポーネントの作成」の「4.2.2. XML文書のデータ構造へのXML文書フラグメントの追加」で学習したとおりです。

xvcd:moveコマンドインストラクションの各属性には、それぞれ次の値を設定します。

select属性
移動するXML文書フラグメントを、XPath式で設定します。
ref属性
XML文書フラグメントの移動先のノードまたは範囲を、XPath式で設定します。
position属性
ref属性で指定された基準ノードに対する、XML文書フラグメントの挿入位置を属性値テンプレートで設定します。

xvcd:moveコマンドインストラクションのselect属性とref属性の値は、しばしば長くなります。ここでは instruction:param要素を使用して値の記述を短くしています。instruction:param要素を使用すると、コマンド内で使用する値を変数に割り当てることができます。instruction:param要素のname属性には変数名を、select属性には変数の値を、それぞれ記述します。割り当てた変数を参照するときは、XPath式を使用して「$変数名」と記述します。

ノードを上下に移動させるコマンドは以下のようになります。

    <xvcd:command name="move-forward">
        <instruction:param name="message"
            select="xvcd:caret-node()/ancestor-or-self::hw:message[1]"/>
        <xvcd:move select="$message"
            ref="$message/preceding-sibling::hw:message[1]" position="before"/>
    </xvcd:command>

    <xvcd:command name="move-backward">
        <instruction:param name="message"
            select="xvcd:caret-node()/ancestor-or-self::hw:message[1]"/>
        <xvcd:move select="$message"
            ref="$message/following-sibling::hw:message[1]" position="after"/>
    </xvcd:command>

これらのコマンドをユーザーの操作によるイベントと関連付けます。Ctrlキーと組み合わせるキーは、ノードを上下に移動させるので、上矢印キーと下矢印キーにします。Ctrlキーと上矢印キーを同時に押す操作は、Ctrl+UPで表されます。同様に、Ctrlキーと下矢印キーを同時に押す操作は、Ctrl+DOWNで表されます。

xvcd:action要素内でコマンドを呼び出すには、 instruction:call要素を使用します。instruction:call要素のname属性に、呼び出したいコマンドの名前を記述します。

これまでの内容を反映したXVCDは、次のようになります。強調文字で表記した箇所が追加された箇所です。プラットフォームコマンドインストラクションの要素をXVCD内で使用しているため、XML名前空間宣言にxmlns:instruction="http://xmlns.xfy.com/instruction"が追加されていることに注意してください。

<?xml version="1.0"?>

<xvcd:xvcd
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xvcd="http://xmlns.xfy.com/xvcd" 
    xmlns:event="http://xmlns.xfy.com/event"
    xmlns:instruction="http://xmlns.xfy.com/instruction"
    xmlns:hw="http://xmlns.example.com/developer/tutorial/helloworld"
    version="1.0">

<!-- =============================================
	Command
===============================================	-->
    <xvcd:command name="move-forward">
        <instruction:param name="message"
            select="xvcd:caret-node()/ancestor-or-self::hw:message[1]"/>
        <xvcd:move select="$message"
            ref="$message/preceding-sibling::hw:message[1]" position="before"/>
    </xvcd:command>

    <xvcd:command name="move-backward">
        <instruction:param name="message"
            select="xvcd:caret-node()/ancestor-or-self::hw:message[1]"/>
        <xvcd:move select="$message"
            ref="$message/following-sibling::hw:message[1]" position="after"/>
    </xvcd:command>


<!-- =============================================
	Vocabulary
===============================================	-->
    <xvcd:vocabulary name="HelloWorld4" match="hw:document" call-template="root"/>

<!-- =============================================
	Template Rules
===============================================	-->
    <xvcd:template name="root">
        <html>
            <!-- KEY EVENT -->
             <xvcd:action event="event:key-pressed[@stroke='ENTER']">
                <xvcd:split>
                    <xvcd:main-elements test="self::hw:message"/>
                    <xvcd:default>
                        <xvcd:insert ref="xvcd:caret-node()/ancestor-or-self::hw:message[1]" position="after">
                            <hw:message/>
                     </xvcd:insert>
                 </xvcd:default>
                </xvcd:split>
            </xvcd:action>

            <xvcd:action event="event:key-pressed[@stroke='DELETE']">
                <xvcd:combine>
                    <xvcd:main-elements test="self::hw:message"/>
                    <xvcd:default>
                        <xvcd:delete select="xvcd:selection-range()"/>
                    </xvcd:default>
                </xvcd:combine>
            </xvcd:action>

             <xvcd:action event="event:key-pressed[@stroke='BACK_SPACE']">
                <xvcd:combine to="before">
                    <xvcd:main-elements test="self::hw:message"/>
                    <xvcd:default>
                        <xvcd:delete select="xvcd:selection-range()" backspace="yes"/>
                    </xvcd:default>
                </xvcd:combine>
            </xvcd:action>

            <xvcd:action event="event:key-pressed[@stroke='Ctrl+UP']">
                <instruction:call name="move-forward"/>
            </xvcd:action>

            <xvcd:action event="event:key-pressed[@stroke='Ctrl+DOWN']">
                <instruction:call name="move-backward"/>
            </xvcd:action>

            <head>
                <title>HelloWorld example</title>
            </head>
            <body>
               <xvcd:apply-templates select="*"/>
            </body>
        </html>
    </xvcd:template>

    <xvcd:template match="hw:message">
        <p>
            <xvcd:text-of select="." filler="[** Enter any text here.]"/>
        </p>
    </xvcd:template>
</xvcd:xvcd>

編集が完了したら、HelloWorld4.xvcdを上書き保存します。

実際にxfy Clientで動作を確かめましょう。次の操作で、HelloWorld4.xmlをxfy Clientで開きます。

  1. xfy Clientを起動します
  2. [ファイル - 開く]を選択します
  3. HelloWorld4.xmlを選択して、[開く]をクリックします

Ctrlキーと上矢印キーを同時に押すと、ノードを上に移動することができます。また、Ctrlキーと下矢印キーを同時に押すと、ノードを下に移動することができます。

ノードを上下に移動させる
ノードを上下に移動させる

5. マウス操作によるXML文書データ構造の操作

「キー操作によるXML文書データ構造の操作」ではキーイベントにさまざまな機能を関連付けました。今度は機能をマウスイベントに関連付けしてみましょう。 マウス操作を実現するために必要なものは、XML文書ファイルとXVCDファイルです。

引き続き、HelloWorld4.xmlHelloWorld4.xvcdを使用して説明します。

5.1. 右クリックによる文字の強調

ここでは、マウスを右クリックすることで、選択された文字列を強調表示させるようにします。

5.1.1. データイメージ

まず、選択したHelloWorld4.xml内の文字列を強調表示させるには、XML文書のデータ構造をどのように変化させればよいかを考えてみましょう。まず、HelloWorld4.xmlのXMLデータ構造に、強調された文字列を表現するhw:strong要素を追加します。

HelloWorld4.xmlが次のようになれば、文字列を強調表示できます。強調文字で表記した箇所が、変更された構造です。

<?xml version="1.0"?>

<?com.xfy vocabulary-connection href="HelloWorld4.xvcd" ?>
<hw:document xmlns:hw="http://xmlns.example.com/developer/tutorial/helloworld">
    <hw:message>
        Hello 
        <hw:strong>World!</hw:strong>
    </hw:message> 
</hw:document>

選択された文字列をhw:strong要素で囲んでいます。この例では、「World!」がその文字列です。このXML文書にXVCDのテンプレートルールを適用すると、文字列を強調表示させることができます。

5.1.2. XVCD定義

XVCDにマウスイベントを追加するには、 xvcd:action要素event属性にマウスイベントを指定します。ここでは「右クリック」ですから、 event:mouse-clickedイベントを使用します。イベントの記述方法は、キーイベントのときと同じです。xvcd:action要素は以下のようになります。

<html>
<!-- 変換後文書のノードはXHTMLなので、html要素にxvcd:action要素を関連付ける -->

    <xvcd:action event="event:mouse-clicked[@button='3']">
        <!-- 「右クリック」なので、button属性の値が3のevent:mouse-clickedイベントを指定する
        -->
        .....
    </xvcd:action>

    .....
</html>

選択された範囲を指定した要素で囲むコマンドインストラクション要素は、 xvcd:surround-contentsコマンドインストラクションです。xvcd:surround-contentsコマンドインストラクションのparent-name属性に、選択した範囲を囲むために使用する要素の名前を記述します。ここでは、選択された範囲をhw:strong要素で囲むので、コマンドは以下のようになります。コマンド名はstrongとします。

<xvcd:command name="strong">
    <xvcd:surround-contents parent-name="hw:strong"/>
</xvcd:command>

このコマンドをユーザーの操作によるイベントと関連付けます。右クリックするイベントなので、button属性の値が「3」のevent:mouse-clickedイベントと関連付けます。コマンドを呼び出すには、 instruction:call要素を使用します。instruction:call要素のname属性にコマンド名strongを指定します。xvcd:action要素の定義は次のようになります。

<xvcd:action event="event:mouse-clicked[@button='3']">
    <instruction:call name="strong"/>
</xvcd:action>

これまでの内容を適用したXVCDは次のようになります。また、新しく追加されたhw:strong要素に対応するため、XVCDのテンプレートルールも変更されています。強調文字で表記された箇所が、追加・変更された箇所です。

<?xml version="1.0"?>

<xvcd:xvcd
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xvcd="http://xmlns.xfy.com/xvcd" 
    xmlns:event="http://xmlns.xfy.com/event"
    xmlns:instruction="http://xmlns.xfy.com/instruction"
    xmlns:hw="http://xmlns.example.com/developer/tutorial/helloworld"
    version="1.0">

<!-- =============================================
	Command
===============================================	-->
    <xvcd:command name="move-forward">
        <instruction:param name="message" select="xvcd:caret-node()/ancestor-or-self::hw:message[1]"/>
        <xvcd:move select="$message" ref="$message/preceding-sibling::hw:message[1]" position="before"/>
    </xvcd:command>

    <xvcd:command name="move-backward">
        <instruction:param name="message" select="xvcd:caret-node()/ancestor-or-self::hw:message[1]"/>
        <xvcd:move select="$message" ref="$message/following-sibling::hw:message[1]" position="after"/>
    </xvcd:command>

    <xvcd:command name="strong">
        <xvcd:surround-contents parent-name="hw:strong"/>
    </xvcd:command>

<!-- =============================================
	Vocabulary
===============================================	-->
    <xvcd:vocabulary name="HelloWorld4" match="hw:document" call-template="root"/>

<!-- =============================================
	Template Rules
===============================================	-->
    <xvcd:template name="root">
        <html>
            <!-- MOUSE EVENT -->
            <xvcd:action event="event:mouse-clicked[@button='3']">
                 <instruction:call name="strong"/>
            </xvcd:action>

            <!-- KEY EVENT -->
             <xvcd:action event="event:key-pressed[@stroke='ENTER']">
                <xvcd:split>
                    <xvcd:main-elements test="self::hw:message"/>
                    <xvcd:default>
                        <xvcd:insert
                                ref="xvcd:caret-node()/ancestor-or-self::hw:message[1]"
                                position="after">
                            <hw:message/>
                     </xvcd:insert>
                 </xvcd:default>
                </xvcd:split>
            </xvcd:action>

            <xvcd:action event="event:key-pressed[@stroke='DELETE']">
                <xvcd:combine>
                    <xvcd:main-elements test="self::hw:message"/>
                    <xvcd:default>
                        <xvcd:delete select="xvcd:selection-range()"/>
                    </xvcd:default>
                </xvcd:combine>
            </xvcd:action>

             <xvcd:action event="event:key-pressed[@stroke='BACK_SPACE']">
                <xvcd:combine to="before">
                    <xvcd:main-elements test="self::hw:message"/>
                    <xvcd:default>
                        <xvcd:delete select="xvcd:selection-range()" backspace="yes"/>
                    </xvcd:default>
                </xvcd:combine>
            </xvcd:action>

            <xvcd:action event="event:key-pressed[@stroke='Ctrl+UP']">
                <instruction:call name="move-forward"/>
            </xvcd:action>

            <xvcd:action event="event:key-pressed[@stroke='Ctrl+DOWN']">
                <instruction:call name="move-backward"/>
            </xvcd:action>

            <head>
                <title>HelloWorld example</title>
            </head>
            <body>
               <xvcd:apply-templates select="*"/>
            </body>
        </html>
    </xvcd:template>

    <xvcd:template match="hw:message">
        <p>
            <xvcd:apply-templates>
                <xvcd:filler>
                    <xvcd:text-of select="." filler="[** Enter any text here.]"/>
                </xvcd:filler>
            </xvcd:apply-templates>
        </p>
    </xvcd:template>

    <xvcd:template match="hw:strong">
        <strong>
            <xvcd:apply-templates/>
        </strong>
    </xvcd:template>

    <xvcd:template match="text()">
        <xvcd:text-of select="."/>
    </xvcd:template>
</xvcd:xvcd>

編集が完了したら、HelloWorld4.xvcdを上書き保存します。

実際にxfy Clientで動作を確かめましょう。次の操作で、HelloWorld4.xmlをxfy Clientで開きます。

  1. xfy Clientを起動します
  2. [ファイル - 開く]を選択します
  3. HelloWorld4.xmlを選択して、[開く]をクリックします

テキストを選択してマウスを右クリックすると、選択されたテキストが強調表示されます。

右マウスボタンクリックでテキストを強調する
右マウスボタンクリックでテキストを強調する

6. まとめ

このチュートリアルで学んだことをまとめておきます。