Java 为什么我的转换器输出它的样式表,而不是它所代表的转换?
简单地说,我的问题是:当我从一个有效的样式表构建一个Java 为什么我的转换器输出它的样式表,而不是它所代表的转换?,java,xslt,Java,Xslt,简单地说,我的问题是:当我从一个有效的样式表构建一个转换器,并调用它的transform(input,output)方法时,我似乎得到了样式表本身存储在output中的内容,而不是input的转换 (在底部更新。这个问题现在是。) 我正在使用Java8对basicjavax.xml.transformAPI进行最基本的基本调用 这里是所有的细节 我有一个基本的XML文档,看起来是这样的(我们将看到,它几乎不重要): print()方法非常简单: private static final void
转换器
,并调用它的transform(input,output)
方法时,我似乎得到了样式表本身存储在output
中的内容,而不是input
的转换
(在底部更新。这个问题现在是。)
我正在使用Java8对basicjavax.xml.transform
API进行最基本的基本调用
这里是所有的细节
我有一个基本的XML文档,看起来是这样的(我们将看到,它几乎不重要):
print()
方法非常简单:
private static final void print(final Document document) throws Exception {
print(document, new BufferedWriter(new OutputStreamWriter(System.out, "UTF-8")), 2);
}
private static final void print(final Document document, final Writer writer, final int indent) throws Exception {
final Transformer transformer = tf.newTransformer();
assertNotNull(transformer);
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", String.valueOf(indent));
transformer.transform(new DOMSource(document), new StreamResult(writer));
}
最后是输出。如您所见,如我所料,首先打印原始文档,然后是显式打印的样式表,如我所料,然后是样式表的规范化版本(WTF):
*****
*****
*****
*****
在这个最基本的教程级示例中,我做错了什么
更新#1:在我的示例中,我使用DOMSource
为我的样式表构建了一个源代码。如果我切换到使用StreamSource
来“存放”我的样式表,我的输出是正确的。为什么会这样?使用DOMSource
包装解析XSLT样式表的文档
是否存在固有的问题
更新#2:感谢上帝;有一个
更新#3:TransformerFactory
允许您在其方法中使用任何源代码
实现。但是如果Source
实现恰好是DOMSource
,那么您最好希望调用者使用DocumentBuilderFactory
生成它,否则文档转换的结果将是样式表本身。这非常奇怪,而且在这些API的设计中有一点缺陷。事实证明,尽管TransformerFactory
允许您为您的应用程序使用一个实现,但如果您碰巧(当然是在不知不觉中)使用了由调用方构造的,那么您将得到样式表的输出作为您的转换(!)
这个故事的寓意是:告诉你的调用者该做什么(?!),或者如果你对转换过程本身有任何控制权,确保你永远不会接受一个源代码,它实际上是一个DOMSource
使用StreamSource
(而不是DOMSource
)会产生不同的结果吗?(我的意思是尝试使用:final Transformer t=tf.newTemplates(new-DOMSource(foobarXsltStream)).newTransformer()
和t.transform(new-DOMSource(foobarStream),result);
)。方法不同,结果可能会给你一个更好的问题线索(这样做也更有效)。是的,这正是问题所在。如果(间接地)在DOMSource
中构建文档的DocumentBuilderFactory
不知道名称空间,那么您将获得样式表作为输出。即使Transformer
中的合同接受任何类型的源代码
。为什么会出现这种情况对我来说仍然是一个谜。虽然答案在经验上可能是正确的(可能是针对JDK附带的Xalan版本),但我不明白为什么会发生这种情况。我希望有一条消息说样式表无效。但这个故事的另一个寓意是,避免像瘟疫一样的死亡。总有更好的选择。我也不知道!当我有时间的时候,我将深入研究Xalan的实现,并跟踪这个问题。我讨厌觉得自己笨手笨脚。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- First the identity transformation. -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="target-store">
<xsl:copy>
<xsl:apply-templates select="@*|node()">
<xsl:with-param name="u" select="'bill'"/>
<xsl:with-param name="p" select="'gates'"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="target-key">
<xsl:param name="u" select="'scott'"/>
<xsl:param name="p" select="'tiger'"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<username><xsl:value-of select="$u"/></username>
<password><xsl:value-of select="$p"/></password>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
public void testRawAPIs() throws Exception {
final ClassLoader ccl = Thread.currentThread().getContextClassLoader();
assertNotNull(ccl);
final URL foobarXml = ccl.getResource("foobar.xml");
assertNotNull(foobarXml);
final URL foobarXslt = ccl.getResource("foobar.xslt");
assertNotNull(foobarXslt);
try (final InputStream foobarStream = new BufferedInputStream(foobarXml.openStream());
final InputStream foobarXsltStream = new BufferedInputStream(foobarXslt.openStream())) {
System.out.println("*****");
// db is set up elsewhere as DocumentFactoryBuilder.newInstance().newDocumentBuilder().
final Document foobarDocument = db.parse(foobarStream);
assertNotNull(foobarDocument);
print(foobarDocument);
System.out.println("*****");
final Document foobarXsltDocument = db.parse(foobarXsltStream);
assertNotNull(foobarXsltDocument);
print(foobarXsltDocument);
System.out.println("*****");
// tf is set up by JUnit elsewhere as TransformerFactory.newInstance().
final Transformer t = tf.newTemplates(new DOMSource(foobarXsltDocument)).newTransformer();
assertNotNull(t);
final DOMResult result = new DOMResult();
t.transform(new DOMSource(foobarDocument), result);
// TODO FIXME: for some reason, this prints out the STYLESHEET. WTF.
print((Document)result.getNode());
System.out.println("*****");
}
private static final void print(final Document document) throws Exception {
print(document, new BufferedWriter(new OutputStreamWriter(System.out, "UTF-8")), 2);
}
private static final void print(final Document document, final Writer writer, final int indent) throws Exception {
final Transformer transformer = tf.newTransformer();
assertNotNull(transformer);
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", String.valueOf(indent));
transformer.transform(new DOMSource(document), new StreamResult(writer));
}
*****
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<doc>
<target-store name="foobar">
<target-key name="abc"/>
<target-key name="def"/>
</target-store>
<testing>
<target-store>
<target-key name="ghi">
<bogus/>
</target-key>
</target-store>
</testing>
</doc>
*****
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- First the identity transformation. -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="target-store">
<xsl:copy>
<xsl:apply-templates select="@*|node()">
<xsl:with-param name="u" select="'bill'"/>
<xsl:with-param name="p" select="'gates'"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="target-key">
<xsl:param name="u" select="'scott'"/>
<xsl:param name="p" select="'tiger'"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<username>
<xsl:value-of select="$u"/>
</username>
<password>
<xsl:value-of select="$p"/>
</password>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
*****
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="target-store">
<xsl:copy>
<xsl:apply-templates select="@*|node()">
<xsl:with-param name="u" select="'bill'"/>
<xsl:with-param name="p" select="'gates'"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="target-key">
<xsl:param name="u" select="'scott'"/>
<xsl:param name="p" select="'tiger'"/>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<username>
<xsl:value-of select="$u"/>
</username>
<password>
<xsl:value-of select="$p"/>
</password>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
*****