Java : TransformerFactory (XML) - API使用例

TransformerFactory (Java SE 17 & JDK 17) の使用例まとめです。
だいたいのメソッドを網羅済みです。
API仕様のおともにどうぞ。


概要

TransformerFactoryインスタンスを使用して、TransformerおよびTemplatesオブジェクトを作成できます。

クラス構成

TransformerFactoryは、XMLオブジェクト(DOMやSAX、StAX)を、XML形式の文字列やファイルに変換するための起点となるクラスです。
(正確には、DOMからSAXなどへの変換も可能です)

汎用APIなので、DOMやSAX、StAXに依存していません。

DOMからXML形式の文字列へ変換する一連の流れは次のようになります。

final var builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
final var document = builder.newDocument();

final var root = document.createElement("root");
document.appendChild(root);

final var text = document.createTextNode("abcd");
root.appendChild(text);

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

final var result = new StreamResult(new StringWriter());
transformer.transform(new DOMSource(document), result);

System.out.println(result.getWriter());

// 結果
// ↓
//<?xml version="1.0" encoding="UTF-8" standalone="no"?><root>abcd</root>

関連記事:XML (DOM) の基本

コンストラクタ

TransformerFactory ()

デフォルトのコンストラクタが意図的に保護されます。

protectedです。
独自にサブクラスを作ることは少ないと思いますので、コード例は割愛します。

メソッド

abstract Source getAssociatedStylesheet (Source source, String media, String title, String charset)

「The xml-stylesheet processing instruction」から、指定された基準に一致するXML Sourceドキュメントに関連付けられているスタイル・シート仕様を取得します。

final var file = Path.of("R:", "java-work", "sample.xsl");
System.out.println(file); // R:\java-work\sample.xsl

Files.writeString(file, """
        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
          <xsl:output omit-xml-declaration="yes" />

          <xsl:template match="root">
            <xxx>
              <xsl:value-of select="." />
            </xxx>
          </xsl:template>

        </xsl:stylesheet>
        """);

final var xml = """
        <?xml-stylesheet type="text/xsl" href="file:///R:/java-work/sample.xsl"?>
        <root>abcd</root>
        """;

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

final var transformerFactory = TransformerFactory.newInstance();

final var stylesheet = transformerFactory.getAssociatedStylesheet(
        new DOMSource(document), null, null, null);

final var transformer = transformerFactory.newTransformer(stylesheet);

final var result = new StreamResult(new StringWriter());
transformer.transform(new DOMSource(document), result);

System.out.println(result.getWriter());

// 結果
// ↓
//<xxx>abcd</xxx>

abstract Object getAttribute (String name)

ユーザーがベースとなる実装の特定の属性を取り出すことができるようにします。

このメソッドの使用例は、setAttribute(String name, Object value) にまとめて記載しました。
そちらのAPI使用例をご参照ください。

abstract ErrorListener getErrorListener ()

TransformerFactoryのエラー・イベント・ハンドラを取得します。

このメソッドの使用例は、setErrorListener(ErrorListener listener) にまとめて記載しました。
そちらのAPI使用例をご参照ください。

abstract boolean getFeature (String name)

機能の値を検索します。

このメソッドの使用例は、setFeature(String name, boolean value) にまとめて記載しました。
そちらのAPI使用例をご参照ください。

abstract URIResolver getURIResolver ()

document()、xsl:import、またはxsl:includeで使用されるURIを解決するために変換時にデフォルトで使用されるオブジェクトを取得します。

このメソッドの使用例は、setURIResolver(URIResolver resolver) にまとめて記載しました。
そちらのAPI使用例をご参照ください。

static TransformerFactory newDefaultInstance ()

TransformerFactory組み込みシステムのデフォルト実装の新しいインスタンスを作成します。

newInstance()とほぼ同じです。
API使用例はそちらをご参照ください。

補足:newInstanceとの違い

newInstance は、いろいろと TransformerFactory の実装を探して、なければ最後に組み込みシステムのデフォルト実装を使います。
newDefaultInstance は、組み込みシステムのデフォルト実装をすぐに使います。

よって、メソッドの呼び出し速度は newDefaultInstance のほうが速いです。

自分の環境(openjdk-17.0.1_windows)ではどちらも同じ実装を返しました。

final var defaultFactory = TransformerFactory.newDefaultInstance();

//com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl@6f43c82
System.out.println(defaultFactory);

final var factory = TransformerFactory.newInstance();

//com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl@58e1d9d
System.out.println(factory);

どちらを使うべきか?というのは正直、分かりません…
拡張性が高いのは newInstance のほうなので、個人的には newInstance でよいのではないかなと思います。

static TransformerFactory newInstance ()

TransformerFactoryの新しいインスタンスを取得します。

final var builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
final var document = builder.newDocument();

final var root = document.createElement("root");
document.appendChild(root);

final var text = document.createTextNode("abcd");
root.appendChild(text);

final var transformerFactory = TransformerFactory.newInstance();

final var transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");

final var result = new StreamResult(new StringWriter());
transformer.transform(new DOMSource(document), result);

System.out.println(result.getWriter());

// 結果
// ↓
//<root>abcd</root>

static TransformerFactory newInstance (String factoryClassName, ClassLoader classLoader)

ファクトリ・クラス名からTransformerFactoryの新しいインスタンスを取得します。

おそらくサードパーティ製のパーサを使うときのためのAPIです。
本記事ではコード例は割愛します。

abstract Templates newTemplates (Source source)

Sourceを処理して、ソースのコンパイル表現であるTemplatesオブジェクトにします。

final var xml = """
        <root>abcd</root>
        """;

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

final var xsl = """
        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
          <xsl:output omit-xml-declaration="yes"/>

          <xsl:template match="root">
            <xxx>
              <xsl:value-of select="." />
            </xxx>
          </xsl:template>

        </xsl:stylesheet>
        """;

final var transformerFactory = TransformerFactory.newInstance();
final var templates = transformerFactory.newTemplates(
        new StreamSource(new ByteArrayInputStream(xsl.getBytes())));

final var transformer = templates.newTransformer();

final var result = new StreamResult(new StringWriter());
transformer.transform(new DOMSource(document), result);

System.out.println(result.getWriter());

// 結果
// ↓
//<xxx>abcd</xxx>

abstract Transformer newTransformer ()

ResultへのSourceのコピーを実行する新しいTransformerを作成します、たとえば、"「アイデンティティ変換」"。

このメソッドの使用例は、newInstance() にまとめて記載しました。
そちらのAPI使用例をご参照ください。

abstract Transformer newTransformer (Source source)

SourceをTransformer Objectに処理します。

このメソッドの使用例は、getAssociatedStylesheet(Source source, String media, String title, String charset) にまとめて記載しました。
そちらのAPI使用例をご参照ください。

abstract void setAttribute (String name, Object value)

ユーザーがベースとなる実装に特定の属性を設定できるようにします。

final var file = Path.of("R:", "java-work", "sample.xsl");
System.out.println(file); // R:\java-work\sample.xsl

Files.writeString(file, """
        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
          <xsl:output omit-xml-declaration="yes" />

          <xsl:template match="root">
            <xxx>
              <xsl:value-of select="." />
            </xxx>
          </xsl:template>

        </xsl:stylesheet>
        """);

final var xml = """
        <root>abcd</root>
        """;

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

final var xsl = """
        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
          <xsl:import href="file:///R:/java-work/sample.xsl"/>
        </xsl:stylesheet>
        """;

final var transformerFactory = TransformerFactory.newInstance();

{
    // 標準のデフォルトは "all"
    final var ret = transformerFactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
    System.out.println(ret); // "all"

    final var transformer = transformerFactory.newTransformer(
            new StreamSource(new ByteArrayInputStream(xsl.getBytes())));

    final var result = new StreamResult(new StringWriter());
    transformer.transform(new DOMSource(document), result);

    System.out.println(result.getWriter());

    // 結果
    // ↓
    //<xxx>abcd</xxx>
}

// すべての外部スタイルシート読み込みを拒否します。
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");

{
    final var ret = transformerFactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
    System.out.println(ret); // ""

    try {
        final var transformer = transformerFactory.newTransformer(
                new StreamSource(new ByteArrayInputStream(xsl.getBytes())));
    } catch (TransformerConfigurationException e) {
        System.out.println(e);
    }

    // 結果
    // ↓
    //javax.xml.transform.TransformerConfigurationException: line 2:
    //  accessExternalStylesheetプロパティで設定された制限により'file'アクセスが
    //  許可されていないため、スタイルシート・ターゲット'sample.xsl'を読み取れま
    //  せんでした。
}

abstract void setErrorListener (ErrorListener listener)

TransformerFactoryのエラー・イベント・リスナーを設定します。TransformerFactoryは、変換自体のためではなく、変換命令を処理するために使用されます。

// 意図的にエラーを起こすために、属性名として許容されていない"xmlns"を追加します。
final var xsl = """
        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

          <xsl:template match="/">
            <xsl:attribute name="xmlns"/>
          </xsl:template>

        </xsl:stylesheet>
        """;

final var transformerFactory = TransformerFactory.newInstance();

System.out.println(transformerFactory.getErrorListener() != null); // true

final var listener = new ErrorListener() {
    @Override
    public void warning(TransformerException exception) {
        System.out.println("ErrorListener warning : " + exception);
    }

    @Override
    public void error(TransformerException exception) {
        System.out.println("ErrorListener error : " + exception);
    }

    @Override
    public void fatalError(TransformerException exception) {
        System.out.println("ErrorListener fatalError : " + exception);
    }
};

transformerFactory.setErrorListener(listener);
System.out.println(listener == transformerFactory.getErrorListener()); // true

try {
    final var transformer = transformerFactory.newTransformer(
            new StreamSource(new ByteArrayInputStream(xsl.getBytes())));
} catch (TransformerConfigurationException e) {
    System.out.println("TransformerConfigurationException : " + e);
}

// 結果
// ↓
//ErrorListener error : javax.xml.transform.TransformerException:
// line 4: 属性'xmlns'を呼び出すことはできません
//ErrorListener fatalError : javax.xml.transform.TransformerConfigurationException:
// line 4: 属性'xmlns'を呼び出すことはできません
//TransformerConfigurationException : javax.xml.transform.TransformerConfigurationException:
// line 4: 属性'xmlns'を呼び出すことはできません

abstract void setFeature (String name, boolean value)

このファクトリによって生成されたTransformerFactoryおよびTransformerまたはTemplateの機能を設定します。

関連API : setAttribute(String name, Object value)

final var transformerFactory = TransformerFactory.newInstance();

System.out.println(transformerFactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)); // false
System.out.println(transformerFactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_DTD)); // "all"
System.out.println(transformerFactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET)); // "all"

transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

System.out.println(transformerFactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)); // true
System.out.println(transformerFactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_DTD)); // ""
System.out.println(transformerFactory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET)); // ""

abstract void setURIResolver (URIResolver resolver)

document()、xsl:import、またはxsl:includeで使用されるURIを解決するために変換時にデフォルトで使用されるオブジェクトを設定します。

final var sampleX = Path.of("R:", "java-work", "sample-x.xsl");
System.out.println(sampleX); // R:\java-work\sample-x.xsl

Files.writeString(sampleX, """
        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

          <xsl:template match="root">
            <xxx>
              <xsl:value-of select="." />
            </xxx>
          </xsl:template>

        </xsl:stylesheet>
        """);

final var sampleY = Path.of("R:", "java-work", "sample-y.xsl");
System.out.println(sampleY); // R:\java-work\sample-y.xsl

Files.writeString(sampleY, """
        <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

          <xsl:template match="root">
            <yyy>
              <xsl:value-of select="." />
            </yyy>
          </xsl:template>

        </xsl:stylesheet>
        """);

final var xml = """
        <root>abcd</root>
        """;

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

final var xsl = """
        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
          <xsl:import href="file:///R:/java-work/sample-x.xsl"/>
          <xsl:output omit-xml-declaration="yes"/>
        </xsl:stylesheet>
        """;

final var transformerFactory = TransformerFactory.newInstance();

{
    System.out.println(transformerFactory.getURIResolver()); // null

    final var transformer = transformerFactory.newTransformer(
            new StreamSource(new ByteArrayInputStream(xsl.getBytes())));

    final var result = new StreamResult(new StringWriter());
    transformer.transform(new DOMSource(document), result);

    System.out.println(result.getWriter());

    // 結果
    // ↓
    //<xxx>abcd</xxx>
}

transformerFactory.setURIResolver(new URIResolver() {
    @Override
    public Source resolve(String href, String base) {
        if ("file:///R:/java-work/sample-x.xsl".equals(href)) {
            return new StreamSource("file:///R:/java-work/sample-y.xsl");
        }
        return null;
    }
});

{
    System.out.println(transformerFactory.getURIResolver() != null); // true

    final var transformer = transformerFactory.newTransformer(
            new StreamSource(new ByteArrayInputStream(xsl.getBytes())));

    final var result = new StreamResult(new StringWriter());
    transformer.transform(new DOMSource(document), result);

    System.out.println(result.getWriter());

    // 結果
    // ↓
    //<yyy>abcd</yyy>
}

関連記事

ページの先頭へ