JavaとDOMによるXML文書の操作
Contents

  1. メモリ上にXML文書を作成する
    1. XML文書(白紙)を作成する
    2. ルート要素を作る
    3. 子要素を追加する
    4. 属性を追加する
    5. ここまでのコードをまとめると
    6. 各種ノードを作成するメソッド
  2. メモリ上のXML文書の内容を取得する
    1. ノードツリーを辿って目的のノード見つける
    2. 要素名から目的のノード見つける
    3. 属性ノードを取得する
    4. ノードの各値を取得する
    5. ノードタイプ一覧
    6. 属性ノード
    7. プログラム例
  3. メモリ上のXML文書の内容を変更する
    1. 要素を追加する
    2. 要素の値を変更する
    3. 要素を置き換える
    4. 要素を削除する
    5. 属性の値を変更する
    6. 属性を変更(なければ追加)する
    7. 属性を追加する・置き換える
    8. 属性を削除する
  4. メモリ上のXML文書をファイルに出力する
  5. ファイルからXML文書をメモリ上に読み込む
  6. WebからXML文書をメモリ上に読み込む

  1. メモリ上にXML文書を作成する

    1. XML文書(白紙)を作成する

       まず、

      Document document = new XMLDocument();

      のようにして白紙のXML文書を作成します。

    2. ルート要素を作る

       次に、上記で作成した白紙のXML文書に

      <items>
      </items>

      というルート要素(items)を作成するには

      Element rootElement = document.createElement("items");
      document.appendChild(rootElement);

      のようにします。

    3. 子要素を追加する

       さらに、子要素を追加して

      <items>
      <item>VALUE</item>
      </items>

      のようにするには、まず、

      Element element = document.createElement("item");
      rootElement.appendChild(element);

      として、子要素(item)を追加します。
      この状態ではまだ

      <items>
      <item></item>
      </items>

      または

      <items>
      <item />
      </items>

      のような空要素です。
      これに

      Text textContents = document.createTextNode("VALUE");
      element.appendChild(textContents);

      とすることでテキスト(VALUE)を追加します。
      これで

      <items>
      <item>VALUE</item>
      </items>

      となりました。

      ここでは、要素の追加に appendChild() というメソッドを使用しましたが、任意に位置に要素を追加する場合は、

      Node insertChild(Node newChild, Node refChild) throws DOMException;

      というメソッドを使います。

    4. 属性を追加する

       また、属性(id)を追加して

      <items>
      <item id="ID">VALUE</item>
      </items>

      のようにするには

      Attribute attribute = document.createAttribute("id");
      attribute.setValue("ID");
      element.setAttributeNode(attribute);

      とします。
      この一連の操作を一度で行う

      element.setAttribute("id", "ID");

      という方法もあります。

    5. 要素の複製を作成して要素を追加する

       すでに同形式の要素がある場合は、次のようにして、要素の複製を作成して要素を追加することもできます。

      Element cloneElement = element.clone(true);
      cloneElement.getChildNodes().item(0).setNodeValue("VALUE2");
      cloneElement.setAttribute("id", "ID2");
      rootElement.appendChild(cloneElement);

    6. ここまでのコードをまとめると

      import org.w3c.dom.*;

      class Foo {
      public void bar() {
      try {
      // XML文書を作成する
      Document document = new XMLDocument();

      // ルート要素を追加する
      Element rootElement = document.createElement("items");
      document.appendChild(rootElement);

      // 子要素を追加する
      Element element = document.createElement("item");
      rootElement.appendChild(element);

      // 値を設定する
      Text textContents = document.createTextNode("VALUE");
      element.appendChild(textContents);

      // 属性を追加する
      element.setAttribute("id", "ID");

      } catch (Exception e) {
      System.out.println(e.getMessage());
      e.printStackTrace();
      }
      }
      }

      上記のコードによってメモリ上に

      <items>
      <item id="ID">VALUE</item>
      </items>

      というXML文書が作成されます。

    7. 各種ノードを作成するメソッド

      1. 属性を作成する。

        Attr attribute = document.createAttribute("AttributeName");

      2. CDATASectionを作成する。

        CDATASection cdataSection = document.createCDATASection("DataString");

      3. Commentを作成する。

        Comment comment = document.createComment("CommentString");

      4. 部分文書(空)を作成する。

        DocumentFragment documentFragment = document.createDocumentFragment();

      5. 要素を作成する。

        Elenment element = document.createElement("ElementName");

      6. 実体参照を作成する。

        EntityReference entityReference = document.createEntityReference("EntityReferenceName");

      7. 処理命令を作成する。

        ProcessingInstruction processingInstruction = document.createProcessingInstruction("ProcessingInstructionName", "DataString");

      8. テキストを作成する。

        Text text = document.createTextNode("TextString");


  2. メモリ上のXML文書の内容を取得する

    1. ノードツリーを辿って目的のノード見つける

       ノードツリーを辿って目的のノードを見つけるには、以下のような操作を使って行います。

      1. 子ノードの一覧(ノードリスト)を取得する。

        NodeList nodeList = node.getChildNodes();

      2. ノードリスト内のノードの数を取得する

        int length = nodeList.getLength();

      3. ノードリスト内の i 番目のノードを取得する

        Node node = nodeList.item(i);

      4. ノードリスト内の最初のノードを取得する

        Node node = nodeList.getFirstChild();

      5. ノードリスト内の最後のノードを取得する

        Node node = nodeList.getLastChild();

      6. ノードリスト内の一つ前のノードを取得する

        Node node = currentNode.getPreviousSibling();

      7. ノードリスト内の次のノードを取得する

        Node node = currentNode.getNextSibling();

      8. 親ノードを取得する。

        Node parentNode = node.getParentNode();

      9. 子ノードの有無を判定する。

        boolean stat = node.hasChildNodes();

      10. そのノードが所属するドキュメントを取得する。

        Document document = node.getOwnerDocument();

    2. 要素名から目的の要素ノード見つける

       上記のようにノードツリーを辿るのではなく

      NodeList nodeList = node.getElementByTagName("hoge");

      のようにして、指定の要素名( ここでは hoge )の要素の一覧を取得することもできます。

    3. 属性ノードを取得する

      1. 要素内の属性の一覧を取得する。

        NamedNodeMap nodeMap = element.getAttributes();

      2. 属性一覧内の属性の数を取得する

        int length = nodeMap.getLength();

      3. 属性一覧内の i 番目の属性を取得する

        Node node = nodeMap.item(i);

    4. ノードの各値を取得する

      ※ ノードタイプごとの返却値は後述の一覧表参照。

      1. ノードタイプを取得する

        short nodeType = node.getNodeType();

      2. ノード名を取得する

        String nodeName = node.getNodeName();

      3. ノードの値を取得する

        String nodeValue = node.getNodeValue();

    5. ノードタイプ一覧

      ノードタイプ 定義値 getNodeName getNodeValue getNodeAttribute
      要素 Node.ELEMENT_NODE 要素名 null NamedNodeMap
      属性 Node.ATTRIBUTE_NODE 属性名 属性値 null
      テキスト Node.TEXT_NODE #text テキスト null
      CDATAセクション Node.CDATA_SECTION_NODE #cdata-section CDATAセクションの内容 null
      実体参照 Node.ENTITY_REFERENCE_NODE 展開される実体参照 null null
      実体 Node.ENTITY_NODE 実体名 null null
      処理命令 Node.PROCESSING_INSTRUCTION_NODE ターゲット ターゲットを除いた内容全部 null
      コメント Node.COMMENT_NODE #comment コメントの内容 null
      ドキュメント Node.DOCUMENT_NODE #document null null
      文書型 Node.DOCUMENT_TYPE_NODE 文書型名 null null
      部分文書 Node.DOCUMENT_FRAGMENT_NODE #document-fragment null null
      記法 Node.NOTATION_NODE 記法名 null null

    6. 属性ノード

       属性ノードは、上記の他に以下の方法でも操作することができる。

      1. 属性名を取得する

        String attributeName = attribute.getName();

      2. 属性の値を取得する

        String attributeValue = element.getAttribute(attributeName);

        String attributeValue = attribute.getValue();

      3. その属性が所属する要素を取得する

        Element element = attribute.getOwnerElement();

    7. プログラム例

      プログラム例 : XML文書をスキャンするプログラム

      import org.w3c.dom.*;
      import javax.xml.parsers.*;

      class Foo {
      public void scanNodes(NodeList nodeList) throws Exception {
      try {
      for ( int i=0; i<nodeList.getLength(); i++ ) {
      Node node = nodeList.item(i);
      String nodeName = node.getNodeName();
      String nodeValue = node.getNodeValue();
      if ( Node.ELEMENT_NODE == node.getNodeType() ) {
      NamedNodeMap nodeMap = node.getAttributes();
      it ( null != nodeMap ) {
      for ( int j=0; j<nodeMap.getLength(); j++ ) {
      String attributeName = nodeMap.item(j).getNodeName();
      String attributeValue = nodeMap.item(j).getNodeValue();
      }
      }
      }
      if ( true == node.hasChildNodes() ) {
      scanNodes( node.getChildNodes() );
      }
      }
      } catch (Exception e) {
      System.out.println(e.getMessage());
      e.printStackTrace();
      throw e;
      }
      }
      }


  3. メモリ上のXML文書の内容を変更する

    1. 要素を追加する

      parentNode.appendChild(element);

    2. 要素の値を変更する

      element.getChildNodes().item(0).setNodeValue(value);

    3. 要素を置き換える

      parentNode.replaceChild(newElement, oldElement);

    4. 要素を削除する

      parentNode.removeChild(element);

    5. 属性の値を変更する

      attribute.setValue(attributeValue);

    6. 属性を変更(なければ追加)する

      element.setAttribute(attributeName, attributeValue);

    7. 属性を追加する・置き換える

      element.setAttributeNode(attributeNode);

    8. 属性を削除する

      element.removeAttribute(attributeName);

      element.removeAttributeNode(attributeNode);


  4. メモリ上のXML文書をファイルに出力する

     メモリ上のXML文書を出力するには

    ((XmlDocument)document).write(出力先, エンコード);

    のようにします。
    ここで、ファイルに出力するのに BufferdWriter を使うとしたら

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

    FileWriter fileWriter = new FileWriter("hoge.xml");
    BufferedWriter bufferdWriter = new BufferedWriter(fileWriter);
    ((XmlDocument)document).write(bufferdWriter, "Shift_JIS");
    bufferdWriter.flush();
    bufferdWriter.close();

    のようになります。


  5. ファイルからXML文書をメモリ上に読み込む

     ファイルに保存されたXML文書をメモリ上に読み込むには、

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

    File fileObject = new File("hoge.xml");
    DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    Document document = docBuilder.parse(fileObject);

    のようにします。
    ここで、JAXP の実装によっては行末の改行コードの処理がうまく行かず行末にゴミコードが残ってしまうようなので、読み込んだ後に

    document.normalize();

    とすれば行末のゴミを取り除くことができます。
    と本に書いてありましたが、Sun ONE Studio 4, Community Edition 付属の JAXP ではうまくいきませんでした。


  6. WebからXML文書をメモリ上に読み込む

     Web上のXML文書をメモリ上に読み込むには、

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

    URL url = new URL("http://www.aheahe.com/xml/hoge.xml");
    HttpURLConnection connection = (HttpURLConnection)url.openConnection();
    connection.setDoOutput(true);
    connection.setUseCashes(false);
    connection.setRequestMethod("GET"); または connection.setRequestMethod("POST");
    InputStream inputStream = connection.getInputStream();
    DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    Document document = docBuilder.parse(inputStream);

    のようにします。