- PR -

J2SE1.4でXML文書を保存/読込するとノード数が変わる

投稿者投稿内容
MASATO
常連さん
会議室デビュー日: 2002/06/25
投稿数: 22
投稿日時: 2002-10-26 14:13
J2SE SDKのXMLに関する機能を使って以下のようなプログラムを書いたのですが、
XML文書として保存したときと、保存した後、再度読込んだときのノード数が異なっています。

開発環境 J2SE 1.4.0_01 + WindowsXP

プログラム(XMLTest.java)
コード:

import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;
import java.io.*;

class XMLTest
{
public static void main(String[] args)
{
File datafile = new File("test.xml");
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = null;
try {
doc = builder.parse(datafile);
}catch (IOException e){
doc = builder.newDocument();
}
Node root = doc.getFirstChild();
if (root == null){
root = doc.appendChild(doc.createElement("root"));
}
System.out.println("1.nodelist length = " + root.getChildNodes().getLength());
root.appendChild(doc.createElement("sub"));
System.out.println("2.nodelist length = " + root.getChildNodes().getLength());
FileOutputStream writer = new FileOutputStream(datafile);
((org.apache.crimson.tree.XmlDocument)doc).write(writer);
writer.close();
}catch (Exception e){
e.printStackTrace();
}
}
}



実行結果
コード:

% java XMLTest
1.nodelist length = 0
2.nodelist length = 1
% java XMLTest
1.nodelist length = 3
2.nodelist length = 4



二回目にXMLTestを実行した結果は、
1.nodelist length = 1
2.nodelist length = 2
となって欲しいです。

参考までに、XMLTest二回実行後のtest.xmlの中身は
以下のようになっております。
不要な空白や改行が多数ありました。
コード:

<?xml version="1.0" encoding="UTF-8"?>

<root>

<sub />

<sub />
</root>




明示的に作成した数以上のノードが作られるのは困るのですが、
どなたか解決方法をご存知ないでしょうか。


[ メッセージ編集済み 編集者: MASATO 編集日時 2002-10-26 14:25 ]
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2002-10-27 00:05
詳細を調べてませんが、このプログラムは実行する度に、
root.appendChild(doc.createElement("sub"));
を実行しますよね…。
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2002-10-27 00:13
それと、Documentの直下にElementをappendされているようですが、
DocumentElementを飛ばしてしまわないほうが良いのではないでしょうか?
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2002-10-27 01:01
で、1つの答え。(できるだけMASATOさんのプログラムを尊重してという意味で、最適ではないかもしれませんが。)
((org.apache.crimson.tree.XmlDocument)doc).write(writer);
 を
writer.write(doc.getDocumentElement().toString().getBytes());
 にしてみてはどうでしょうか?(乱暴ですが。)

私なら,
Node root = doc.getFirstChild();

Node root = doc.getDocumentElement();
にしておきますが。
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2002-10-27 01:04
あっ、でもこれだとXML宣言の部分が出力されないか…。
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2002-10-27 01:17
結論、ちゃんと transformを使った例を示します。
crimsonのパッケージを裸で使うより、
javax.xml.transform関連のパッケージを使用したほうが
良いと思います。

-------------------------------------------------------------
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import java.io.*;

class XMLTest
{
public static void main(String[] args)
{
File datafile = new File("test.xml");
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = null;
try {
doc = builder.parse(datafile);
}catch (IOException e){
doc = builder.newDocument();
}
Node root = doc.getDocumentElement();
if (root == null){
root = doc.appendChild(doc.createElement("root"));
}
System.out.println("1.nodelist length = " + root.getChildNodes().getLength());
root.appendChild(doc.createElement("sub"));
System.out.println("2.nodelist length = " + root.getChildNodes().getLength());
FileOutputStream writer = new FileOutputStream(datafile);
TransformerFactory tFactory = TransformerFactory.newInstance();
Source source = new DOMSource(doc);
Result target = new StreamResult(writer);
if (source != null)
try {
tFactory.newTransformer().
transform(source, target);
} catch (TransformerConfigurationException ex) {
ex.printStackTrace();
} catch (TransformerException ex) {
ex.printStackTrace();
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
writer.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
MASATO
常連さん
会議室デビュー日: 2002/06/25
投稿数: 22
投稿日時: 2002-10-27 02:48
Kissingerさん、どうもありがとうございました。
目的通りの動作を達成することができました。

コード:
import java.io.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;
import org.xml.sax.*;

class XMLTest
{
  public static void main(String[] args)
  {
    File datafile = new File("test.xml");
    try {
      // 読み込み
      Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
      Transformer transformer = TransformerFactory.newInstance().newTransformer();
      StreamSource source = new StreamSource(datafile);
      DOMResult domResult = new DOMResult(doc);
      try {
        transformer.transform(source, domResult);
      }catch (Exception ex){
      }
      Node root = doc.getFirstChild();
      if (root == null){
        root = doc.appendChild(doc.createElement("root"));
      }
      // ノード一つ追加
      System.out.println("1.nodelist length = " + root.getChildNodes().getLength());
      root.appendChild(doc.createElement("sub"));
      System.out.println("2.nodelist length = " + root.getChildNodes().getLength());
      // 保存
      Source domSource = new DOMSource(doc);
      StreamResult target = new StreamResult(datafile);
      transformer.transform(domSource, target);
    }catch (Exception e){
      e.printStackTrace();
    }
  }
}



以上のプログラムを二回実行すると、
以下のようなxmlファイルが作成されました。

コード:
<?xml version="1.0" encoding="UTF-8"?>
<root><sub/><sub/></root>



余計な空白や改行が何も無い(あたりまえと言えばあたりまえですが)
xmlファイルとなって、
書き込み時と読込み時にノード数が変わることもなくなりました。
どうもありがとうございました。

また、org.apache.crimson.tree.XmlDocumentを使っていたのは、
他に保存する方法がわからなかったからです。
javax.xml.transformを使った例を提示して頂けましたので、
こちらを参考に作り直しました。

最後に、
今まではjavax.xml.parsersを用いて記述していた読込み部分も、
javax.xml.transformを用いて書いてみました。
DOMResultのコンストラクタの引数がNodeですので、
Node root = doc.getFirstChild()としてあります。

XMLファイルを読込むための方法として、
javax.xml.parsersを用いる方法と、
javax.xml.transformを用いる方法があり、
どちらも読込めることを確認しましたが、
どちらを使うのが適当でしょうか?
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2002-10-27 03:12
> XMLファイルを読込むための方法として、
> javax.xml.parsersを用いる方法と、
> javax.xml.transformを用いる方法があり、
> どちらも読込めることを確認しましたが、
> どちらを使うのが適当でしょうか?
私は簡単の為にはparsersの方を使ってますが、XSLTの様に柔軟な使い方をよりスマートにやりたいときはtransform系のResult, Sourceの組み合わせを使うでしょうね。

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