gpt4 book ai didi

java - 为什么我的 Transformer 输出其样式表,而不是其表示的转换?

转载 作者:行者123 更新时间:2023-11-30 08:18:56 25 4
gpt4 key购买 nike

我的问题简述:当我从有效的样式表构建 Transformer 并调用其 transform(input, output) 方法时,我似乎得到了以下内容样式表本身存储在output中,而不是input的转换。

(底部更新。这个问题现在是 answered)

我正在使用 Java 8 对基本 javax.xml.transform API 进行所有可能的基本调用中最基本的操作。

以下是所有详细信息。

我有一个基本的 XML 文档,如下所示(正如我们将看到的,这并不重要):

<?xml version="1.0" encoding="UTF-8"?>
<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>

我有一个看起来像这样的 XSLT 文件,尽管我们很快就会看到它并不重要:

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

(将这些原始值插入几个不同的 online XSLT testers 会产生我想要的类型的转换输出。将虚假字符放入 XSLT 文件中会产生错误,因此它会成功读取和解析,因此它是一个有效的样式表文件.)

如果我运行以下(基本)Java 转换代码,则输出样式表,而不是它所代表的转换。 Whiskey Tango Foxtrot。

我一生都无法理解这是为什么。这是代码,然后我将粘贴输出:

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

}

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):

*****
<?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>
*****

在这个最基本的教程级示例中我做错了什么?

更新 #1: 在我的示例中,我使用 DOMSource 为样式表构建 Source。如果我改用 StreamSource 来“容纳”我的样式表,我的输出是正确的。为什么是这样?使用 DOMSource 包装作为解析 XSLT 样式表结果的 Document 是否存在本质上的错误?

更新#2:感谢主;有一个related question .

更新 #3: TransformerFactory 允许您在其 newTransformer(Source) 中使用任何 Source 实现方法。但是,如果该 Source 实现恰好是 DOMSource,那么您最好希望调用者使用 namespace aware 生成它。 DocumentBuilderFactory,或者文档转换的结果将是样式表本身。这非常奇怪,而且看起来像是这些 API 设计中的缺陷。

最佳答案

事实证明,尽管 TransformerFactory 允许您使用 Source为您实现stylesheet ,如果您碰巧(当然是在不知不觉中)使用 DOMSource它是由调用者 did not declare his associated DocumentBuilderFactory as namespace-aware 构建的然后您将获得样式表的输出作为您的转换(!)。

这个故事的寓意是:告诉你的调用者要做什么(?!)或者——如果你对转换过程本身有任何控制权——确保你永远不会接受Source这实际上是一个 DOMSource

关于java - 为什么我的 Transformer 输出其样式表,而不是其表示的转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29245370/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com