【问题标题】:Using xsl:result-document in Java (Sax)在 Java (Sax) 中使用 xsl:result-document
【发布时间】:2014-11-11 15:22:53
【问题描述】:

我确实阅读和测试了很多,但我没有得到一个有效的 java 解决方案:

我现在有一个通过 JAXB 处理的大型 xml 文件(超过 100MB)。目的是每次使用 root 的一个孩子将 xml 拆分为多个 xml。
重要提示:由于文件大小,首选萨克斯风格。

我找到了很多关于 xsl:result-document 的信息,但我发现无法从 java 中运行它,而且我很不确定是否可以将所需的内存保持在较低水平。

这是我的 Java 代码:

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class TestParse {

public static void main(final String[] args) throws Throwable {
    final TransformerFactory factory = TransformerFactory.newInstance();
    final Transformer transformer = factory.newTransformer(new StreamSource("D:\\split.xsl"));

    final StreamSource in = new StreamSource("D:\\input.xml");
    final StreamResult out = new StreamResult("D:\\output.xml");
    transformer.transform(in, out);
}

这是一个示例-xml(“input.xml”):

<?xml version="1.0" encoding="ISO-8859-1"?>
<Taskname>
  <Item attr="ab" attr2="c">
    <MoreNodes>...</MoreNodes>
  </Item>
  <Item attr="xy" attr2="z">
    <MoreNodes>...</MoreNodes>
  </Item>
  <!-- ...and many items more -->
</Taskname>

这是我的 xsl (split.xsl):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:strip-space elements="*"/>
    <xsl:param name="dir" select="'file:///D://'"/>

    <xsl:template match="Item">
        <xsl:result-document href="{$dir}section{position()}.xml" method="xml">
            <Taskname>
            <xsl:copy-of select="." />
            </Taskname>
        </xsl:result-document>
    </xsl:template>

</xsl:stylesheet>

所以一个 result-xml 应该如下所示:

<?xml version="1.0" encoding="ISO-8859-1"?>
<Taskname>
  <Item attr="..." attr2="...">
    <MoreNodes>...</MoreNodes>
  </Item>
 </Taskname>

我的问题:

我现在真的不知道,我怎样才能获得 xslt 的不同输出,除此之外,我需要将它们作为 Streams 而不是作为文件 - 我会逐项需要它们(如 sax 的 endElement)使用更少的内存。

也许,还有比使用 xslt 更好的方法,请告诉我。

【问题讨论】:

  • 对于 XSLT 1.0 和 2.0,即使您使用 SAX 来解析输入 XML,XSLT 处理器也会根据语言的需要构建内存中的树表示。使用 XSLT 3.0(目前正在进行中,尽管 Saxon 9.5 和 9.6 EE 有一些支持),您可以避免构建树。
  • 如果问题只是关于如何将 XSLT 2.0 功能(如 xsl:result-document)与 Java 结合使用,那么答案是使用像 Saxon 9 这样的 XSLT 2.0 处理器,作为开源版本 HE 来自我认为是 saxon.sourceforge.net 或通过 Maven。

标签: java xslt sax


【解决方案1】:

首先,如果您想避免在内存中为源文档构建树,那么您将不得不使用 XSLT 3.0 流式传输来运行它——这意味着您需要 Saxon-EE 许可证。 (不过,用传统的方式处理一个 100Mb 的文件是很可行的,在内存中有一棵树)。

其次,如果您希望 xsl:result-document 的输出被捕获为内存流而不是写入文件存储,那么在 Saxon 中实现此目的的方法是编写并注册一个 OutputURIResolver。这将为每个结果文档调用一次,并且可以指定接收文档的目的地(例如 StreamResult 或 SAXResult)。

【讨论】:

    【解决方案2】:

    我可能会放弃 XSLT 来完成这项任务,而直接使用像 StAX API 这样的东西。但这取决于您最终要对拆分的文件做什么。您在问题中提到了 JAXB,请注意,JAXB Unmarshaller 可以从 StAX XMLStreamReader 读取,这允许您使用一种“半流式”处理模型,您可以通过输入文件进行流式处理Item 一次。假设您有一个代表 Item 元素类型的 Item 类:

    JAXBContext ctx = JAXBContext.newInstance(Item.class);
    Unmarshaller u = ctx.createUnmarshaller();
    XMLInputFactory inFactory = XMLInputFactory.newFactory();
    try(InputStream stream = Files.newInputStream(Paths.get("input.xml"))) {
      XMLStreamReader reader = inFactory.createXMLStreamReader(stream);
      try {
        reader.nextTag(); // the root Taskname start tag
        reader.nextTag(); // the start tag of the first Item, if there is
                          // one, the end of the Taskname if there isn't
        while(reader.getEventType() == XMLStreamConstants.START_ELEMENT) {
          JAXBElement<Item> theItem = u.unmarshal(reader, Item.class);
          // do whatever you want to do with this item
          process(theItem.getValue());
    
          // this is an oddity of the JAXB API - when unmarshalling from
          // a stream reader the reader is left pointing to the event
          // *after* the closing tag, not to the closing tag itself,
          // so whether or not we need to advance to the next tag depends
          // whether there is whitespace between the close of one Item
          // and the start of the next.
          if(reader.getEventType() != XMLStreamConstants.START_ELEMENT &&
               reader.getEventType() != XMLStreamConstants.END_ELEMENT) {
            reader.nextTag();
          }
        }
      } finally {
        reader.close();
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-10-17
      • 1970-01-01
      • 1970-01-01
      • 2022-01-06
      • 2019-08-05
      • 2023-03-18
      • 2016-07-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多