【问题标题】:Writing XSLT output to the multiple objects in memory将 XSLT 输出写入内存中的多个对象
【发布时间】:2018-05-19 00:38:01
【问题描述】:

我正在使用 XSLT 并将结果写入 Java 中的多个输出,如以下链接所述: link1, link2

在写入文件时,一切正常,但现在我想将输出 XML 存储为 Document 对象或某种 InputStream/String - 除了驱动器上的文件之外的任何内容。使用 Transformer 将文档写入文件,然后将它们读取对象(文档、字符串等) 不是一种选择

我的问题是:我应该在我的 xslt 映射和 java 代码中进行哪些更改才能将输出作为对象而不是驱动器上的文件。 (我想出的唯一解决方案是在这个 XML 上使用两个 XSLT,但这不是优雅的方式)

我的 Java 代码类似于上面链接中的答案。 我正在使用 XSLT 2.0 并使用以下方式进行转换:

transformer.transform(xmlText, new DOMResult());

我也加了

  <xsl:result-document href="{concat($jobName, '_assets.xml')}">
        <xsl:apply-templates select="GetMetadata/Metadata" mode="assets"/>
    </xsl:result-document>
    <xsl:result-document href="{concat($jobName, '_flows.xml')}">
        <xsl:apply-templates select="GetMetadata/Metadata" mode="flows"/>
    </xsl:result-document>

到我的 xsl 地图 [写入文件工作正常]

稍后

正确的实现:(谢谢迈克尔)

public void multipleXMLExtractor(Document inputDom, String xsltPath) throws TransformerException, UnsupportedEncodingException {

Source xmlInput = new DOMSource(inputDom);
Source xsltMap = new StreamSource(new File(xsltPath));
final Map<String, StreamResult> resultsMap = new HashMap<String, StreamResult>();
resultsMap.put("output1", new StreamResult(new ByteArrayOutputStream()));
resultsMap.put("output2", new StreamResult(new ByteArrayOutputStream()));

TransformerFactory tFactory = TransformerFactory.newInstance("net.sf.saxon.TransformerFactoryImpl", XMLviaXSLTransformer.class.getClassLoader());
Transformer transformer = tFactory.newTransformer(xsltMap);
((net.sf.saxon.jaxp.TransformerImpl) transformer).getUnderlyingController().setOutputURIResolver(new OutputURIResolver() {
    @Override
    public OutputURIResolver newInstance() {
        return this;
    }

    @Override
    public Result resolve(String s, String s1) throws TransformerException {
        return resultsMap.get(s);
    }

    @Override
    public void close(Result result) throws TransformerException {
    }
});

StreamResult standardResult = new StreamResult(new ByteArrayOutputStream());
transformer.transform(xmlInput, standardResult);


for (Map.Entry<String, StreamResult> stringStreamResultEntry : resultsMap.entrySet()) {
    System.out.println(stringStreamResultEntry.getKey() + ": " + ((ByteArrayOutputStream) stringStreamResultEntry.getValue().getOutputStream()).toString("UTF-8"));
}

}

【问题讨论】:

  • 请准确告诉我们您使用的是哪个版本的 XSLT 2 处理器。如果它是 Saxon 9 并且您使用 JAXP API 来运行 XSLT 2,那么您可能希望切换 Saxon 9 API 以访问配置(尽管我认为您也可以通过 JAXP 和 Saxon 特定代码来做到这一点)和然后设置saxonica.com/html/documentation/javadoc/net/sf/saxon/…根据需要处理结果文档。
  • "net.sf.saxon.TransformerFactoryImpl" 我正在使用处理器:Saxon - HE 9.8.0-3 并导入 javax.xml ...我仍然不知道如何实现不是输出到文件,而是输出到某个流
  • @MartinHonnen 由于线程安全问题,将OutputURIResolver 设置为Controller 级别而不是Configuration 可能更安全。

标签: java xml xslt saxon


【解决方案1】:

您需要定义一个OutputURIResolver - 这是一个特定于撒克逊的接口,被调用以确定xsl:result-document 的输出目标。它被给定一个 URI 作为输入,并返回一个 JAXP Result 对象,结果文档将写入该对象。

https://www.saxonica.com/documentation/index.html#!javadoc/net.sf.saxon.lib/OutputURIResolver

如果您使用 JAXP API 来控制转换,则必须将 Transformer 对象强制转换为 net.sf.saxon.jaxp.TransformerImpl,然后调用 getUnderlyingController().setOutputURIResolver(),并提供您的 OutputURIResolver 作为参数。

【讨论】:

  • Michael - 我对 OutputURIResolver 的实现有疑问,尤其是 resolve 方法。我找到的实现示例,将文件保存到名为 - href 的基本目录中,即来自 xsl:result-document 的 href。我找不到描述如何处理第二个输出的示例。我猜两者都在结果树中,对吗?我认为我不调用resolve方法,撒克逊人以某种方式调用。所以我只需要正确实现 OutputURIResolver 并将两个 XML 输出都放入 Document obj 中。从结果 obj。你介意帮我解决这个问题吗?
  • 是的,Saxon 调用了resolve() 方法。你的代码看起来不错。您确定名称“output1”和“output2”与您的 xsl:result-document 调用中的 href 值匹配吗?添加一些诊断输出或调试器断点以查看 Saxon 对您的 resolve() 方法所做的调用。在调用 resolve() 时在映射中创建条目会更健壮,而不是尝试预先分配它们。
  • 是的,名称匹配(我在基本 xml 和 xsl 上运行所有内容)。我的 resultsMap 中键“output1”和“output2”的值是空的。 resolve() 可能有问题。也许 close() 不应该为空?
  • 那么调试告诉你什么?是否调用了 resolve(),并使用了哪些参数?
  • 我的 resolve() 没有被调用,只有来自 StandardOutputResolver 类的 resolve() ,所以转换将输出文件保存在一个基本位置。我知道使用 setOutputURIResolver(new OutputURIResolver() {...} 会重载 StandardOutputResolver 中的方法。这就是为什么在我的 resolve() 中我可以对输出做任何我想做的事情 - 在我的例子中,将它们放入 map 中,但它没有'似乎不起作用。也许我对地图或 newInstance() 做错了什么?
猜你喜欢
  • 2021-10-15
  • 2010-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-10
  • 1970-01-01
  • 2018-04-27
  • 1970-01-01
相关资源
最近更新 更多