Java : XML (DOM) の基本

XMLの構文は知っているけど、Javaで扱うにはどうしたらよいのかな…
そんなかたを対象に、本記事ではXMLを扱う基本となる DOM (Document Object Model) API について解説していきます。

対象読者:XMLの構文は理解しているかた


概要

JavaでXMLを扱うには、大きく分けて3つの種類のAPIがあります。

API 簡単な説明 向き 不向き
DOM XMLを、アプリから操作しやすいツリー構造で表現します。
アプリはツリー構造の各要素(ノード)に対して読み・書き・追加・削除ができます。
比較的サイズの小さなXMLに対して、きめ細やかな操作をしたいときに向いています。 XMLをまるごとツリー構造として表現するため、巨大なXMLを扱うとメモリ不足になる場合があります。
SAX XMLを読み込み(パース)しながら、逐次的にアプリケーションで処理します。
アプリはSAXのイベントを受動的に受け取ります。
PUSH型とも言われています。
単純な構造のXMLの読み込みに向いています。
ツリー構造を作らないので、巨大なサイズのXMLでもメモリ使用量は抑えられます。
XMLの先頭から順々に処理するため、例えば最後のノードを処理してから最初のノードを処理したい、というのは難しいです。
StAX SAXとは違い、アプリはイベントを能動的に取得します。
PULL型とも言われています。
SAXより後発のAPIなこともあり、SAXより使いやすくなっている、と思います。(そこまでがっつりと使ったことはないですが…)
SAXと同じです。 SAXと同じです。

本記事では、この中の DOM (Document Object Model) を解説していきます。

DOMのAPIは W3C によって勧告されています。Java独自の仕様ではありません。
そのため、Java以外のプログラミング言語(例えばC#やPythonなど)でも実装されています。

JavaでDOMが理解できれば、他の言語でもほぼ同じ使い方ができます。
なので理解しておいて損はないかな、と。

W3C (World Wide Web Consortium)

  • Webに関する各種技術の標準化を推進する団体です。
    HTMLやXML、DOMといった規格が勧告されています。
  • Java 16の時点では、DOM Level 3 Core の仕様に対応しています。
    Document Object Model (DOM) Level 3 Core Specification

JAXP セキュリティ・ガイド

少し難しい内容ですが、大事なことなので早めにご紹介してしまいます。
今はまだ読まなくてもよいですが、XMLの扱いに慣れてきたら下記の公式ドキュメントもご確認ください。

Java API for XML Processing (JAXP)セキュリティ・ガイド (Java SE 16)

XML処理中の潜在的な攻撃である

  • XML外部エンティティ(XXE)インジェクション攻撃
  • 指数関数的エンティティ展開攻撃

について解説しています。

また、それらの攻撃を回避するためのXMLConstants.FEATURE_SECURE_PROCESSINGやプロパティについても詳しく説明されています。
外部からの信頼されていないXMLを読み込む場合は、上記のページを熟読することをおすすめします。

XMLテキスト → DOM

DOMでは、XMLをツリー構造に表現して操作していきます。

XMLテキストからDOMのツリー構造を生成することを、パース(Parse)といいます。
Parse = 解析ですね。

それではコード例を見てみましょう。

final var xml = """
        <root><child-a/><child-b/></root>
        """;

final var builderFactory = DocumentBuilderFactory.newInstance();
final var builder = builderFactory.newDocumentBuilder();

final var document = builder.parse(new ByteArrayInputStream(xml.getBytes()));

final Element root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var nodes = root.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
    final var node = nodes.item(i);

    //i = 0 : [child-a: null]
    //i = 1 : [child-b: null]
    System.out.println("i = " + i + " : " + node);
}

XML形式の文字列をパースしてDOMのツリー構造を生成します。
そして、ツリー構造の内容を確認しています。

コードを少しずつ見ていきましょう。

DOMのツリー構造では、ツリーの一番の親はDocumentとなります。
そのため、Documentを生成するためのDocumentBuilderを生成するためのDocumentBuilderFactoryから生成していきます。

// DocumentBuilerを生成するためのFactoryを生成します。
final var builderFactory = DocumentBuilderFactory.newInstance();

// FactoryでDocumentBuilderを生成します。
final var builder = builderFactory.newDocumentBuilder();

// DocumentBuilderでDocumentを生成します。
// 対象となるXMLはInputStreamとして読み込ませています。(他にはURIやファイルからなども可能)
final var document = builder.parse(new ByteArrayInputStream(xml.getBytes()));

Documentは、ルートとなる1つのElementを持ちます。

final Element root = document.getDocumentElement();
System.out.println(root); // [root: null]

Elementは複数の子ノードを持ちます。

final var nodes = root.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
    final var node = nodes.item(i);

    //i = 0 : [child-a: null]
    //i = 1 : [child-b: null]
    System.out.println("i = " + i + " : " + node);
}

ツリー構造は次のようなイメージになります。

ツリー構造

DOM → XMLテキスト

DOMからXMLテキストに変換するにはTransformerを使います。

TransformerはJava独自のAPIです。
DOM専用というわけではなく、SAXやStAX、文字列にも使える汎用的なAPIとなっています。

final var xml = """
        <root><child>aaa</child></root>
        """;

final var builderFactory = DocumentBuilderFactory.newInstance();
final var builder = builderFactory.newDocumentBuilder();

final var document = builder.parse(new ByteArrayInputStream(xml.getBytes()));

final var transformerFactory = TransformerFactory.newInstance();
final var transformer = transformerFactory.newTransformer();

final var source = new DOMSource(document);
final var result = new StreamResult(new StringWriter());

transformer.transform(source, result);

//<?xml version="1.0" encoding="UTF-8" standalone="no"?><root><child>aaa</child></root>
System.out.println(result.getWriter());

XMLテキストをまずDOM形式にパースして、それをTransformerで再びXMLテキストへと変換する例となります。
コードを少しずつ見ていきましょう。

// Transformerを生成するためのFactoryを生成します。
final var transformerFactory = TransformerFactory.newInstance();

// FactoryでTransformerを生成します。
final var transformer = transformerFactory.newTransformer();

DocumentBuilderのときと同じように、Transformerを生成するためにまずFactoryを生成します。

public abstract void transform​(Source xmlSource, Result outputTarget) throws TransformerException
XML SourceをResultに変換します。

Transformer.transformで実際に変換します。
Source → Resultへと変換されます。

// SourceとしてDOMを使います。
final var source = new DOMSource(document);

// 結果はストリーム(文字列)で受け取ります。
final var result = new StreamResult(new StringWriter());

// 変換します。
transformer.transform(source, result);

SourceResult はSAXやStAXなどにも対応しています。
詳細はAPI仕様をご参照ください。

//<?xml version="1.0" encoding="UTF-8" standalone="no"?><root><child>aaa</child></root>
System.out.println(result.getWriter());

無事、StringWriter経由で結果を文字列として取得できました。

<?xml ~ ?>の部分は、XML宣言といいます。
Tranformerではデフォルトで出力します。

もし出力させたくない場合は、次のsetOutputPropertyで設定できます。

出力形式の設定

public abstract void setOutputProperty​(String name, String value) throws IllegalArgumentException
変換に有効な出力プロパティを設定します。

Transformer.setOutputProperty​を使うことで、出力形式を設定できます。
nameパラメータに指定できる文字列は、OutputKeysクラスに定義されています。

Transformerの出力プロパティを設定するために、あるいはTransformerまたはTemplatesオブジェクトから出力プロパティを取り出すために使用できる文字列定数を提供します。

よく使うのは、

  • OMIT_XML_DECLARATION
  • INDENT

あたりでしょうか。

OMIT_XML_DECLARATIONの例

final var xml = """
        <root><child>aaa</child></root>
        """;
... 省略 ...

final var transformer = transformerFactory.newTransformer();

// デフォルトは"no"
System.out.println(transformer.getOutputProperty(OutputKeys.OMIT_XML_DECLARATION)); // "no"

// "yes"に変更
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");

final var source = new DOMSource(document);
final var result = new StreamResult(new StringWriter());

transformer.transform(source, result);

//<root><child>aaa</child></root>
System.out.println(result.getWriter());

OMIT_XML_DECLARATIONを"yes"に設定すると、XML宣言の<?xml ~ ?>は出力しません。

INDENTの例

final var xml = """
        <root><child>aaa</child></root>
        """;
... 省略 ...

final var transformer = transformerFactory.newTransformer();

// デフォルトは"no"
System.out.println(transformer.getOutputProperty(OutputKeys.INDENT)); // "no"

// "yes"に変更
transformer.setOutputProperty(OutputKeys.INDENT, "yes");

final var source = new DOMSource(document);
final var result = new StreamResult(new StringWriter());

transformer.transform(source, result);

//<?xml version="1.0" encoding="UTF-8" standalone="no"?>
//<root>
//    <child>aaa</child>
//</root>
System.out.println(result.getWriter());

見やすいように、改行とスペースをいい感じに入れてくれます。

ただし、1点注意があります。
インデントされたXMLテキストをそのままパースすると、追加された改行とスペースはTextノードとしてツリー構造に追加されます。

final var xml = """
        <root>
            <child>aaa</child>
        </root>
        """;

final var builderFactory = DocumentBuilderFactory.newInstance();
final var builder = builderFactory.newDocumentBuilder();

final var document = builder.parse(new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();

final var nodes = root.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
    final var node = nodes.item(i);

    // 見やすさのため、半角スペースは * 改行は \n として表記します。

    //i = 0 : [#text: \n****]
    //i = 1 : [child: null]
    //i = 2 : [#text: \n]
    System.out.println("i = " + i + " : " + node);
}

ノードの操作

今までの例では、XMLテキストをパースすることにより、Nodeのツリー構造を作成してきました。
もちろん、XMLテキストなしで、1からNodeのツリー構造を作成することも可能です。

コード例を見てみましょう。

final var builderFactory = DocumentBuilderFactory.newInstance();
final var builder = builderFactory.newDocumentBuilder();

// 空のDocumentを生成します。
final var document = builder.newDocument();

// ルートとなるElementを作成して、documentに追加します。
final var root = document.createElement("root");
document.appendChild(root);

// 子となるElement(child-a)を作成して、rootに追加します。
final var childA = document.createElement("child-a");
root.appendChild(childA);

// Textノードを作成して、child-aに追加します。
final var text = document.createTextNode("aaaa");
childA.appendChild(text);

// 子となるElement(child-b)を作成して、rootに追加します。
final var childB = document.createElement("child-b");
root.appendChild(childB);

// 属性ノード bbb="ccc" を作成して、child-bに設定します。
final var attr = document.createAttribute("bbb");
attr.setValue("ccc");

childB.setAttributeNode(attr);

final var transformerFactory = TransformerFactory.newInstance();
final var transformer = transformerFactory.newTransformer();

transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");

final var source = new DOMSource(document);
final var result = new StreamResult(new StringWriter());

transformer.transform(source, result);

//<root>
//    <child-a>aaaa</child-a>
//    <child-b bbb="ccc"/>
//</root>
System.out.println(result.getWriter());

Document.create~で各種ノードを生成し、appendChildで子ノードとして追加していく、というのが基本となります。

Node

Nodeは、すべてのツリー構造の要素の基底となるインタフェースです。

クラス図

ただし、属性(Attr)は少し特殊で、ツリー構造の一部とはならずにElementに直接保持されます。

1.1.1 The DOM Structure Model
The DOM presents documents as a hierarchy of Node objects that also implement other, more specialized interfaces. Some types of nodes may have child nodes of various types, and others are leaf nodes that cannot have anything below them in the document structure.

どのノードがどのノードを子ノードとして持てるのか? もしくはノードを持てないのか?というのは上記のDOM仕様で定義されています。

主要なノードのみに絞ると次のようになります。

  • Document -- Element (maximum of one), Comment
  • Element -- Element, Text, Comment
  • Attr -- Text
  • Comment -- no children
  • Text -- no children

CommentやTextは子ノードを持てないことが分かりますね。

Nodeの主要なメソッドは、ツリー構造に関するものです。
親ノードを取得(getParent)、子ノードを追加(appendChild​)、子ノードを取得(getChildNodes)などなど。

API 説明 コード例
short getNodeType() 自分がなんのノードなのか?というタイプ値を返します。
値については定数で定義されています。

final var element = document.createElement("element");
System.out.println(element.getNodeType() == Node.ELEMENT_NODE); // true

final var text = document.createTextNode("text");
System.out.println(text.getNodeType() == Node.TEXT_NODE); // true

final var attr = document.createAttribute("attr");
System.out.println(attr.getNodeType() == Node.ATTRIBUTE_NODE); // true
Node getParentNode() 親ノードを取得します。
final var xml = """
        <root><child><child-child/></child></root>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var child = root.getFirstChild();
System.out.println(child); // [child: null]

final var childChild = child.getFirstChild();
System.out.println(childChild); // [child-child: null]

final var childChildParent = childChild.getParentNode();
System.out.println(childChildParent); // [child: null]
System.out.println(childChildParent == child); // true

final var childParent = child.getParentNode();
System.out.println(childParent); // [root: null]
System.out.println(childParent == root); // true
Node getFirstChild() 先頭の子ノードを取得します。
final var xml = """
        <root><child-a/><child-b/><child-c/></root>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var firstChild = root.getFirstChild();
System.out.println(firstChild); // [child-a: null]
Node getLastChild() 最後の子ノードを取得します。
final var xml = """
        <root><child-a/><child-b/><child-c/></root>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var lastChild = root.getLastChild();
System.out.println(lastChild); // [child-c: null]
NodeList getChildNodes() 子ノードをすべて取得します。
(孫となるノードは取得されません)
final var xml = """
        <root><child-a/><child-b/><child-c/></root>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var nodes = root.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
    final var node = nodes.item(i);

    //i = 0 : [child-a: null]
    //i = 1 : [child-b: null]
    //i = 2 : [child-c: null]
    System.out.println("i = " + i + " : " + node);
}
Node appendChild​(Node newChild) 指定したノードを、子ノードの最後に追加します。
final var xml = """
        <root><child-a/></root>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var childB = document.createElement("child-b");
root.appendChild(childB);

final var text = document.createTextNode("bbb");
childB.appendChild(text);

...

transformer.transform(source, result);

//<root>
//    <child-a/>
//    <child-b>bbb</child-b>
//</root>
System.out.println(result.getWriter());
Node insertBefore(Node newChild, Node refChild) すでに追加済みのNodeの手前に、新しくノードを追加します。
final var xml = """
        <root><child-z/></root>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var childZ = root.getFirstChild();
System.out.println(childZ); // [child-z: null]

final var childY = document.createElement("child-y");
root.insertBefore(childY, childZ);

final var childX = document.createElement("child-x");
root.insertBefore(childX, childY);

...

transformer.transform(source, result);

//<root>
//    <child-x/>
//    <child-y/>
//    <child-z/>
//</root>
System.out.println(result.getWriter());

NodeList

NodeListインタフェースは、ノードの順序付きコレクションの抽象を提供します。

Node.getChildNodesやElement.getElementsByTagName などで、複数のNodeを返すときに使われます。

Java標準APIのListインタフェースではないので、ちょっと使いづらいですね。(拡張for文も使えません)
素直に、基本for文でループさせるのがよさそうです。

final var xml = """
        <root><child-a/><child-b/><child-c/></root>
        """;

final var builderFactory = DocumentBuilderFactory.newInstance();
final var builder = builderFactory.newDocumentBuilder();

final var document = builder.parse(new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var nodes = root.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
    final var node = nodes.item(i);

    //i = 0 : [child-a: null]
    //i = 1 : [child-b: null]
    //i = 2 : [child-c: null]
    System.out.println("i = " + i + " : " + node);
}

Document

Documentは、DOMのツリー構造の一番親となるノードです。
ルートとなる1つのElementノードを持ちます。

ツリー構造図

そして、ElementやText、Attrといった各種ノードを生成する役割をもちます。

クラス図

API 説明 コード例
Element getDocumentElement() ルートとなるElementノードを取得します。
final var xml = """
        <root><child/></root>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]
Element createElement(String tagName) 指定したタグ名のElementノードを生成します。
final var element = document.createElement("element");
System.out.println(element); // [element: null]
System.out.println(element.getNodeType() == Node.ELEMENT_NODE); // true
Attr createAttribute(String name) 指定した属性名のAttrノードを生成します。
final var attr = document.createAttribute("aaa");
attr.setValue("bbb");

System.out.println(attr); // aaa="bbb"
System.out.println(attr.getNodeType() == Node.ATTRIBUTE_NODE); // true
Text createTextNode(String data) 指定した内容のTextノードを生成します。
final var text = document.createTextNode("abcd");
System.out.println(text); // [#text: abcd]
System.out.println(text.getNodeType() == Node.TEXT_NODE); // true
Comment createComment(String data) 指定した内容のCommentノードを生成します。
final var comment = document.createComment("abcd");
System.out.println(comment); // [#comment: abcd]
System.out.println(comment.getNodeType() == Node.COMMENT_NODE); // true

Element

Elementは、XML構造の要素を表します。
子ノードとしてElement、 Comment、Textなどを複数持つことが可能です。
また、子ノードとしてではないですが、属性(Attr)を複数持つことが可能です。

主要なメソッドとコード例になります。

API 説明 コード例
String getTagName() タグ名を取得します。
final var element = document.createElement("element");
System.out.println(element.getTagName()); // "element"
NodeList getElementsByTagName(String name) 子ノードから、指定したタグ名のノードを探して、すべて取得します。
子ノード、さらにその子ノードと、再帰的に検索します。
final var xml = """
        <root>
            <child-a>
                <target>aaa</target>
            </child-a>
            <child-b>
                <target>bbb</target>
            </child-b>

            <target>ccc</target>
        </root>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var nodes = root.getElementsByTagName("target");
for (int i = 0; i < nodes.getLength(); i++) {
    final var node = nodes.item(i);

    //i = 0 : aaa
    //i = 1 : bbb
    //i = 2 : ccc
    System.out.println("i = " + i + " : " + node.getTextContent());
}
void setAttribute(String name, String value) 新しい属性を追加します。
もしくは、すでに同じ属性名があるのであれば上書きします。
// XML表記 : <element/>
final var element = document.createElement("element");

// XML表記 : <element aaa="bbb"/>
element.setAttribute("aaa", "bbb");

// XML表記 : <element aaa="bbb" xxx="yyy"/>
element.setAttribute("xxx", "yyy");

// 上書き
// XML表記 : <element aaa="bbb" xxx="zzz"/>
element.setAttribute("xxx", "zzz");
String getAttribute(String name) 指定した属性名の値を取得します。
// XML表記 : <element/>
final var element = document.createElement("element");

// XML表記 : <element aaa="bbb"/>
element.setAttribute("aaa", "bbb");

final var attrValue = element.getAttribute("aaa");
System.out.println(attrValue); // bbb
void removeAttribute(String name) 指定した属性名の属性を削除します。
// XML表記 : <element/>
final var element = document.createElement("element");

// XML表記 : <element aaa="bbb"/>
element.setAttribute("aaa", "bbb");

// XML表記 : <element/>
element.removeAttribute("aaa");
Attr setAttributeNode(Attr newAttr)
Attr getAttributeNode(String name)
Attr removeAttributeNode(Attr oldAttr)
属性ノードとしても、set/get/removeできます。
// XML表記 : <element/>
final var element = document.createElement("element");

final var attrA = document.createAttribute("aaa");
attrA.setValue("bbb");

final var attrX1 = document.createAttribute("xxx");
attrX1.setValue("yyy");

final var attrX2 = document.createAttribute("xxx");
attrX2.setValue("zzz");

// XML表記 : <element aaa="bbb"/>
element.setAttributeNode(attrA);
System.out.println(attrA == element.getAttributeNode("aaa")); // true

// XML表記 : <element aaa="bbb" xxx="yyy"/>
element.setAttributeNode(attrX1);
System.out.println(attrX1 == element.getAttributeNode("xxx")); // true

// 上書き
// XML表記 : <element aaa="bbb" xxx="zzz"/>
element.setAttributeNode(attrX2);
System.out.println(attrX2 == element.getAttributeNode("xxx")); // true

// XML表記 : <element aaa="bbb"/>
element.removeAttributeNode(attrX2);

これ以外にも、Nodeで定義されているappendChild​やgetChildNodesもよく使いますね。

Attr

Attrは要素の属性を表します。
ツリー構造にはならず、Elementに直接保持されます。

API 説明 コード例
String getName() 属性名を取得します。
final var xml = """
        <root aa="AA"/>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var attr = root.getAttributeNode("aa");
System.out.println(attr); // aa="AA"

System.out.println(attr.getName()); // aa
System.out.println(attr.getValue()); // AA
String getValue() 属性値を取得します。
final var xml = """
        <root aa="AA"/>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var attr = root.getAttributeNode("aa");
System.out.println(attr); // aa="AA"

System.out.println(attr.getName()); // aa
System.out.println(attr.getValue()); // AA
void setValue(String value) 属性値を設定します。
final var xml = """
        <root aa="AA"/>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var attr = root.getAttributeNode("aa");
System.out.println(attr); // aa="AA"

// XML表記 : <root aa="BB"/>
attr.setValue("BB");

System.out.println(attr.getValue()); // BB

Text

Textノードは、XMLのテキストを表します。

API 説明 コード例
String getData() テキストの内容を取得します。
final var xml = """
        <root>aaa</root>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var child = root.getFirstChild();
if (child instanceof Text text) {
    System.out.println(text); // [#text: aaa]
    System.out.println(text.getData()); // "aaa"
}
void setData(String data) テキストの内容を設定します。
final var xml = """
        <root>aaa</root>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var child = root.getFirstChild();
if (child instanceof Text text) {
    System.out.println(text); // [#text: aaa]

    text.setData("bbb");

    System.out.println(text.getData()); // "bbb"
}

// rootのXML表記 : <root>bbb</root>

Comment

Commentノードは、XMLのコメント要素である <!-- ~ -->を表します。

API 説明 コード例
String getData() コメントの内容を取得します。
final var xml = """
        <root><!--aaa--></root>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var child = root.getFirstChild();
if (child instanceof Comment comment) {
    System.out.println(comment); // [#comment: aaa]
    System.out.println(comment.getData()); // "aaa"
}
void setData(String data) コメントの内容を設定します。
final var xml = """
        <root><!--aaa--></root>
        """;
...

final var document = builder.parse(
        new ByteArrayInputStream(xml.getBytes()));

final var root = document.getDocumentElement();
System.out.println(root); // [root: null]

final var child = root.getFirstChild();
if (child instanceof Comment comment) {
    System.out.println(comment);

    comment.setData("bbb");

    System.out.println(comment.getData()); // "bbb"
}

// rootのXML表記 : <root><!--bbb--></root>

まとめ

XMLは一時期に比べて使用率が減ってきた印象はあります。
代わりに、よりシンプルなJSONが人気でしょうか。

しかし、今回は紹介できませんでしたが、XMLはスキーマ言語によって厳格にフォーマットを定義できます。
他にもXSLTで結果を変換できたりと機能が豊富です。まだまだXMLがすたれることはないでしょう。

本記事では扱いきれなかったものとして、

  • SAX
  • StAX
  • DTD
  • XML Schema
  • XSLT
  • XPath

などがあります。
興味のあるかたは、それらのキーワードで調べてみてみるのもおすすめです。

いずれ記事にもまとめられたらな、と思っています。

DOMのさらなる詳細が知りたいかたは、関連記事の各種API使用例も参考にしていただけたら幸いです。


関連記事

ページの先頭へ