倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

ノードの変更と名前空間宣言 (2) -- 名前空間宣言に関するメソッド

今回は、要素に対して名前空間宣言を付加したり取り外したりするメソッドを見ていきます(一覧):

  • Element#addNamespace(String, String)
  • Element#remove(Namespace)
  • Namespace#detach()

Element#addNamespace(String, String) メソッド


addNamespace(String, String) メソッドは、要素に名前空間宣言を付加するメソッドです。 第0引数は「名前空間接頭辞」を、第1引数は「名前空間 URI」を指定します。

これはバグかと思いますが、以下のようなプログラムを実行すると、

Document doc = DocumentHelper.parseText("<e xmlns='ns1'/>");
Element e = doc.getRootElement();
        
parent.addNamespace("", "ns2");
//  Namespace ns2 = DocumentHelper.createNamespace("", "ns2");
//  parent.add(ns2);
//  としても同じ。

System.out.println(e.asXML());

次のように表示されます:

<e xmlns="ns1" xmlns="ns2"></e>

これは XML 文書としては整形式ではありません。 このようなコードは、要素の名前空間を変更したいときに書きそうですが、うまく働きません。 要素の名前空間を変更したい場合は、Element#setQName(QName) メソッドを用いましょう。

似たようなことが、名前空間接頭辞をもつ属性に関しても起こります。 例えば次のようなプログラムを実行すると、

Document doc = DocumentHelper.parseText("<e xmlns:p='ns1' p:att='value'/>"));
Element parent = doc.getRootElement();

parent.addNamespace("p", "ns2");
System.out.println(parent.asXML());

次のように表示されます:

<e xmlns:p="ns1" xmlns:p="ns2" xmlns:p="ns1" p:att="value"></e>

要素の場合よりも酷い結果になります(笑)。

Element#remove(Namespace) メソッド


remove(Namespace) メソッドは、要素から名前空間宣言を取り除くメソッドです。 このメソッドで注意が必要なのは、要素の名前空間を指定している名前空間宣言を取り除くときです。 以下のようなプログラムを実行すると、

Document doc = DocumentHelper.parseText("<e xmlns='ns'/>");
Element e = doc.getRootElement();
        
for(final Namespace ns: (List<Namespace>)e.declaredNamespaces())
    e.remove(ns);
        
System.out.println(e.asXML());
System.out.println(e.declaredNamespaces());

次のように表示されます:

<e xmlns="ns"/>
[]    <!-- 空リスト。 つまり名前空間宣言は付加されていません。 -->

名前空間宣言を取り除いても、文字列として出力すると名前空間宣言「xmlns="ns"」が付加されています。 ただし、オブジェクトの時点では名前空間宣言は取り除かれています。

Element#detach() メソッド


Node#detach() メソッドは、対象ノードを親要素から取り除くメソッドですが、名前空間宣言に関しては何もしません。 以下のようなプログラムを実行すると、

Document doc = DocumentHelper.parseText("<e xmlns='ns'/>");
Element e = doc.getRootElement();
        
for(final Namespace ns: (List<Namespace>)e.declaredNamespaces())
    ns.detach();
        
System.out.println(e.asXML());
System.out.println(e.declaredNamespaces());

次のように表示されます:

<e xmlns="ns"/>
[org.dom4j.Namespace@dc5 [Namespace: prefix  mapped to URI "ns"]]

表示される XML 文書は remove(Namespace) メソッドと同じですが、名前空間宣言は取り除かれていません。

そもそも、名前空間宣言 Namespace オブジェクトには親要素が設定されておらず、Namespace#getParent() を呼び出しても null が返されます。