Java の org.w3c.dom.Document オブジェクトと XML 文字列を変換する

## サンプルコード

MyApp.java というファイル名で以下のサンプルコードを保存する。

```java
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;

/**
 * XML 文字列と Document オブジェクトの変換サンプルコード (文字エンコーディングは UTF-8 固定)。
 */
public class MyApp {

  /**
   * XML 文字列を Document オブジェクトに変換します。
   * @param xml XML 文字列
   * @return Document オブジェクト
   * @throws ParserConfigurationException
   * @throws SAXException
   * @throws IOException
   */
  public static Document toDocument(String xml) throws ParserConfigurationException, SAXException, IOException {
    try (StringReader reader = new StringReader(xml)) {
      InputSource source = new InputSource(reader);
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      DocumentBuilder builder = factory.newDocumentBuilder();
      return builder.parse(source);
    }
  }

  /**
   * Document オブジェクトを XML 文字列に変換します。
   * @param doc Document オブジェクト
   * @return XML 文字列
   * @throws IOException
   * @throws TransformerException
   */
  public static String toString(Document doc) throws IOException, TransformerException {
    try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
      TransformerFactory factory = TransformerFactory.newInstance();
      Transformer transformer = factory.newTransformer();
      // 指定しなくてもデフォルトは UTF-8 だったりする
      transformer.setOutputProperty(OutputKeys.ENCODING, StandardCharsets.UTF_8.name());
      DOMSource source = new DOMSource(doc);
      StreamResult result = new StreamResult(output);
      transformer.transform(source, result);
      return output.toString(StandardCharsets.UTF_8);
    }
  }

  // 動作確認用メソッド
  public static void main(String[] args) throws IOException, SAXException, ParserConfigurationException, TransformerException, XPathExpressionException {

    // 動作確認用の XML 文字列を用意
    // Java 15 から使える Text Blocks 機能による文字列リテラルを利用
    String xml = """
      <?xml version="1.0" encoding="UTF-8"?>
      <feed xml:lang="ja-JP" xmlns="http://www.w3.org/2005/Atom">
        <id>helloworldfeed</id>
        <author>niwasawa</author>
        <title>Hello World フィード</title>
        <updated>2000-08-06T00:00:00+09:00</updated>
        <entry>
          <id>helloworldfeed:helloworld1</id>
          <title>Hello World こんにちは世界</title>
          <content>Hello World こんにちは世界</content>
          <updated>2000-08-06T00:00:00+09:00</updated>
        </entry>
      </feed>
      """;

    // XML 文字列を Document オブジェクトに変換
    System.out.println("***** XML 文字列を Document オブジェクトに変換 *****");
    Document doc = toDocument(xml);
    System.out.println("タイトル: " + XPathFactory.newInstance().newXPath().evaluate("//title", doc, XPathConstants.STRING));
    System.out.println();

    // Document オブジェクトを XML 文字列に変換
    System.out.println("***** Document オブジェクトを XML 文字列に変換 *****");
    doc.setXmlStandalone(true);
    String outputXml = toString(doc);
    System.out.println(outputXml);
    System.out.println();
  }
}
```

## サンプルの実行結果

実行環境: Java 15 (Oracle JDK) + macOS Catalina

```
$ java MyApp.java
***** XML 文字列を Document オブジェクトに変換 *****
タイトル: Hello World フィード

***** Document オブジェクトを XML 文字列に変換 *****
<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ja-JP">
  <id>helloworldfeed</id>
  <author>niwasawa</author>
  <title>Hello World フィード</title>
  <updated>2000-08-06T00:00:00+09:00</updated>
  <entry>
    <id>helloworldfeed:helloworld1</id>
    <title>Hello World こんにちは世界</title>
    <content>Hello World こんにちは世界</content>
    <updated>2000-08-06T00:00:00+09:00</updated>
  </entry>
</feed>
```

## 参考資料

- [java\.xml \(Java SE 15 & JDK 15\)](https://docs.oracle.com/en/java/javase/15/docs/api/java.xml/module-summary.html)
- [java\.xml \(Java SE 14 & JDK 14\) 日本語ドキュメント](https://docs.oracle.com/javase/jp/14/docs/api/java.xml/module-summary.html)