1. 序章

このチュートリアルでは、一般的なJavaライブラリとテンプレートエンジン(JAXP、StAX、Freemarker、Mustache )を使用してXMLをHTMLに変換する方法について説明します。

2. マーシャリングを解除するXML

HTMLに変換する前に、適切なJava表現にアンマーシャリングする単純なXMLドキュメントから始めましょう。 いくつかの重要な目標を念頭に置きます。

  1. すべてのサンプルで同じXMLを維持する
  2. 最後に構文的および意味的に有効なHTML5ドキュメントを作成します
  3. すべてのXML要素をテキストに変換します

サンプルXMLとして単純なJenkins通知を使用してみましょう。

<?xml version="1.0" encoding="UTF-8"?>
<notification>
    <from>builds@baeldung.com</from>
    <heading>Build #7 passed</heading>
    <content>Success: The Jenkins CI build passed</content>
</notification>

そして、それはかなり簡単です。 これには、ルート要素といくつかのネストされた要素が含まれます。

HTMLファイルを作成するときに、一意のXMLタグをすべて削除し、キーと値のペアを出力することを目指します。

3. JAXP

XML処理用のJavaアーキテクチャ( JAXP )は、追加のDOMサポートを使用して人気のあるSAXパーサーの機能を拡張することを目的としたライブラリです。 JAXPは、SAXパーサーを使用して、XML定義のオブジェクトをPOJOとの間でマーシャリングおよびアンマーシャリングする機能を提供します。 また、組み込みのDOMヘルパーを利用します。

JAXPMaven依存関係をプロジェクトに追加しましょう。

<dependency>
    <groupId>javax.xml</groupId>
    <artifactId>jaxp-api</artifactId>
    <version>1.4.2</version>
</dependency>

3.1. DOMBuilderを使用したアンマーシャリング

まず、XMLファイルをJava Elementオブジェクトにアンマーシャリングすることから始めましょう。

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);

Document input = factory
  .newDocumentBuilder()
  .parse(resourcePath);
Element xml = input.getDocumentElement();

3.2. マップ内のXMLファイルの内容の抽出

それでは、XMLファイルの関連コンテンツを使用してMapを作成しましょう。

Map<String, String> map = new HashMap<>();
map.put("heading", 
  xml.getElementsByTagName("heading")
    .item(0)
    .getTextContent());
map.put("from", String.format("from: %s",
  xml.getElementsByTagName("from")
    .item(0)
    .getTextContent()));
map.put("content", 
  xml.getElementsByTagName("content")
    .item(0)
    .getTextContent());

3.3. DOMBuilderを使用したマーシャリング

XMLをHTMLファイルにマーシャリングするのはもう少し複雑です。

HTMLを書き出すために使用する転送ドキュメントを準備しましょう。

Document doc = factory
  .newDocumentBuilder()
  .newDocument();

次に、マップドキュメント要素を入力します。

Element html = doc.createElement("html");

Element head = doc.createElement("head");
html.setAttribute("lang", "en");

Element title = doc.createElement("title");
title.setTextContent(map.get("heading"));

head.appendChild(title);
html.appendChild(head);

Element body = doc.createElement("body");

Element from = doc.createElement("p");
from.setTextContent(map.get("from"));

Element success = doc.createElement("p");
success.setTextContent(map.get("content"));

body.appendChild(from);
body.appendChild(success);

html.appendChild(body);
doc.appendChild(html);

最後に、TransformerFactoryを使用してDocumentオブジェクトをマーシャリングしましょう。

TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");

try (Writer output = new StringWriter()) {
    Transformer transformer = transformerFactory.newTransformer();
    transformer.transform(new DOMSource(doc), new StreamResult(output));
}

output.toString()を呼び出すと、HTML表現が得られます。

工場で設定した追加機能と属性の一部は、XXEインジェクションを回避するためにOWASPプロジェクトの推奨事項から取得されていることに注意してください

4. StAX

使用できるもう1つのライブラリは、XML用のストリーミングAPI( StAX )です。 JAXPと同様に、StAXは2004年以来長い間存在しています。

他の2つのライブラリは、XMLファイルの解析を簡素化します。 これは単純なタスクやプロジェクトには最適ですが、反復する必要がある場合や、要素の解析自体を明示的かつきめ細かく制御する必要がある場合には適していません。 そこでStAXが役に立ちます。

StAXAPIMaven依存関係をプロジェクトに追加しましょう。

<dependency>
    <groupId>javax.xml.stream</groupId>
    <artifactId>stax-api</artifactId>
    <version>1.0-2</version>
</dependency>

4.1. StAXを使用したアンマーシャリング

単純な反復制御フローを使用して、XML値をMapに格納します。

XMLInputFactory factory = XMLInputFactory.newInstance();
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
XMLStreamReader input = null;
try (FileInputStream file = new FileInputStream(resourcePath)) {
    input = factory.createXMLStreamReader(file);

    Map<String, String> map = new HashMap<>();
    while (input.hasNext()) {
        input.next();
        if (input.isStartElement()) {
            if (input.getLocalName().equals("heading")) {
                map.put("heading", input.getElementText());
            }
            if (input.getLocalName().equals("from")) {
                map.put("from", String.format("from: %s", input.getElementText()));
            }
            if (input.getLocalName().equals("content")) {
                map.put("content", input.getElementText());
            }
        }
    }
} finally {
    if (input != null) {
        input.close();
    }
}

4.2. StAXを使用したマーシャリング

それでは、マップを使用してHTMLを書き出しましょう。

try (Writer output = new StringWriter()) {
    XMLStreamWriter writer = XMLOutputFactory
      .newInstance()
      .createXMLStreamWriter(output);

    writer.writeDTD("<!DOCTYPE html>");
    writer.writeStartElement("html");
    writer.writeAttribute("lang", "en");
    writer.writeStartElement("head");
    writer.writeDTD("<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">");
    writer.writeStartElement("title");
    writer.writeCharacters(map.get("heading"));
    writer.writeEndElement();
    writer.writeEndElement();

    writer.writeStartElement("body");

    writer.writeStartElement("p");
    writer.writeCharacters(map.get("from"));
    writer.writeEndElement();

    writer.writeStartElement("p");
    writer.writeCharacters(map.get("content"));
    writer.writeEndElement();

    writer.writeEndElement();
    writer.writeEndDocument();
    writer.flush();
}

JAXPの例のように、 output.toString()を呼び出してHTML表現を取得できます。

5. テンプレートエンジンの使用

HTML表現を作成する代わりに、テンプレートエンジンを使用できます。 Javaエコシステムには複数のオプションがあります。 それらのいくつかを調べてみましょう。

5.1. ApacheFreemarkerの使用

Apache FreeMarker は、テンプレートと変更データに基づいてテキスト出力(HTML Webページ、電子メール、構成ファイル、ソースコードなど)を生成するためのJavaベースのテンプレートエンジンです。

これを使用するには、freemarker依存関係をMavenプロジェクトに追加する必要があります。

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.29</version>
</dependency>

まず、FreeMarker構文を使用してテンプレートを作成しましょう。

<!DOCTYPE html>
<html lang="en">
<head>
    <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>${heading}</title>
</head>
<body>
<p>${from}</p>
<p>${content}</p>
</body>
</html>

それでは、マップを再利用して、テンプレートのギャップを埋めましょう。

Configuration cfg = new Configuration(Configuration.VERSION_2_3_29);
cfg.setDirectoryForTemplateLoading(new File(templateDirectory));
cfg.setDefaultEncoding(StandardCharsets.UTF_8.toString());
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
cfg.setLogTemplateExceptions(false);
cfg.setWrapUncheckedExceptions(true);
cfg.setFallbackOnNullLoopVariable(false);
Template temp = cfg.getTemplate(templateFile);
try (Writer output = new StringWriter()) {
    temp.process(staxTransformer.getMap(), output);
}

5.2. 口ひげを使う

Mustacheは、ロジックのないテンプレートエンジンです。 Mustacheは、HTML、構成ファイル、ソースコードなど、ほとんど何にでも使用できます。 ハッシュまたはオブジェクトで提供される値を使用して、テンプレート内のタグを展開することで機能します。

これを使用するには、mustache依存関係をMavenプロジェクトに追加する必要があります。

<dependency>
    <groupId>com.github.spullara.mustache.java</groupId>
    <artifactId>compiler</artifactId>
    <version>0.9.6</version>
</dependency>

Mustache構文を使用してテンプレートの作成を開始しましょう。

<!DOCTYPE html>
<html lang="en">
<head>
    <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>{{heading}}</title>
</head>
<body>
<p>{{from}}</p>
<p>{{content}}</p>
</body>
</html>

それでは、テンプレートにマップを入力してみましょう。

MustacheFactory mf = new DefaultMustacheFactory();
Mustache mustache = mf.compile(templateFile);
try (Writer output = new StringWriter()) {
    mustache.execute(output, staxTransformer.getMap());
    output.flush();
}

6. 結果のHTML

最終的に、すべてのコードサンプルで、同じHTML出力が得られます。

<!DOCTYPE html>
<html lang="en">
<head>
    <META http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Build #7 passed</title>
</head>
<body>
<p>from: builds@baeldung.com</p>
<p>Success: The Jenkins CI build passed</p>
</body>
</html>

7. 結論

このチュートリアルでは、JAXP、StAX、Freemarker、およびMustacheを使用してXMLをHTMLに変換するための基本を学びました。

JavaのXMLの詳細については、ここBaeldungでこれらの他の優れたリソースを確認してください。

いつものように、ここに表示される完全なコードサンプルは、GitHubから入手できます。