デベロッパーズコーナー:DOMプログラミング講座 II(6)
2001年08月22日作成
第2回:サンプルで理解するDOMの利用
竹内 理
目次<全7ページ>
3.準備
6.サンプルコードでのDOMの利用
7.おわりに
|
サンプルコードでのDOMの利用
では、いよいよsetDataSet()メソッドのソースコードを見ていくことにしましょう。ここではソースコードを幾つかのパートに分けて説明していきます。
SetDataSet()メソッドの最初のところでは、メソッドで使用する変数を宣言しています。リスト2を見てください。DOMのメソッドを使用している箇所は赤で強調してあります。
//setDataSet():データセットを解析し、doInsert()を呼び出してレコードをDBに挿入する public void setDataSet() throws Exception { //(1)使用する変数を宣言する Exception e = new Exception(); String tableName = ""; String fieldNames = ""; String dataValues = ""; NodeList rowList = null; Element tableEl = null; Element rowEl = null; NamedNodeMap rowAttList = null; int i = 0,i2 = 0,i3 = 0; try{ |
リスト2.SetDataSet()メソッドで使用する変数の宣言
次に、Xercesの用意するメソッドを使用してDOMのDocumentオブジェクトを生成しています。リスト3を見てください。
//(2)Xercesのメソッドを使用してデータセットをパース後、Documentオブジェクトを生成 DOMParser xml = new DOMParser(); xml.parse("dataset.xml"); Document xdoc = xml.getDocument(); |
リスト3.Documentオブジェクトを生成する
2行目ではXercesのクラスであるDOMParserクラスのインスタンスxmlを生成しています。次の行ではXMLで記述されているdataset.xmlファイルを読み込んでいます。
4行目ではDOMParserクラスのgetDocument()メソッドを使って、読み込んだdataset.xmlをもとにDOMのDocumentオブジェクトを生成しています。リスト3の処理は、それぞれのパーサーに依存します。
次に、dataset.xml中のtable要素の数を取得し、その数の分だけループさせます。リスト4を見てください。
//(3)"table"要素のリストを取得し、その数だけループする NodeList tblList = xdoc.getElementsByTagName("table"); for(i=0;i< tblList.getLength();i++){ |
リスト4.Table要素のリストを取得し、その要素の数だけループする
2行目ではDocumentクラスのメソッドgetElementsByTagName()を使用しています。このメソッドは引数で指定した名前をもつ要素のリスト(NodeListクラスのインスタンス)を返します。ここではドキュメント中のtable要素のリストを返しています。
3行目ではNodeListクラスのメソッドgetLength()を使用してtable要素の数の分だけループすることを示しています。
dataset.xmlでは
<?xml version="1.0" encoding="UTF-8"?> <dataset> <table name="Person"> …… </table> </dataset> |
と記述されてるので、この場合はtblListには1つのtable要素が含まれていることになります。それでループ処理は一度のみ行います。
次に、それぞれのtable要素の属性からテーブル名を取得します。リスト5を見てください。
//(4)"table"要素をElementとして取得し、テーブル名を取得する。 tableEl = (Element)tblList.item(i); if(tableEl.getAttributeNode("name") != null){//テーブル名がセットされているかどうかをチェックする。 tableName = tableEl.getAttributeNode("name").getNodeValue(); }else{ System.out.println(e + ":XML2DB.createQueryString:no table name in datafile"); throw e; } |
リスト5. Table要素からテーブル名を取得する
2行目では、NodeListクラスのメソッドitem()を使ってElementクラスのインスタンスtableElを生成しています。item()メソッドはNodeListクラスのリストにおいて、引数で指定した位置のオブジェクトを返します。
3行目ではElementクラスのgetAttributeNode()メソッドを使って、table要素が"name"という名前の属性をもっているかどうかをチェックしています。getAttributeNode()メソッドは引数で指定された名前の属性を返すメソッドです。
4行目では、name属性が存在する場合にNodeクラスのgetNodeValue()メソッドを使用してその属性の値を取得しています。getNodeValue()メソッドは、そのNodeオブジェクトの名前を返します。同じ事をAttrクラスのgetValue()メソッドを用いても行えます。
dataset.xmlには
<table name="Person"> …… </table> |
と記述されているので、変数tablenameには"Person"という値が入ることになります。
次にtable要素の子要素であるrow要素の数を取得し、その数だけループさせます。リスト6を見てください。
//(5)"row"要素のリストを取得し、その数だけループする。 rowList = tableEl.getChildNodes(); for(i2=0;i2< rowList.getLength();i2++){ //(6)Elementオブジェクトかどうかをチェックする。 if(rowList.item(i2).getNodeType() == 1){ fieldNames = ""; dataValues = ""; |
リスト6.row要素のリストを取得し、その数だけループする
2行目ではNodeクラスのメソッドgetChildNodes()を使用してtable要素の子要素(row)のリストを取得しています。getChildNodes()は子要素のリストをNodeListクラスのインスタンスとして返します。
3行目ではNodeListクラスのメソッドgetLength()を使用して、row要素の数だけループする処理を行います。
5行目では、NodeクラスのgetNodeType()メソッドを使って、table要素の子要素であるそれぞれのオブジェクトがElementクラスのインスタンスかどうかをチェックしています。
dataset.xmlには
<row Name="'O.Wilde'" Age="67"/> <row Name="'C.Dickenz'" Age="78"/> |
と記述されていますからrowListには2つの要素が含まれていることに成りますので、2回ループすることになります。
次に、それぞれのrowList中の各row要素が持つ属性のリストを取得し、その属性の数だけループします。リスト7を見てください。
//(7)"row"要素の属性の数だけループする rowEl = (Element)rowList.item(i2); rowAttList = rowEl.getAttributes(); for(i3=0;i3< rowAttList.getLength();i3++){ |
リスト7. Row要素の属性の数だけループする
2行目では、NodeListクラスのitem()メソッドを使用して、rowList(table要素の子要素として取得したrow要素のリスト)から1つのElelementクラスのインスタンスrowEl(各々のrow要素を表す)を取り出しています。
3行目はNodeクラスのメソッドgetAttributesを使用してrowElからNamedNodeMapクラスのインスタンスrowAttListを取得します。rowAttListはrow要素がもつ属性のリストを表しています。
ElementクラスはNodeクラスを継承しているので、ElementクラスのインスタンスであるrowElでNodeクラスのメソッドを使用することができます。
4行目は、NamedNodeMapクラスのメソッドgetLengthを使用して属性リストに含まれる属性の数を取得し、その数だけループします。
dataset.xmlには
<row Name="'O.Wilde'" Age="67"/> <row Name="'C.Dickenz'" Age="78"/> |
と記述されていますから、属性リストrowAttListには"Name"、"Age"という二つの属性が含まれているので、1つのrow要素について2回ずつループすることになります。
次に、属性の名前、値から実際のSQL文を生成していきます。まずは、属性の名前から挿入する先のテーブルのフィールド名のリストを、属性の値から実際に挿入するデータのリストを生成します。以下の例を見てください。
INSERT INTO Person (Name,Age) VALUES ('O.Wild',67); 「Name,Age」の部分を属性の名前から生成 「'O.Wilde',67」の部分を属性の値から生成。 |
では、リスト8をご覧ください。
//(8)"row"要素の属性の「名前」でフィールド名のリストを、「値」で挿入する値のリストを作成 //ex)fieldnames:"Name,Age,..." // datavalues:"'E.Hemingway,67,...'" if(i3 == 0){ fieldNames = rowAttList.item(i3).getNodeName(); dataValues = rowAttList.item(i3).getNodeValue(); }else{ fieldNames = fieldNames + "," + rowAttList.item(i3).getNodeName(); dataValues = dataValues + "," + rowAttList.item(i3).getNodeValue(); } } |
リスト8. 属性の名前からフィールド名のリストを、値から挿入するデータのリストを生成する
変数fieldNamesはフィールド名のリスト、dataValuesは挿入するデータのリストを表しています。If文は、ループの一回目にはそれぞれの文字列にカンマを入れないための処理です。
5,8行目ではNodeクラスのメソッドgetNodeName()を使用して、row要素のそれぞれの属性の名前を取得し、それをfieldNamesに付加してフィールド名のリストを生成しています。
6,9行目ではNodeクラスのメソッドgetNodeValue()を使用して挿入するデータのリストを生成しています。
dataset.xmlのtable要素の子供の一番目のrow要素は
<row Name="'O.Wilde'" Age="67"/> |
と記述されているので、この場合
fieldNames:Name,Age dataValues:'O.Wilde',67 |
となります。
次にここで生成した二つの文字列を用いて、実際のINSERT文を生成します。最後に、doInsert()メソッドを呼び出して、INSERT文を実行します。リスト9をご覧ください。
//(9)fieldnames,datavalues,tableNameを使ってSQL文を生成 sqlstr = "insert into " + tableName + "(" + fieldNames + ")"; sqlstr = sqlstr + "VALUES(" + dataValues + ");"; //(10)クエリの実行 doInsert(); |
リスト9.
2、3行目でSQLのINSERT文を生成します。dataset.xmlの2つのrow要素からは
insert into Person (Name,Age) values ('O.Wilde',67); insert into Person (Name,Age) values ('C.Dickenz',78); |
という文字列が生成されます。生成した文字列はXML2DBクラスのプライベート変数sqlstrに代入します。
5行目ではdoInsert()メソッドを呼び出し、sqlstrに代入されているSQL文を実行します。このdoInsert()メソッドはデータセットファイルに含まれているrow要素の数だけ実行されます。dataset.xmlの場合は2回呼び出されるわけです。doInsert()メソッドはDOMを使用しないので詳しい説明はしませんが、興味のある方はソースコードをご覧ください。
この実行結果は前述したとおりですが、ここでもう一度実行後のテーブルを見ておきましょう。
図7.データ挿入後のPersonテーブル
確かにdataset.xmlファイルに記述されていたO.WildeとC.Dickenzのデータが追加されています。