広告

Java : TransformerFactory (XML) - API使用例

TransformerFactory (Java SE 22 & JDK 22) の使い方まとめです。
ほとんどのメソッドにサンプルコードがあります。
API仕様書のおともにどうぞ。


概要

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

クラス構成

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

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

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

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>

コンストラクタ

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)

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

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();

{
    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 ErrorListener getErrorListener ()

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 boolean getFeature (String name)

機能の値を検索します。

final var factory = TransformerFactory.newInstance();

final var ret1 = factory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING);
System.out.println(ret1); // false

final var ret2 = factory.getAttribute(XMLConstants.ACCESS_EXTERNAL_DTD);
System.out.println(ret2); // "all"

final var ret3 = factory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
System.out.println(ret3); // "all"

factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

final var ret4 = factory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING);
System.out.println(ret4); // true

final var ret5 = factory.getAttribute(XMLConstants.ACCESS_EXTERNAL_DTD);
System.out.println(ret5); // ""

final var ret6 = factory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
System.out.println(ret6); // ""

abstract URIResolver getURIResolver ()

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>
}

final var resolver = 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;
    }
};
transformerFactory.setURIResolver(resolver);

{
    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>
}

static TransformerFactory newDefaultInstance ()

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

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

補足:newInstanceとの違い

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

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

自分の環境(openjdk-22.0.2_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を作成します、たとえば、"「アイデンティティ変換」"。

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>

abstract Transformer newTransformer (Source source)

SourceをTransformer Objectに処理します。

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 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();

{
    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の機能を設定します。

final var factory = TransformerFactory.newInstance();

final var ret1 = factory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING);
System.out.println(ret1); // false

final var ret2 = factory.getAttribute(XMLConstants.ACCESS_EXTERNAL_DTD);
System.out.println(ret2); // "all"

final var ret3 = factory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
System.out.println(ret3); // "all"

factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

final var ret4 = factory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING);
System.out.println(ret4); // true

final var ret5 = factory.getAttribute(XMLConstants.ACCESS_EXTERNAL_DTD);
System.out.println(ret5); // ""

final var ret6 = factory.getAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
System.out.println(ret6); // ""

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>
}

final var resolver = 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;
    }
};
transformerFactory.setURIResolver(resolver);

{
    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>
}

関連記事

ページの先頭へ