我遇到了以下问题:
- 大型输出文件 (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>
问题:
- XMLStreamWriter 似乎忽略了属性 IS_REPAIRING_NAMESPACES。怎么了?
- 我能否优化 Saxon 转换器,使其在部分 xml 上运行。因此:我真的需要包装 XMLOutputStream 以便转换器不会写入打开/关闭文档或完全关闭流吗?
- 我是否正确定义了 namespace (使用 setPrefix 和 writeNameSpace)。
- 使用 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/