java - 将 XSLT 转换后的 XML 片段写入 XMLStreamWriter

标签 java xslt namespaces jaxb saxon

我遇到了以下问题:

  • 大型输出文件 (zip),其中包含一个 xml 文档(“FeatureCollection”)
  • 相对较小的 xml 片段
  • XSLT 转换后,每个片段都需要作为“featureMember”写入 XMLStream
  • 仅在“FeatureCollection”(根)标签上定义命名空间。

现在,我通过使用单独的字节流来解析片段来实现它。我还包装了 XMLStream 以避免 XSLT 转换器 (Saxon) 打开/关闭文档或关闭流。

但是,我觉得解决方案太复杂了。应该可以将 JAXB 上下文作为源(没有中间字节流)。查看代码片段:

        try {
            XMLStreamWriterWrapper writer = getWriter( xmlFile );
            for ( Map.Entry<String, String> entry : prefixMapper.getNamespaces().entrySet() ) {
                writer.setPrefix( entry.getValue(), entry.getKey() );
            }

            writer.getWrapperWriter().writeStartDocument();
            writer.writeStartElement( GML_URI, "FeatureCollection" );

            for ( Map.Entry<String, String> entry : prefixMapper.getNamespaces().entrySet() ) {
                writer.getWrapperWriter().writeNamespace( entry.getValue(), entry.getKey() );
            }

            while ( dtoIterator.hasNext() ) {
                writer.writeStartElement( GML_URI, "featureMember" );
                D dto = dtoIterator.next();
                hideAttributes( dto );

                J jaxb = transformToJaxb( dto );

                Source untransformed = new JAXBSource( jaxbContext, getRootElement( jaxb ) );
                getTransformer().transform( untransformed, new StAXResult( writer) );
                writer.writeEndElement();
            }

            writer.writeEndElement();
            writer.getWrapperWriter().writeEndDocument();
            writer.getWrapperWriter().flush();
            writer.getWrapperWriter().close();
        }
        catch ( IOException | JAXBException | TransformerException | XMLStreamException e ) {
            LOG.error( e );
            throw new IllegalArgumentException( e );
        }
        
private XMLStreamWriterWrapper getWriter( File xmlFile ) throws XMLStreamException, FileNotFoundException, IOException {
    XMLOutputFactory xof = XMLOutputFactory.newFactory();
    xof.setProperty( XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE );

    XMLStreamWriter writer = xof.createXMLStreamWriter( new BufferedOutputStream( new FileOutputStream( xmlFile ) ) );

    return new XMLStreamWriterWrapper( writer );
}           

预期结果(来自未优化的解决方案):

    <?xml version="1.0" ?><gml:FeatureCollection xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:brocom="http://www.broservices.nl/xsd/brocommon/3.0" xmlns:bro="http://www.pdok.nl/bro">
    <gml:featureMember>
        <bro:Characteristics gml:id="BRO_id_1">
            <brocom:broId>id_1</brocom:broId>
        </bro:Characteristics>
    </gml:featureMember>
    <gml:featureMember>
        <bro:Characteristics gml:id="BRO_id_2">
            <brocom:broId>id_2</brocom:broId>
        </bro:Characteristics>
    </gml:featureMember>
</gml:FeatureCollection>

但是结果(来自上面的代码片段)是:

    <?xml version="1.0" ?><gml:FeatureCollection xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:brocom="http://www.broservices.nl/xsd/brocommon/3.0" xmlns:bro="http://www.pdok.nl/bro">
    <gml:featureMember>
        <bro:Characteristics gml:id="BRO_id_1">
            <broId xmlns="http://www.broservices.nl/xsd/brocommon/3.0">id_1</broId>
        </bro:Characteristics>
    </gml:featureMember>
    <gml:featureMember>
        <bro:Characteristics gml:id="BRO_id_2">
            <broId xmlns="http://www.broservices.nl/xsd/brocommon/3.0">id_2</broId>
        </bro:Characteristics>
    </gml:featureMember>
</gml:FeatureCollection>

问题:

  1. XMLStreamWriter 似乎忽略了属性 IS_REPAIRING_NAMESPACES。怎么了?
  2. 我能否优化 Saxon 转换器,使其在部分 xml 上运行。因此:我真的需要包装 XMLOutputStream 以便转换器不会写入打开/关闭文档或完全关闭流吗?
  3. 我是否正确定义了 namespace (使用 setPrefix 和 writeNameSpace)。
  4. 使用 JAXB 编码器时,我可以在编码器上设置属性,例如:JAXB_FORMATTED_OUTPUT、JAXB_FRAGMENT。我也可以这样做吗?

最佳答案

请注意,您可以使用 XMLStreamWriter 的 Saxon 实现来代替您正在使用的实现 (Processor.newSerializer().getXMLStreamWriter())。这可能会给您更多控制权,并可能解决命名空间问题。

与其提供 new StaxResult(writer) 作为 transform() 的第二个参数,不如尝试提供 new net.sf.saxon.stax。 ReceiverToXMLStreamWriter(writer),然后您可以将 ReceiverToXMLStreamWriter 子类化,这样 startDocument()endDocument() 调用什么也不做.

关于命名空间的 XMLStreamWriter 处理,恐怕 API 规范非常晦涩。我发现咨询 http://veithen.github.io/2009/11/01/understanding-stax.html 很有帮助虽然它没有官方地位。我无法保证 Saxon 解释就是 API 作者的意图(没有引用实现或测试套件)。

关于java - 将 XSLT 转换后的 XML 片段写入 XMLStreamWriter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49813192/

相关文章:

java - telegram java 客户端上的 TimeoutException

java - 如何根据类的值将类对象添加到hashMap?

java - 在两个类之间传递变量

java.lang.RuntimeException : Unable to start activity, 传递给另一个 Activity

asp.net - Web.Config 将单个 AppSettings 转换为 ConfigSource

rest - Marklogic REST API - 检索文件内容

c++ - 命名空间内具有函数的循环包含

xml - xsl 1.x如何根据选择更改输出?

c# - 如何从 C# 中单独文件夹中的文件导入命名空间

c# - 手动更改命名空间是错误的吗