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

コールバックで HTML を処理する

形式

#include <SGML.h>
SGML_t *
scRegisterSGMLMimeType( mimetype, dtd)
        char * mimetype;
        char * dtd;
SGML_t *
scRegisterHTML( mimetype)
        char * mimetype;
int
scRegisterSGMLErrorHandler( handler)
        void     (*handler)();
int
scAddTagCallback( sgm, tagname, type, callback, data)
        SGML_t * sgm;
        char   * tagname;
        int      type;
        void     (*callback)();
        void   * data;
int
scAddAttrCallback( sgm, tagname, attrname, callback, data)
        SGML_t * sgm;
        char   * tagname;
        char   * attrname;
        void     (*callback)();
        void   * data;
int
scProcessSGML( sgm, istream)
        SGML_t * sgm;
        InputStream istream;
環境変数 DTDDIR
配布の lib ディレクトリ内のライブラリ -lsgml

概要

Web サーバーから取り込むデータの 95% は HTML です。多くの場合、そのデータは直接ブラウザウィジェットに渡すか、または必要な重要情報を抽出するためにフィルタします。

SGML ライブラリは、入力データをフィルタするためのアップグレード可能な標準的なメカニズムを提供します。これは、HTML の解析に時間をとられないように用意されています。これは、特別な構文解析プログラムではなく、SGML User Group の提供する参照構文解析プログラムで、標準の HTML32 DTD を使用します。HTML 規格が進化するに従って、DTD をアップグレードできます。

これは、次のように使用できます。

  • インタフェースに使用するためにテキストの全体または一部を抽出する。
  • カスタマイズされたインタフェースを提供するために、書式の重要な要素を抽出する。
  • リンク情報またはイメージデータを取得する。
  • その他
  • 必要な 4 つの手順

  • 1. MIME 型 scRegisterSGMLMimeType またはショートカット scRegisterHTML の登録
  • 2. エラーハンドラ scRegisterSGMLMimeErrorHandler の登録 [オプション]
  • 3. scAddTagCallback および scAddAttrCallback 入力ストリームの機能に目標を登録 (ただし、解析だけを行い、従来の解析ツリーを出力として取得することも可能)
  • 4. scProcessSGML構文解析プログラムの呼び出し
  • このセクションの後半では、この API のリファレンスマニュアルと処理済み例を紹介します。

    説明

    解析処理は、データ構造、すなわち SGML オブジェクト (SGML_t*) に左右されます。このオブジェクトは、指定された MIME 型に合わせて設定します。これは、MIME 型を登録することによって作成されます。 

    MIME 型を登録する

    SGML_t *
    scRegisterSGMLMimeType( mimetype, dtd)
            char * mimetype;
            char * dtd;
    
    
    これは、MIME 型を SGML DTD と関連付けるために使用します。もっとも一般的な例を次に示します。
    SGML_t * sgm = scRegisterSGMLMimeType( "text/html", "HTML32.soc");
    
    
    もう 1 つの方法を次に示します。
    SGML_t *
    scRegisterHTML( mimetype)
            char * mimetype;
    
    
    これは、テキストまたは html を HTML32 DTD に関連付けます。 

    エラーハンドラを登録する

    デフォルトのエラーハンドラは、エラーメッセージを標準の診断に出力します。次の形式で独自のエラーハンドラを登録することにより、デフォルトのハンドラを無効にすることができます。
    void
    errorhandler( s)
            char * s;
    
    
    次を使用します。
    int
    scRegisterSGMLErrorHandler( handler)
            void_f handler;
    
    

    解析済みの HTML を取得する

    データにアクセスするもっとも簡単な方法は、入力の中の特定の機能に目標を登録し、その機能が発生したときにトリガーされるコールバックを登録する方法です。これは、ユーザーインタフェースプログラミング用のイベント駆動型モデルと同じで、XtAddCallback() を使用しています。 

    TAG 要素に関するコールバック

    登録できるコールバックは、2 種類あります。1 つは TAG 用のコールバックで、次の中から 1 つを指定できます。
    ON_ENTRY
    ON_EXIT
    ON_ATTR

    指定したルーチンを呼び出す時期を次のように指定します。

    int
    mycallback( tag, attribute, type, call_data, client_data)
            char * tag;
            char * attribute;
            int    type;
            void * call_data;
            void * client_data;
    
    
    int
    scAddTagCallback( sgm, tagname, type, callback, data)
            SGML_t * sgm;            /* 解析プログラムは scRegisterSGMLMimeType を処理します */
            char   * tagname;        /* 例: "LI" "MENU" "A" */
            int      type;           /* ON_ENTRY (<MENU> 用) ON_EXIT (</MENU> 用) および ON_ATTR */
            void     (*callback)();  /* ルーチン */
            void   * data;           /* ルーチンに渡したいデータ */
    
    
    

    ATTR 要素に関するコールバック

    int
    scAddAttrCallback( sgm, tagname, attrname, callback, data)
            SGML_t * sgm;            /* 解析プログラムは scRegisterSGMLMimeType を処理します */
            char   * tagname;        /* 例: "A" または "MENU" */
            char   * attrname;       /* 例: "SRC" または "href" */
            void     (*callback)();  /* ルーチン */
            void   * data;           /* ルーチンに渡したいデータ */
    
    

    InputStream を解析する

    最後に次の呼び出しが必要です。
    int
    scProcessSGML( sgm, istream)
            SGML_t * sgm;           /* 解析プログラムは scRegisterSGMLMimeType を処理します */
            InputStream istream;    /* サーバーからの入力ストリーム */
    
    
    
    これでドキュメントを解析します。 

    例として、Web サーバーから返されたデータを処理するためにユーザーが用意したルーチンに対して生成された C のスタブコードを、次に示します。
    int
    processMyData ( sc_data_t * data )
    {
            group0_t * group   = (group0_t*)data->group;
            char      * type   = data->content_type; /*  MIME 型 */
            InputStream i      = (InputStream) data->data;
            int         len    = data->content_length;
    
            return 0;
    }
    
    
    
    次に、上記の例に、入力ストリームが HTML の場合に解析が行われるようにコードを付加した例を示します。
    int
    processMyData ( sc_data_t * data )
    {
            group0_t * group   = (group0_t*)data->group;
            char      * type   = data->content_type; /*  MIME 型 */
            InputStream i      = (InputStream) data->data;
            int         len    = data->content_length;
    
            SGML_t * sgm;
    
            if ( strcmp( type, "text/html") != 0)
                    return -1;
    
            sgm = scRegisterHTML( type);         /* パーサーオブジェクト */
    
            (void) scAddTagCallback(  sgm,  "A", ON_ENTRY, getanchor, "a-call");
            (void) scAddAttrCallback( sgm,  "A", "HREF",   getlinkinfo, "href");
    
            (void) scProcessSGML( sgm, i);
    
            return 0;
    }
    
    
    
    この例では、解析される入力でリンクが検出されたときに、getanchor ルーチンおよび getlinkinfo ルーチンが呼び出されます。
    int
    getanchor( tag, attr, type, call_data, client_data)
            char * tag;
            char * attr;
            int    type;
            void * call_data;
            void * client_data;
    {
            printf("anchor-start(%s)\n", client_data);
    }
    
    int
    getlinkinfo( tag, attr, type, call_data, client_data)
            char * tag;
            char * attr;
            int    type;
            void * call_data;
            void * client_data;
    {
            printf( "%s=%s\n", client_data, call_data);
    }
    
    

    より厳格に処理する

    入力処理を解析フェーズと処理フェーズに分割したほうがより適切な場合は、構文解析プログラムが解析ツリーを返すようにして、後で処理することができます。

    次のようなツリーデータ構造が返されます。

    typedef struct snode_s {
            char         * s_tag;
            sattribute_t * s_attributes;
            int           numchildren;
            union {
                    struct snode_s * children;
                    sdata_t        * data;
            } body;
            struct snode_s * s_stackprev;
            struct snode_s * s_next;
            stag_t *         s_ref;
    } DOCtree_t;
    
    
    

    使用許諾契約書

    構文解析用エンジンは、sgmls プログラムの一部として James Clark によって書かれた SGML 参照構文解析です。当社では、このソフトウェアが C++ で書き直される前の、C の最終バージョンを原典として採用し、それを追加された入力ストリームおよびイベント処理に適応させています。

    次に、SGML User Group によるこのソフトウェアのライセンスに関する文書の抜粋を紹介します。全テキストは、ソースに格納されています。

          Standard Generalized Markup Language Users' Group (SGMLUG)
                             SGML Parser Materials
    
                                  1. License
    
    SGMLUG hereby grants to any user: (1) an irrevocable royalty-free,
    worldwide, non-exclusive license to use, execute, reproduce, display,
    perform and distribute copies of, and to prepare derivative works
    based upon these materials; and (2) the right to authorize others to
    do any of the foregoing.
    
    [...]
    
    (d) SGMLUG has no knowledge of any conditions that would impair its right
    to license the SGML Parser Materials.  Notwithstanding the foregoing,
    SGMLUG does not make any warranties or representations that the
    SGML Parser Materials are free of claims by third parties of patent,
    copyright infringement or the like, nor does SGMLUG assume any
    liability in respect of any such infringement of rights of third
    parties due to USER's operation under this license.