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

kmb7vmvb  于 2023-02-18  发布在  Java
关注(0)|答案(1)|浏览(129)

我遇到了以下问题:

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

现在,我通过使用一个单独的字节流来解析片段,我还 Package 了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出了什么问题?
    1.我可以优化Saxon转换器,使其对部分xml进行操作吗?我是否真的需要 Package XMLOutputStream以使转换器不会写入打开/关闭文档或完全关闭流?
    1.我是否正确定义了名称空间(使用setPrefix和writeNameSpace)。
    1.在使用JAXB编组器时,我可以在编组器上设置如下属性:JAXB_FORMATTED_OUTPUT,JAXB_FRAGMENT.这个解决方案也可以这样做吗?
yhived7q

yhived7q1#

注意,您可以使用XMLStreamWriter的Saxon实现来代替您正在使用的(Processor.newSerializer().getXMLStreamWriter()),这可能会给予您更多的控制权,并可能解决名称空间问题。
您可以尝试提供new net.sf.saxon.stax.ReceiverToXMLStreamWriter(writer),而不是将new StaxResult(writer)作为transform()的第二个参数,然后您可能可以将ReceiverToXMLStreamWriter子类化,这样startDocument()endDocument()调用就什么也不做了。
至于XMLStreamWriter对名称空间的处理,我担心API规范非常模糊。我发现参考http://veithen.github.io/2009/11/01/understanding-stax.html是有帮助的,尽管它没有官方地位。我不能保证Saxon解释是API作者想要的(没有参考实现或测试套件)。

相关问题