目次へ

7. DOMと名前空間

7.1. 名前空間とDOM

DOMでは、Level2より名前空間に対応しています。以下のような操作を行うことが可能になりました。

  • 特定の名前空間に属する要素の内容を取得する
  • 特定の名前空間に属する属性ノードを作成する  。。。など 

ただし、名前空間に対応したメソッドには、少し「くせ」があります。以下、DOMで名前空間を指定したXML文書を扱う方法と注意点について、説明します。

7.2. XMLを読む

名前空間対応に伴い、DOM Level 2では、名前空間URIとローカル名を指定してノードを取得するメソッドが追加されました。

例えば、Elementには要素のリストを取得するgetElementsByTagName(String name)というメソッドが用意されています。これは、引数に指定されたタグ名の要素を取得するメソッドです。対して、名前空間を指定して要素を取得する getElementsByTagNameNS(String namespaceURI,String localName)が追加されました。引数には、ネームスペースURIとローカル名を指定します。その他にも、Elementノードには、以下のメソッドが提供されています。

メソッド 内容
public NodeList getElementsByTagNameNS(String namespaceURI,
String localName)

所定のローカル名およびネームスペース URI とともに、すべての Elements の NodeList を返します。返される順番は、この Element ツリーの先行順 (preorder traversal) で検出された順番になります。

public String getAttributeNS(String namespaceURI,
String localName)

ローカル名とネームスペース URI を指定して属性値を取得します。

public Attr getAttributeNodeNS(String namespaceURI,
String localName)

ローカル名とネームスペース URI を指定して Attr ノードを取得します。

public boolean hasAttributeNS(String namespaceURI,
String localName)

この要素上に所定のローカル名とネームスペース URI を持つ属性が指定された場合、またはその属性にデフォルト値がある場合は true、それ以外の場合は false

例を挙げて、説明しましょう。以下のようなXML文書があったとします。

  <?xml version="1.0" encoding="UTF-8"?>
  <html xmlns="http://www.w3.org/1999/xhtml">
  <body>
  <form action="/sample2/productInput.jsp" method="post">
      <table>
      <tr><td>商品名</td><td><input type="text" name="name" /></td></tr>
      <tr><td>メーカ名</td><td><input type="text" name="maker"/></td><f/tr> </table> 
      <input type="submit" value="登録" />
  </form>

 <html:form action="/sample/productInput.do" method="post" 
    xmlns:html="http://jakarta.apache.org/struts/tags-html-1.0">
 
     <table>
     <tr><td>商品名</td><td><html:text property="name" /></td></tr>
     <tr><td>メーカ名</td><td><html:text property="maker"/></td></tr> 
   </table> 
     <html:submit value="登録" />
 </html:form>
 
 </body>
 </html>

上のXML文書には、名前空間URIが2つ登場します。まず、html要素で宣言している"http://www.w3.org/1999/xhtml"です。これは、ルート要素の、xmlns属性の値として宣言しているので、名前空間接頭辞を持たないすべての要素(body,table,tr...)はこの名前空間に属しています。4行目のformも、"http://www.w3.org/1999/xhtml"で表される名前空間に属します。

 2つ目は、12行目で宣言している"http://jakarta.apache.org/struts/tags-html-1.0"です。この名前空間URIは"xmlns:html"属性の値として宣言しています。これは、html接頭辞がついている要素・属性は、この名前空間に属すということを表しています。この文書では、11行目のform要素、および15,16行目のtext要素が"http://jakarta.apache.org/struts/tags-html-1.0"名前空間に属します。

このXML文書を読み込み、値を取得するプログラムを以下のように作成しました。

 1  import java.io.*;
 2  import org.w3c.dom.Document;
 3  import org.w3c.dom.DocumentType;
 4  import org.w3c.dom.Element;
 5  import org.w3c.dom.Node;
 6  import org.w3c.dom.NodeList;
 7
 8  import javax.xml.parsers.*;
 9
10  public class NamespaceSample{
11
12  public static void main(String args[]) throws Exception{
13
14          System.out.println("filename is "+args[0]);
15          DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
16          factory.setNamespaceAware(true);
17          DocumentBuilder builder=factory.newDocumentBuilder();
18          Document document= builder .parse(new File(args[0]));
19
20          Element root=document.getDocumentElement();
21
22          NodeList formWithPrefix
23              =root.getElementsByTagNameNS("http://jakarta.apache.org/struts/tags-html-1.0","form");
24          System.out.println("form elemenet (NS = http://jakarta.apache.org/struts/tags-html-1.0): num="+formWithPrefix.getLength());
25          for(int i=0;i<formWithPrefix.getLength();i++){
26              Element element=(Element)formWithPrefix.item(i);
27              System.out.println("action attribute value is "+element.getAttributeNS(null,"action"));
28          }
29
30          NodeList formInDefaultSpace
31              =root.getElementsByTagNameNS("http://www.w3.org/1999/xhtml","form");
32          System.out.println("form elemenet (NS=http://www.w3.org/1999/xhtml): num="+formInDefaultSpace.getLength());
33
34          for(int i=0;i<formInDefaultSpace.getLength();i++){
35              Element element=(Element)formInDefaultSpace.item(i);
36              System.out.println("action attribute value is "+element.getAttributeNS(null,"action"));
37          }
38
39      }    
40  }

名前空間を扱うには、パーサの設定を変更する必要があります。デフォルトでは、Java 1.4 付随のXMLパーサは名前空間を認識しません。16行目で、DocumentBuilderFactoryのsetNamespaceAware()メソッドを使用して、名前空間を認識するよう設定します。

22-23行目では、URI "http://jakarta.apache.org/struts/tags-html-1.0"で表される名前空間に属するform要素のNodeListを取得しています。24行目では、取得したNodeListの長さを表示しています。"http://jakarta.apache.org/struts/tags-html-1.0"に属しているform要素は、ひとつだけです。27行目では、action属性の値を取得し、表示しています。属性ノードの取得のために、getAttributeNSメソッドを使用しています。このメソッドは、getAttributeメソッドを名前空間に対応させたもので、引数に名前空間URIと属性のローカル名を指定します。

属性の名前空間について、復習しましょう。

  • 属性に名前空間接頭辞がついている場合、その属性は接頭辞が表す名前空間に属する
  • 属性に名前空間接頭辞がついていない場合、その属性は、要素毎のローカルな名前空間に属する。URIで表される名前空間に属さない。

このaction属性は名前空間接頭辞を持ちません。よって、要素毎の区画に属することになります。このような場合、名前空間URIには null を指定します。27行目でgetAttributeNSメソッドでも、名前空間URIとしてnull を指定しています。つまり、名前空間に対応した属性操作メソッドで名前空間URIにnullを指定した場合は、名前空間接頭辞を持たない属性を指定していることになります。27行目では、action属性の値を出力していますが、その値は、"/sample2/productInput.jsp"になるはずです。

 同様に、30-31行目では"http://www.w3.org/1999/xhtml"名前空間に属するform要素を取得しています。これも、デフォルト名前空間"http://www.w3.org/1999/xhtml"に属するform要素はひとつだけです。また、36行目で、getAttributeNSメソッドを用いてaction属性の値を取得しています。このaction属性も名前空間接頭辞を持ちません。名前空間URIにnullを指定しています。actionの値が"/sample2/productInput.jsp"であることを確認できます。上記プログラムを実行すると、以下のように出力されます。

$  java NameSpaceSample sample.xml 
filename is sample.xml
form elemenet (NS = http://jakarta.apache.org/struts/tags-html-1.0): num=1
action attribute value is /sample/productInput.do
form elemenet (NS=http://www.w3.org/1999/xhtml): num=1
action attribute value is /sample2/productInput.jsp

getElementsByTagNSメソッドでは、「全ての名前空間」「全てのローカル名」という意味で、"*"を引数に設定することができます。例えば、以下のプログラムです。

 1 import java.io.*;
 2 import org.w3c.dom.Document;
 3 import org.w3c.dom.DocumentType;
 4 import org.w3c.dom.Element;
 5 import org.w3c.dom.Node;
 6 import org.w3c.dom.NodeList;
 7
 8 import javax.xml.parsers.*;
 9
10 public class NamespaceSample2{
11
12     public static void main(String args[]) throws Exception{
13
…
20         Element root=document.getDocumentElement();
21
22         NodeList form
23             =root.getElementsByTagNameNS("*","form");
24         System.out.println("form elemenet : num="+form.getLength());
25         for(int i=0;i<form.getLength();i++){
26             Element element=(Element)form.item(i);
27             System.out.println("action attribute value is "+element.getAttributeNS(null,"action"));
28         }
29
30     } 
31 }

上のプログラムを実行すると、以下のようになります。

$ java NamespaceSample2 sample.xml 
filename is sample.xml
form elemenet : num=2
action attribute value is /sample2/productInput.jsp
action attribute value is /sample/productInput.do

それでは、名前文字列URIとしてnullを指定したら、どうなるでしょう。getElementsByTagNameNSメソッドで名前空間URIとしてnullを指定すると、"*"を指定したのと同じ結果が得られます。つまり、ローカル名が引数で与えられたタグ名と一致する全ての要素ノードを返します。

(実習課題1)

与えられたXMLを解析するプログラムを作成しなさい。

  • 名前空間URI "http://schemas.xmlsoap.org/soap/envelope/"、ローカル名"Body"で表される要素の内容を取り出すコンソールプログラム。
  • 名前空間URI "http://schemas.xmlsoap.org/soap/envelope/"、ローカル名"Body"で表される要素は、文書中に必ず出現するものとする。Body要素はルート要素ではなく、2回以上出現しないものとする。
  • 例えば、以下のXML文書があったとします。
    <?xml version="1.0" encoding="UTF-8"?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Body>
    <m:customer xmlns:m="http://www.techscore.com/customerMessage/">
    <m:name>山田太郎</m:name>
    <m:age>31</m:age>
    </m:customer>
    </soapenv:Body>
    </soapenv:Envelope>
    
    出力結果は以下のようになります。
    1番目の要素: 名前空間URI:http://www.techscore.com/customerMessage/ ローカル名:customer 
    2番目の要素: 名前空間URI:http://www.techscore.com/customerMessage/ ローカル名:name 内容:山田太郎 
    3番目の要素; 名前空間URI:http://www.techscore.com/customerMessage/ ローカル名:age 内容:32
  • (ヒント)名前空間URIを取得するには、NodeのgetNamespaceURIメソッドを使用します。
  • (ヒント)ローカル名を取得するには、NodeのgetLocalNameメソッドを使用します。
  • bodyの内容には、要素とテキストのみが存在し、名前空間宣言以外の属性やコメント、エンティティは存在しないものとする。
  • body、およびその子供要素は、要素とテキストが混在するような内容を持たないものとする。つまり、body、およびその子供要素の内容は、複数の要素のみ、あるいは、テキストのみからなる。

解答例はこちら

↑このページの先頭へ

こちらもチェック!

PR
  • XMLDB.jp
  • シナジーマーケティング研究開発グループブログ