Java : TransformerFactory (XML) - API使用例
TransformerFactory (Java SE 22 & JDK 22) の使い方まとめです。
ほとんどのメソッドにサンプルコードがあります。
API仕様書のおともにどうぞ。
概要
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)
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 ()
// 意図的にエラーを起こすために、属性名として許容されていない"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 ()
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 ()
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 ()
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)
おそらくサードパーティ製のパーサを使うときのための API です。
本記事ではコード例は割愛します。
abstract Templates newTemplates (Source source)
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 ()
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)
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)
// 意図的にエラーを起こすために、属性名として許容されていない"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)
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)
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>
}