「XMLの使い方」
2001.11.12 改定
2001.11.04 初稿
向の岡工業高校定時制
川井正司
・目的
XMLをスタンドアロンでデータベス検索として使うとき、「使い物になる」ための基本テクニックを紹介します。
それはなにかといえば「XSLへのパラメータのダイナミックな渡しかた」です。
これさえマスターすればXMLは自分のものです。
・能書
サンプルファイルをダウンロードして実際に動かしてみてください。
内容は次のような構成です。
0能書 XML作成ツール
環境が異なる場合表示されなかったり、エラーになることがあります。
特別なツールは必要ありません。
・XMLデータ形式
今回の元となるXMLデータ形式は、階層構造のない、表、テーブルの行を見た目に同じ行単位で表示する、属性値による表記法にしました。
・応用
紹介してある4,6の2つのテクニックの組み合わでデータ検索のほとんどは可能なはずです。
XMLのデータ検索は色々な方法が考えられますが、検索自体はDOMではおこなわず、XSL上で行うようにしたほうがよいと思います。
・いきさつ
本来XMLはネットワーク間相互のデータのやりとりの汎用性を確保することを目的として開発されました。しかし全ての場面においてPCがネットワークに接続され、データをホストコンピュータからロードする状況下で使用するわけではありません。
・データの更新を頻繁にする必要が無い。
・データの規模が小さい。
・データベースツールがない。
このような状況でも、IEさえあれば簡単なデータベース検索ができる、というのもXMLの1つの利用法だと思います。
この記事を書くきっかけになったのは、川崎商業の先生にキーホルダ型のUSBメモリスティックに入ったクラス名簿の「あいうえお検索」を見せつけられたからです。スゴイと思いました。こんなコンパクトなストレ−ジでデータ検索ができるなんて。持ち運びも簡単だしIEさえあれば閲覧できる。これはイイ。ということでさっそく取り掛かったのですが、どうしてもできない。「あいうえお検索」がどうやってもできない。むりやりデッチ上げたものは恥ずかしくてお見せできません。(同じ環境で見た目も同じには動きますが。)こんなはずは無い、もっとスッキリできるはずだ、と悩んだ結果が今回の記事です。
因みに川崎商業の先生のやりかたは、私とは全く異なる方法でした。
・XMLデータファイル作成ツール
変換ツール「
ExcelToXmld2.xls」
ファイルはダインロードしてください。
フォルダ「0能書 XMLデータファイル作成ツール」のなかにあります。
今回使用するXMLファイルの形式は、直感的にわかりやすいExcelの表、DBのテーブルを行単位でそのまま、属性としてxmlデータに変換したものにしました。SQLServerはxmlでのデータの返信にデフォルトでこの形式を採っています。
では、使用するデータファイルのXMLファイルはどのようにして作るのでしょうか。XMLファイルはテキストファイルですので、メモ帳さえあれば手入力で作成できます。HTMLファイルをメモ帳でつくるのと同じ方法です。しかし現実的ではありません。
そこでExcelの表をここで使うXMLファイルに変換するツール「ExcelToXmld2.xls」を作成しました。
ExcelToXmld2.xlsを開いてください。
「マクロを有効にする」をクリックすると、次のような画面が表示されます。
ダイアログはダブルクリックで再表示します。
操作は直感的にできると思います。遊んでみてください。
「リンクXSL」は生成されるXMLファイルの2行目にXSLファイルのリンク情報が挿入されます。
<?xml version="1.0" encoding="Shift_JIS"?>
<?xml-stylesheet type="text/xsl" href="z1.xsl"?>
出力されるXMLファイルの文字コードは"Shift_JIS"です。
注意
シートの内容の変更は「変換シート」上で行ってください。「設定変換シート」上で行ったシートの内容の変更は反映されません。
1.基礎データ表示
Data.xmlを開いて見てください。
今回使用するデータベースです。
(これに見覚えのあるかた、今回の利用方法は見覚えのある利用方法とは全く異なります。)
この形式を採用した理由は、直感的にわかりやすいからです。Excelの表、DBのテーブルが行単位でそのままxmlデータに変換された形をしています。またSQLServerはxmlでのデータの返信にデフォルトでこの形式を採っています。
XML1.xmlを開いて見てください。
XML1.xmlの中のデータが表形式で表示されます。
・ブラウザに画面表示させる元になっているコードの見方
ツールバーの「表示」-「ソース」を選択してクリックしてください
XML1.xmlファイルとData.xmlファイルの中身の違いは
<?xml-stylesheet type="text/xsl" href="XSL1.xsl"?>
の1行があるかないかだけです。
このようにxmlファイルからxslファイルを読み込んで、データ表示を形造ることができます。
XSL1.xslはxmlデータを表形式であらわすもっとも基本的な方法です。
直感的に理解できるとおもいます。表示項目を追加するなど、遊んでみてください。
XSL1.xsl
--------------------------------------------------
<?xml version="1.0" encoding="Shift_JIS" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<TABLE border="1">
<xsl:apply-templates select="ROOT/住所録"/>
</TABLE>
</xsl:template>
<xsl:template match="ROOT/住所録">
<TR>
<TD><xsl:value-of select="@No"/> </TD>
<TD><xsl:value-of select="@名前"/> </TD>
<TD><xsl:value-of select="@名前よみ"/> </TD>
</TR>
</xsl:template>
</xsl:stylesheet>
--------------------------------------------------
・<?xml version="1.0" encoding="Shift_JIS" ?>
XSLファイルを保存する場合、エンコードの種類の記述"Shift_JIS"と実際の保存形式が一致していなくてはなりません。
"Shift_JIS"の場合は文字コードの設定は「Shift_JIS」にします。
筆者の使っているWin2000のメモ帳には「Shift_JIS」の表示がありません、Win2000の場合「Shift_JIS」は「ANSI」と表示されます。
encoding属性は案外、落とし穴になります。ふだんあまり意識していません。
encoding属性を記述しない場合、デフォルト値として推奨の「UTF-8」または「UTF-16」と解釈されます。保存形式が一致していない場合、エラーになったり、何も表示されないことになります。
・WinMeの場合チョットやっかい
WinMeはShift_JISしかサポートしていません。したがってメモ帳もShift_JISのみの対応です。近頃のサンプルコードは推奨であるUTF-8やUTF-16のUniCodeで書かれたものが多くなっています。OSにWinMeを使用し、ブラウザにIE6.0を使用している場合、ブラザはUniCodeを受け付け正常に表示されます。ところがそのコードをテキストファイルに落とせないのです。「見てるだけ」になってしまいます。当然サンプルコードもメモ帳ではどうにもなりません。
保存形式の指定のしかたはメモ帳の場合、文字コードで設定します。
・メモ帳の「ファイル」-「名前を付けて保存」のダイアログボックス
・<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
この意味は解説書にまかせます。この場所にこの通りに記述してください。
ちなみにこの場所に次のように書かれたものは古い形式です。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
このような記述のサンプルコード、解説書は使用しないことをお奨めします。
・テーブル表示の基本型
<xsl:template match="/">
<TABLE border="1">
<xsl:apply-templates select="ROOT/住所録"/>
</TABLE>
</xsl:template>
<xsl:template match="ROOT/住所録">
<TR>
<TD><xsl:value-of select="@No"/> </TD>
<TD><xsl:value-of select="@名前"/> </TD>
<TD><xsl:value-of select="@名前よみ"/> </TD>
</TR>
</xsl:template>
・「<xsl:apply-templates select="ROOT/住所録"/>」
に
「 <TR>
<TD><xsl:value-of select="@No"/> </TD>
<TD><xsl:value-of select="@名前"/> </TD>
<TD><xsl:value-of select="@名前よみ"/> </TD>
</TR>」
が入れ子で入りテーブル表示されます。
<TD><xsl:value-of select="@**"/> </TD>
で表示したい項目を設定します。
項目を増やしたり、順番を変えたたり、同じものをおいたりしてみてください。
2.基礎 データ表示 ソート昇順
XML2.xmlを開いて見てください。
XML1.xmlとの違いはあいうえお順の名前でソートされていることです。
XSL1.xslの方法では元のデータをそのままの順で表示するだけです。
これでは実用になりません。目的の項目でソートするだけで実用になります。
XSL 2.xsl
--------------------------------------------------
<xsl:template match="/">
<TABLE border="1">
<xsl:apply-templates select="ROOT/住所録">
<xsl:sort select="@名前よみ" />
</xsl:apply-templates>
</TABLE>
</xsl:template>
ソートする項目を変えて、遊んでみてください。
ソート項目を表示しなくてもかまいません。
3.基礎 データ表示 ソート降順
XML3.xmlを開いて見てください。
ここでは番号でソートしています。
XML3.xslの次の部分でソートをかけます。
<xsl:sort select="@No" data-type="number" order="descending" />
XML3a.xmlを開いて見てください。
XML3a.xslの
<xsl:sort select="@No" order="descending" />
ように data-type="number" を指定しないと結果が目的通りになりません。
XMLデータは文字列なので数値として扱うにはその旨を指定する必要があります。
order="descending" は降順指定です。デフォルトは昇順です。
4.基本:文字列検索 「XSLへのパラメータのダイナミックな渡しかた」
HTM4.htmファイルを実行してください。
テキストボックスに”さ”と入力して検索ボタンをおしてください。
”さ”で始まる「名前よみ」のデータだけが抽出されます。
”さと”と入力して検索ボタンをおすと”さと”ではじまるデータだけが表示されます。
いきなり実用性No.1の先頭文字列指定によるデータ抽出です。
ここを見にきたあなたはたぶん幸せです。
XMLを利用するうえで、大変有効なテクニックを紹介しているからです。
知ってしまえば何のことはない当たり前のテクニックですが、私がこのワザにたどり着くには時間がかかりました。
それはなにかといえば「XSLへのパラメータのダイナミックな渡しかた」です。
これさえマスターすればXMLは自分のものです。
XSL4.xslファイル
-------------------------------------------------------
<xsl:variable name="strHead">さ</xsl:variable>
<xsl:template match="/">
<TABLE border="1">
<xsl:apply-templates select="ROOT/住所録[starts-with(string(@名前よみ),$strHead)]" />
</TABLE>
</xsl:template>
-------------------------------------------------------
<xsl:apply-templates select="ROOT/住所録[starts-with(string(@名前よみ),***)]" />
***に適当な文字列を置くことによりその文字列で始まる(@名前よみ)だけの要素が選択されます。
***を固定した文字列ではなくパラメータにするには、***に$ではじまる変数をおきます。
<xsl:apply-templates select="ROOT/住所録[starts-with(string(@名前よみ),$strHead)]" />
$ではじまる変数へのパラメータ値の代入は
<xsl:variable name="strHead">さ</xsl:variable>
でおこないます。ここでは$strHeadに文字列”さ”を代入しています。
しかしこれだけでは***に”さ”を直接記入したのとおなじことです。
$strHeadに必要に応じてその都度異なった値をダイナミックに代入するにはどうしたらよいのでしょうか。
htmファイル
-------------------------------------------------------
function disp(){
inputString=document.form1.inpStr.value;
var objXML=new ActiveXObject("Microsoft.XMLDOM");
objXML.async=false;
objXML.load("Data.xml");
var objXSL=new ActiveXObject("Microsoft.XMLDOM");
objXSL.async=false;
objXSL.load("XSL4.xsl");
var variableNode = objXSL.getElementsByTagName("xsl:variable");
variableNode.item(0).text = inputString;
outList.innerHTML=objXML.transformNode(objXSL);
}
-------------------------------------------------------
それをおこなっているのがhtmファイルのなかの次の部分です。
var variableNode = objStl.getElementsByTagName("xsl:variable");
variableNode.item(0).text = inputString;
まずXSLファイルを操作できるようにDOMとして取り込みます。
var objStl=new ActiveXObject("Microsoft.XMLDOM");
objStl.async=false;
objStl.load("XSL4.xsl");
XSLファイルもXMLファイルですので、XMLファイルの表記法で記述されています。
DOMとして取り込むことにより、ふつうのXMLファイルと同様の操作が可能となります。
var variableNode = objStl.getElementsByTagName("xsl:variable");
の式で要素名"xsl:variable"の要素、つまり<xsl:variable>、</xsl:variable>で挟まれた値を順次番号をふって全て取り込みます。<xsl:variable name="strHead">の属性部分は無視されます。パラメータstrHeadを目標として探しているのではないことに注意してください。ここでは<xsl:variable>、</xsl:variable>で挟まれた値は”さ”1つしかありませんので
variableNode.item(0).text
に”さ”が格納されます。
variableNode.item(0).text
に新たに値を代入することによって<xsl:variable>、</xsl:variable>で挟まれた値を変更することができます。この時点でパラメータ$strHeadに外部から値を代入したことになります。
ここでは
inputString=document.form1.inpStr.value;
variableNode.item(0).text = inputString;
の式でフォームのテキストボックスの入力値を代入して
xslファイル
-------------------------------------------------------
<xsl:variable name="strHead">さ</xsl:variable>
の”さ”をテキストボックスの入力値に変更しています。
この変更は取り込んだオブジェクトの中だけの変更ですので元のファイルはそのままです。
htmファイル
-------------------------------------------------------
outList.innerHTML=objDoc.transformNode(objStl);
の式でXMLDOMとして取り込んだ"Data.xml"ファイルobjDocを、同じく"XML4.xsl"ファイルをXMLDOMとして取り込み、”さ”の部分をテキストボックスの入力値で置き換えたobjStlでHTML形式に変換し、outListに格納します。
変換結果lstの表示は
<div id="outList"></div>
の部分でおこないます。
これでテキストボックスに入力した値を使って、XMLデータ検索が可能になります。
5.基本 セレクトメニュー1
HTM5.xmlファイルを実行してみてください。
セレクトメニューはデータベース閲覧に欠かせないインターフェースです。
データ検索をするのにメニューの項目を1つ1つ手書きで設定するのは、何のためのデータ検索なのでしょう。なんとも陳腐でシャレになりません。項目設定もデータ検索でおこなうというのがスジというものです。
それには理由があります。項目数が少ない場合は手入力でも問題は無いのですが、項目数が多くなると、全項目に目が届かなくなり、漏れが生じやすくなります。いちいち手入力するのも大変な作業になります。項目名を間違いますとその項目は検索されません。特に手入力で問題となるのが、全角と半角の英数字の区別がつきにくいことです。また項目に該当するデータが追加されるたびに閲覧ソフトを手直しすることになります、実用的ではありません。
ここでも基本アイテムとして「XSLへのパラメータのダイナミックな渡しかた」を使用します。
htmファイル
-----------------------------------------------------------------------------
objXML = new ActiveXObject("Microsoft.XMLDom");
objXML.async = false;
objXML.load("Data.xml");
var objNodeList = objXML.getElementsByTagName("住所録");
で Data.xmlファイルの"住所録"要素、全てをobjNodeListに格納します。
htmファイル
-----------------------------------------------------------------------------
var k=0;
for (var i = 0; i <
objNodeList.length; i++) {
strName = objNodeList(i).getAttribute("住所1");
var strSerch = "false";
for (var l = 0; l < strArray.length; l++) {
if (strArray[l]==strName){
strSerch = "true";
break;
}
}
if (strSerch=="false"){
strArray[k]=strName;
k=k+1;
}
}
strArray.sort();
のなかの
for (var i = 0; i < objNodeList.length; i++) {
strName = objNodeList(i).getAttribute("住所1");
で "住所録"要素から属性名"住所1"の属性値を順次とりだします。
それ以降の処理は、取り出した属性値で重複するものをハネ、配列strArray()にセレクトメニューで表示するリストを作成します。
strArray.sort();
で バラバラな表示項目の順序に一貫性をもたせます。
htmファイル
-----------------------------------------------------------------------------
var optionStr = "<option value =''>住所1</option>";
for (var l = 0; l < strArray.length; l++) {
optionStr += "<option value ='"+ strArray[l] + "'>"+strArray[l]+"</option>";
}
var selectStr = "<select name='select1' onChange='disp()'>" + optionStr +"</select>";
outSelect.innerHTML = selectStr;
で 配列strArray()の内容でフォーム:セレクトメニューのタグを作成し、表示できるようにます。
htmファイル
-----------------------------------------------------------------------------
<form name="form1">
<div id="outSelect"></div>
</form>
の位置でセレクトメニューを画面表示します。
function disp(){
で セレクトメニューで選択した項目によりXSLに選択項目を渡しその内容でデータを検索表示します。
方法は「4基本文字列検索」と同様です。説明はそちらを参照してください。
6.基本 セレクトメニュー2
こだわりメニュー
HTM6.htmファイルを実行してみてください。5.基本 セレクトメニュー1との違いはメニュー項目の並び順が異なるだけです。
5.の場合、並び順は表示される地名自信をソートしたものです。しかし住所録で使用する地名の並び順は、郵便番号順にしたいものです。このように項目表示の順序を、他の項目のソート順にしたい場合、どのようにしたらよいのでしょうか。
方法はいたって簡単です。
ソート、表示に使う項目を2次元配列としてとりこみます。取り込む順番に注意してください。ソートをかける項目が先です。
strArray[k]= new Array(strZip,strName);//***
これをソートし、表示項目だけを順次取り出して使います。
JavaScriptの多次元配列は、”入れ子”で実現します。一般の言語の方法とは異なるので注意してください。