第35回 要素や属性の名前に使用できる文字の規定 Page 3

川俣 晶
株式会社ピーデー
2005/7/6

付録:リストの生成使い捨てプログラム

 今回はいくつかの文字の表を用意したが、これはXML勧告本文の文字の表からawkによって機械的に生成したものである。これは、直接は関係ない別の記事、「XMLデータベース開発方法論 第1回 序章、データ処理技法の地政学」を補足するawkの利用例という位置付けになっている。使い捨てデータ処理というものが実感できない読者もいると思うので、実際に利用例を示しておこう、ということである。

ニーズの突発

 そもそも、なぜ文字表を作ろうと思ったのかといえば、コードのリストでは読者が具体的な文字のイメージを思い浮かべることができないためである。フォントがあれば、という条件は付くにせよ、文字のリストがあれば分かりやすさは格段に上がる。そのようなアイデアを書いている途中に突発的に思い付いた。しかし、これはエディタの置換機能などで実現することは難しい。例えば「#x0050」を「P」に置き換えればHTML文書として文字を表示できるが、[… - …」という範囲指定はエディタの置換機能程度では対処できない。しかし、このような作業は1回しか発生しないことが明らかなので、本格的なプログラムを作ることは割に合わない。そこで、使い捨てプログラムをササッと作って処理することに決めた。このような用途に適するプログラム言語はいくつもあるが、上記記事の具体例とするために、あえてawkを選んだ。

要件の定義

 厳密な要件の定義などを行う必要はない。大体のイメージとして、以下のような入力に対して、その下のような出力を行うものを作ろうと思った。1回限りしか使わないので、結果さえよければ途中経過はラフに扱って問題はない。入力書式の定義なども存在しない。

入力

[123]    Sample    ::=    [#x0041-#x0043] | #x0050

 生成規則の1つにつき、上記のような書式のテキストファイルを1つ作成した。

出力

<html>
<head>
<title>[123]    Sample    </title>
</head>
<body>
<h1>[123]    Sample    </h1>
<p>&#x0041; &#x0042; &#x0043; &#x0050;</p>
</body>

 出力は完全に厳密なHTML文書にはしていない。これは、後から編集者やデザイナーが手を入れることを前提に、必要最低限の情報だけを生成しているためである。

 ちなみに、使用したawk処理系であるgawk win32はシフトJISしか扱うことはできないが、文字参照として扱うことでリストにあるすべての文字を正しく出力結果に収めることができている。とはいえ、実用上awkにはすでに古くなったと思わせる点がいくつかあるのは事実である。

実装

 要求を実現するために、試行錯誤しつつ徐々にプログラムを組み上げていった。複数のテキストファイルを一気に処理するWindowsのバッチ(1行)と、処理を行う本体となるawkプログラム(90行)を作成した。90行を使い捨てるとは無駄が多いと思うかもしれないが、入力テキストの解析部分さえできれば後はさほど複雑なものではない。むしろ、これらのコードをすべて手動で書き換えたとすれば、それに要した時間は2倍や3倍では済まないことに注目したい。おそらく、10倍の時間を費やしても終わらないだろう。しかも、手動書き換えはつまらない誤りを容易に混入させるが、このような膨大な文字表に含まれる誤りは見つけ出すのが極めて難しい。

 なお、これはawkのサンプルソースとしては最善ではない可能性がある。筆者はawkが好きだが、優れた使い手というわけではない。

バッチファイル:genall.cmd

for %%i in (*.txt) do gawk -f genlist001.awk %%i >%%~ni.html

本体:genlist001.awk

BEGIN {
    RS="|"
}
END {
    if( lineCount > 0 )
    {
        outputLine()
    }
    print "</body>"
}
{
    if( match($0,"::=") )
    {
        title = substr($0,1,RSTART-1)
        print "<html>"
        print "<head>"
        print "<title>" title "</title>"
        print "</head>"
        print "<body>"
        print "<h1>" title "</h1>"
    }

    p = match($0,"\\[#x")
    if( p != 0 )
    {
        froms = substr($0,p+3,4)
        tos = substr($0,p+10,4)
        from = hexString2int(froms)
        to = hexString2int(tos)
        for( i=from; i<=to; i++ )
        {
            output(i);
        }
    }
    else
    {   
        p = match($0,"#x")
        if( p != 0 )
        {
            froms = substr($0,p+2,4)
            from = hexString2int(froms)
            output(from);
        }
    }
}

function output(number)
{
    line = line sprintf( "&#x%04x; ", number );
    lineCount++;
    if( lineCount >= 16 )
    {
        outputLine()
    }
}

function outputLine()
{
    print "<p>" line "</p>"
    line =""
    lineCount = 0
}

function hexString2int( hex )
{
    sum = 0
    for( c=1; c<=length(hex); c++ )
    {
        sum = sum*16 + hexDigit2int( substr(hex,c,1) )
    }
    return sum
}

function hexDigit2int( hex )
{
    if( hex >= "0" && hex <= "9" ) return hex + 0;
    if( hex == "A" || hex == "a" ) return 10;
    if( hex == "B" || hex == "b" ) return 11;
    if( hex == "C" || hex == "c" ) return 12;
    if( hex == "D" || hex == "d" ) return 13;
    if( hex == "E" || hex == "e" ) return 14;
    if( hex == "F" || hex == "f" ) return 15;
    print hex "は16進数の文字ではありません。"
    exit
}

結果

 awkを使用した結果、手間に対して得られた成果は、大黒字となった。手動書き換えよりも楽ができたのはもとより、本格的なプログラム言語よりも少ない手間で処理が実現されたことは留意する価値があるだろう。また作成のために要求される技術的な知識も、本格プログラム言語より少ない。

 そして、このawkプログラムを使うことは2度とないだろう。使い捨てのデータ処理ということである。しかし、使い捨てても、大黒字という結果に変わりはない。(次回に続く)

3/3

 Index
やさしく読む「XML 1.0勧告」 第35回
要素や属性の名前に使用できる文字の規定
  Page 1
・文字クラスについて
・名前とトークン再び
・文字クラス(Character Classes)
  Page 2
・文字クラスのルール
Page 3
・付録:リストの生成使い捨てプログラム


連載 やさしく読む「XML 1.0勧告」


XML & SOA フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日月間