Smart CODE
生成済みコードに関するオンラインガイド

Web コンテンツを使用する。HTML 以降。既製の例題を使った学習


概要

この例題では、取り込みアプリケーションをさらに進歩させています。これまでに、WWW 上の任意の URL で生の HTML を取り出すアプリケーションを設計しました。今度は、そのドキュメント内の情報を自身の目的のために使用したいと思います。 

HTML は、ある大変単純な理由から、Web データのフォーマットとして使用されてきました。Web の本来意図するところは、巨大な情報倉庫でした。Web ページには、構造化された情報 (HTML マークアップ DTD を使用して) が格納されていました。Web アーキテクチャでは、ページを特定の表示メカニズムの対象にすることは望んでいませんでした。Web の目的は、巨大なハイパーテキスト情報の倉庫になることでした。特許を持つ特定のブラウザによる表示だけが可能な設定済みのページセットになることは望んでいません。 

長い間、これは Web ブラウザ開発者が唯一興味を感じることでしたが、表示方法ではなく、内容を表すためにコンテンツにマークアップすることの利点の 1 つは、手作業で HTML のページを記述するほうが、同じページを TeX、*roff、またはその他の表示指向の表記法でマークアップするよりはるかに簡単だということです。 

X-Designer 7 を使用すると、どのようなアプリケーションでも、ローカルマシン上のリソースと同様に、インターネット上のリソースも簡単に使用できます。しかし、URL を HTML ドキュメントとしてダウンロードすることと、このドキュメントを処理し、単純な Web ブラウザで表示されるデフォルトの方法で表示するだけでなく、ニーズに合わせてその情報を使用することは、まったく別の問題です。 

情報をすばやく入手する

インターネットリソースを使用するときに最初に必要になるのは、HTML を解析する手段です。次に、禁止事項を 2 つ示します。 
  • 独自の解析機能を記述しない。徹底的に作り直すのは無意味です。 
  • 手書きの HTML 構文解析プログラムを使用しない。HTML 規格は常に変化していて (現在は、HTML3.2 が一般的に使用されています)、ほかの SGML DTD も Web 上で使用され始め、注目される XML (Extended Markup Language) は HTML DTD とフル SGML の中間に位置しているためです。
  • 当社では、ライセンス規定がかなり緩やかな SGML ユーザーグループの SGML 構文解析プログラム資料を参照し、汎用 SGML 構文解析エンジンの制作に採用しています。この構文解析エンジンは HTML DTD から直接操作できるため、DTD を更新することにより解析処理も更新することができます。再コンパイルは必要ありません。また、イントラネットで使用されるほかの標準または自社開発による DTD にも使用することができます。 

    構文解析は、困難な処理です。構文解析プログラムの解析ツリー出力を取得して、それを分析するだけでも、数分の作業では終わりません。そこで、Web から受信するデータ入力ストリームをユーザー入力ストリームと同じ方法で扱うことにより、処理を単純化しました。ユーザーのアプリケーションでは、ユーザーが発生させた特定の主要イベントに注目してユーザー入力を処理します。これらのイベントの 1 つが発生するたびに、コールバックが呼び出されます。インターネットから受信する HTML データにも、まったく同じ方法でアクセスできます。

    HTML InputStream から注目する内容を選び出す

    やらなければならないことは、HTML の機能の中で注目するものを決定し、入力ストリームで特定のタグまたは属性が検出されたときに呼び出される独自のコールバックを登録することだけです。 

    この例では、ドキュメント内のリンクをすべて選び出し、それをテキストウィジェットに表示しています。この処理を行うために、<A> アンカーの HREF 属性に目標を設定しています。入力のほかの部分には注意が向けられないため、時間を無駄にすることがありません。リンクリファレンスは、参照された時点で、ストリームから切り離されます。

    例題を実行する前に必要な作業と知識

    環境変数、ほか

    これは、コンパイル済みのコードを使用する唯一の例題です。ソースは $XDROOT/src/sgml に格納されています。ライセンス規定では自由に使用できるようになっていますが、最初はコンパイル済みのエンジンを使用することをお勧めします。 

    ファイルおよびディレクトリについて、次のことはあらかじめ理解しておく必要があります。

  • $XDROOT/lib には、sgml ライブラリのアーカイブバージョンと共用バージョンが格納されています。デフォルトのコンパイルでは libsgml.so が使用されますが、必要であれば、libsgml.a とリンクさせることができます。 
  • $XDROOT/src/sgml/hdrs/SGML.h は、付属の構文解析エンジン API に必要な組み込みファイルです。このファイルは、スマートコードの「カスタマイズ」ダイアログで「 SGML/HTML パーサ」トグルを設定した場合、メークファイルで参照されます。 
  • $XDROOT/src/sgml/dtds は、HTML 3.2 DTD とその他の関連データファイルが格納されているディレクトリです。構文解析プログラムでは、このディレクトリを検索することが必要になるため、検索のために DTDDIR 環境変数を設定する必要があります。
  • 通常どおり、パスには必ず $XDROOT/bin を指定します。

    例題を使用した作業を始める前に設定が必要な変数は以下のものです。

    XDROOT
    LM_LICENSE_FILE
    DTDDIR $XDROOT/src/sgml/dtds に設定
    LD_LIBRARY_PATH $XDROOT/lib を含める

    例題を準備する

    手順 1 新しいディレクトリを作成し、ここでは仮に htmlfilter という名前を付けます。
    手順 2 htmlfilter ディレクトリに移動します。
    手順 3 xdreplay スクリプトの $XDROOT/src/examples/sc/hfetch.vcr を使用して、xdesigner を実行します。次のように、指定します。
    $ xdreplay -f $XDROOT/src/examples/sc/hfetch.vcr xdesigner
    
    
    これを実行すると、アプリケーション例題が作成され、コードが生成され、ユーザーが記述しておいたコールバックの標準バージョンが適切な箇所にコピーされて、プログラムを構築するための呼び出しが行われます。 

    例題を実行する

    まず、環境変数が設定されていることを確認します。問題がある場合は、正しく設定されているかチェックします。
    $ ls $DTDDIR
    
    
    次のように入力してアプリケーション例題を実行します。
    $ ./untitled
    
    
    このアプリケーションは、前述の HTML 取り込みプログラムとまったく同様に動作しますが、例外として、テキストウィジェットに表示される内容は、URL からフィルタされたリンクセットだけになります。 

    ファイアウォールが存在する場合、Web ブラウザ用にプロキシを設定するときと同様に、「プロキシ・ホスト」フィールドにプロキシの名前を設定し、「プロキシ・ポート」フィールドにポート番号を設定する必要があります。 

    URL を取り込んで処理するには、次の例のように、「URL」フィールドに完全な URL を入力します。

    http://www.ist.co.uk/index.html
    
    
    次に、「Fetch」ボタンを押します。 

    処理済みの情報がテキストウィジェット内に格納されます。

    手順の説明

    先の HTML 取り込み例のすべての説明が、この例にも適用されます。 インタフェース構造体、グループ、およびコールバックは同じです。 

    唯一の相違点は、「カスタマイズ」に「SGML/HTML パーサ」トグルが設定されていることです。この設定により、アプリケーションを構築し、HTML 構文解析プログラムサポートとリンクするように、メークファイル内の組み込みディレクトリとライブラリ設定が確実に調整されます。

    受信した HTML を処理する

    これが、前の例とは大きく異なる唯一の点です。前の例では、単純に入力をバッファに読み込み、それをデータテキストウィジェットに表示しました。 

    応答および構築スクリプトは、このファイルの修正済みバージョンを callouts_c ディレクトリにコピーします。作業用の完全にコメントされたファイルは、次の場所にあります。

    $XDROOT/src/examples/sc/datafiles/hfetch/myData.c

    callouts_c/myData.c ファイルは、2 つの部分に分かれています。最初の部分は myData() 関数で、受信データの MIME 型をチェックし、<A> アンカーの HREF 属性にコールバックを設定し、構文解析エンジンを呼び出して、データ領域を更新するためのルーチンを呼び出します。これは、X または Motif でコールバックを設定した場合と同じくらい簡単にデータ入力ストリームを処理できることを示しているので、この例のもっとも重要な部分といえます。 

    この例の 2 番目の部分は、リンクデータをリストに追加するコールバックそのものと、そのリストを取得して、データテキストウィジェットに表示する更新ルーチンで構成されます。 

    myData() ルーチン

    構文解析エンジン API を使用するには、以下のヘッダーファイルをインクルードする必要があります。

    #include <SGML.h>

    この例では、Web から返されるデータ用のデフォルトのハンドラを上書きすることを選択しているため、X-Designer では、グループ、データの MIME 型、InputStream、およびデータ長にアクセスできるようにするスタブを生成します。ただし、データ長は必ずしも有効ではありません。Web サーバーから返される値が -1 になることは、頻繁にあります。

    MyData() のスタブは次のように生成されます。

    int
    myData ( sc_data_t * data )
    {
            mygroup_t * group = (mygroup_t*)data->group;
            char      * type  = data->content_type; /* MIME 型 */
            InputStream i     = (InputStream) data->data;
            int         len   = data->content_length;
    
            return 0;
    }
    
    
    

    構文解析エンジンを使用する

    構文解析エンジンは、次の手順に従って使用します。
    手順 1 構文解析オブジェクト用のハンドルを取得します。これは、ファイル記述子または DIR* を取得する方法と同様です。
    SGML_t * sgm = scRegisterHTML( "text/html");
    
    
    手順 2 独自のコールバックを登録します。たとえば、getlinkinfo() ルーチンとクライアントデータの "href" を登録します。クライアントデータは、データポインタにする方がよいでしょう。
    (void) scAddAttrCallback( sgm,  "A", "HREF",   getlinkinfo, "href");
    
    
    手順 3 ハンドルと入力ストリームを渡して構文解析エンジンを呼び出します。
    (void) scProcessSGML( sgm, i);
    
    

    myData() の最終バージョン

    この例題の myData() ルーチンで使用される、HTML ストリームを解析するために必要なすべてのコードを次に示します。
    #include <SGML.h>
    
    int
    myData ( sc_data_t * data )
    {
            extern int getlinkinfo();
    
            mygroup_t * group = (mygroup_t*)data->group;
            char      * type  = data->content_type; /* MIME 型 */
            InputStream i     = (InputStream) data->data;
            int         len   = data->content_length;
    
    /* コードはここから */
    
            SGML_t * sgm;   /* 構文解析プログラムが使用するあいまいなハンドル */
                            /* FILE* または DIR* に似ている */
    
            if ( strcmp( type, "text/html") != 0) /* 受信データの MIME 型を */
                    return -1;                    /* 調べる */
    
            sgm = scRegisterHTML( type);         /* その MIME 型のパーサオブジェクトを */
                                                 /* 取得する */
    
            (void) scAddTagCallback(  sgm,  "A", ON_ENTRY, getanchor, "a-call");
                                    /* getanchor() は 例のひとつ */
    
            (void) scAddAttrCallback( sgm,  "A", "HREF",   getlinkinfo, "href");
                                    /* gelinkinfo は HTML で検出されるたびに */
                                    /* リンク情報を収集する */
    
            (void) scProcessSGML( sgm, i);
                                    /* ここで InputStream i を処理する */
    
            showMyLinks( group);
                    /* これでデータの構文解析は終わり、*/
                    /* 結果を group->data テキストウィジェットに表示する */
    
    /* コードはここまで */
    
            return 0;
    }
    
    
    

    注意

    Document Type Descriptions (DTDs)MIME 型 構文解析エンジン参照ページ