- PR -

DOMのappendChildについて

1
投稿者投稿内容
KKK
会議室デビュー日: 2005/06/04
投稿数: 6
投稿日時: 2007-03-16 01:03
今、XMLマスタープロフェッショナル(アプリケーション)の勉強をしています。
DOMのappendChildの説明に
「追加する要素がすでにDOMツリーにある場合存在するノードを削除して追加する」
とあるのですが、いまいち理解できていません。
例えば内容がabcのcode要素をappendしたあとに
内容をdefにしたcodeを要素をappendしたら
結果は後者の内容が出力されると思ったら、
<code>abcdef</code>というような結果になってしまいました。

どなたか詳しい方がいたら、appendChildについて
教えてください。
スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2007-03-16 10:47
どうやって「内容をdefに」しましたか?
コードを提示すると問題解決も早いですよ。
KKK
会議室デビュー日: 2005/06/04
投稿数: 6
投稿日時: 2007-03-16 18:24
返答ありがとうございます。
元のxmlソール文書は以下のとおりです。
<?xml version="1.0" encoding="Shift_JIS" ?>
<product><name>冷蔵庫</name><price>150000</price></product>
これに対し以下のDOMを実行します。
////////////////////////////////////////////////
import org.w3c.dom.*;
import javax.xml.parsers.*;

public class aaa{
public static void main(String args[]){
try{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse("aaa.xml");
//ルート要素を取得する
Element root = doc.getDocumentElement();
//要素ノードを作成する
Node mNode = doc.createElement("name");
//要素ノードをDOMツリーへ追加
root.appendChild(mNode);

//表示用
String data = printTree(root);
System.out.println(data);

}catch(Exception e){
System.err.println(e.toString());
}
}

private static String printTree(Node node){
StringBuffer outbuff = new StringBuffer();
int type = node.getNodeType();
if(type == Node.ELEMENT_NODE){
//要素名を取得
String name = node.getNodeName();

//属性ノードを取得する
NamedNodeMap attrs = node.getAttributes();
int attr_cnt = attrs.getLength();
StringBuffer attrBuf = new StringBuffer();
for(int i=0; i< attr_cnt; i++){
Attr attr =(Attr)attrs.item(i);
attrBuf.append(" ");
attrBuf.append(attr.getName());
attrBuf.append("=\"");
attrBuf.append(attr.getValue());
attrBuf.append("\"");
}

//子ノードリストを取得する
NodeList children = node.getChildNodes();
//子ノードの数を取得する
int count = children.getLength();
if( count != 0){
outbuff.append("<" + name + attrBuf.toString() + ">");
for(int i=0; i<count; i++){
//子ノードを1つ取得する
Node child = children.item(i);
//再帰呼び出しを行う
outbuff.append(printTree(child));
}
outbuff.append("</" + name + ">");
}else{
outbuff.append("<" + name + attrBuf.toString() + "/>");
}
}else if(type == Node.TEXT_NODE){
String value = node.getNodeValue();
outbuff.append(value);
}
return outbuff.toString();
}
}
//////////////////////////////////////////////
このDOMを実行するとname要素が置き換わるイメージなのですが
どうぞよろしくお願いします。

スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2007-03-16 22:30
引用:

このDOMを実行するとname要素が置き換わるイメージなのですが



このコードの場合、追加している mNode は新規に作ったノードですから、DOMツリーの中には入ってません。「<name>冷蔵庫</name>」に相当するノードは、mNode とは別に DOM ツリーの中に存在します。ですので、appendChild() しても置き換わったりしませんです。

KKK
会議室デビュー日: 2005/06/04
投稿数: 6
投稿日時: 2007-03-16 23:51
スフレさんありがとうございます!!!
新規追加でも同じ要素名であれば置き換えてしまうものと
勘違いしていました。
大変たすかりました。

最初の質問と記述したコードがめちゃめちゃですね。すいません。
混乱しているようです。。
同じノードに対してtextノードを2回追加しているだけでした・・・
このような感じでしょうか。(特に質問ではございません)

//////////////////////////////////////////////////////////
//ルート要素を取得する
Element root = doc.getDocumentElement();
Node n2 = root.getFirstChild();
//要素ノードを作成する
Element a = doc.createElement("name");
//text作成
Node text = doc.createTextNode("test");
//text追加
a.appendChild(text);

//要素ノードをDOMツリーへ追加
root.appendChild(a);
//もう一回追加。
Node text2 = doc.createTextNode("test2");
a.appendChild(text2);
root.appendChild(a);
//////////////////////////////////////////////////////////////
大ベテラン
会議室デビュー日: 2006/06/28
投稿数: 116
投稿日時: 2007-03-18 16:10
くくりの文言が「(特に質問ではございません)」ですので解決していると思われますが気になる部分があるので……

まず、再投稿されたソースコードでは、パーサの使用方法は正しくなっていますが、スフレさんが指摘された内容が反映されていません。
新たな要素を追加するという動作が変更されていないため、修正されたコードでは以下のような出力になるはずです。
(実行して以下のようになることを確認しました。パーサの設定で本来改行は入りませんが長いため改行しています)
コード:
<?xml version="1.0" encoding="Shift_JIS" ?>
<product><name>冷蔵庫</name><price>150000</price>
<name>testtest2</name></product>


XMLは同一パスのノードが複数存在することを許します。
このため、同一名であっても新規であるノードをappendChildで追加しようとすると、
新たに同じ名前のノードを追加するという動作を行います。
上記から、置き換えたい場合は置き換えたいノードを取得し、テキストノードの値を変更するという手順を踏む必要があります。

あと、以下のコードで標準出力することが出来ます。
投稿前に確認が出来なかったものと推察します。これで多少確認が容易になるかもしれません。
コード:
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(new DOMSource(root) , new StreamResult(System.out));


以下はスレッドを読んでいて気になって試してみたことですが、
同一レベルのテキストノードにテキストノードを追加すると、ノードの値が追加されてゆきました。
実用性がないので小ねたにしかなり得ませんが。
KKK
会議室デビュー日: 2005/06/04
投稿数: 6
投稿日時: 2007-03-20 00:43
暁さん、コメントありがとうございます。

最後に投稿したのは、スフレさんに回答していただいたものを反映
したのではなく、最初の投稿で質問している内容をソースで表現
していたものでした・・・
わかりづらくてもうしわけございません。
まさに
『同一レベルのテキストノードにテキストノードを追加すると、ノードの値が追加されてゆきました。』
という動作のことです。

お手数をおかけしてしまう形になりましたが
『このため、同一名であっても新規であるノードをappendChildで追加しようとすると、 新たに同じ名前のノードを追加するという動作を行います。』
というコメントのおかげで非常に理解がクリアになりました。

ありがとうございました。

1

スキルアップ/キャリアアップ(JOB@IT)