1

我必须将一些 CSV 文件(每个 > 600 MB)转换为 XML,同时使用 XSD 动态验证最终结果。

由于每个文件的大小,我使用 InputStreams 读取内容并使用 OutpuStreams 将结果作为 XML 流式传输回我的客户端。

让我们从简单的部分开始......(伪代码)

void transform(final InputStream CSVCustomerStream, final OutputStream outputStream) {
       outputStream.write("<customers>")
       foreach csvCustomerRow in CSVCustomerStream {
            String xmlCustomerRow = csvCustomerRow.toXML();
            outputStream.write(xmlCustomerRow.getBytes();
       }
       outputStream.write("</customers>")

       **MISSING_XMLVALIDATOR.parse(outputStream);**
}

到目前为止,我的源 CSV 文件的每一行都转换为 xml,然后写入输出流。

很容易。

但是,实际上验证 xml 的部分仍然缺失。

为此,我研究了XMLReader的 parse() 方法。唯一的问题是 parse() 仅接受 InputSources,而同时我将要验证的内容流式传输到 OutputStream。

当然,在阅读了整个 CSV 内容之后,我可以通过以下方式将 OutputStream 转换为 InputStream

 new ByteArrayInputStream((outputstream).toByteArray())

但这会立即将价值 600 MB 的 XML 带回内存,违背了流式传输的全部目的。

PS:我无法控制 OutputStream 的确切实现,因为我的代码作为 REST-webservice 运行

    return Response.ok(new StreamingOutput() {
        @Override
        public void write(OutputStream output) throws Exception {
            ....     loading and transforming csv ...

        }
    }).build();
4

2 回答 2

1

测试可能足以确保您的转换生成使用给定 XSD 验证的 XML,或者(正如 Petru Gardea 在评论中所说)您可以使用临时字符串逐个验证。

但是假设您实际上必须即时验证,您可以尝试一些技巧,基本上是通过操纵流。

您正在生产一个OutputStream大概要发送给客户的产品,并且您有一个知道如何执行此操作的流程InputStream(实际上,Reader接口可能会使其中一些更容易,但修复是并行的)。

这意味着您必须“开球” OutputStream,即即时复制它,以便您可以将一个流发送到客户端并使用该副本进行验证解析。你需要InputStream从你复制的OutputStream.

对于“tee”过程,您应该考虑 Apache Commons TeeOutputStream,对于从输出到输入的转换,您可能应该查看PipedInputStreamPipedOutputStream

于 2013-02-23T00:14:50.960 回答
1

根据您的评论,让我提出“最糟糕”的可能场景,即 XSD 被创作为俄罗斯娃娃(即,除了文档根,所有其他元素和类型都在本地定义)。由于这种风格,无法针对 XSD 验证 xmlCustomerRow,因为没有与您的标签匹配的全局元素声明(假设customer)。

<?xml version="1.0" encoding="utf-8" ?>
<!-- XML Schema generated by QTAssistant/XSD Module (http://www.paschidev.com) -->
<xsd:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" xmlns="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="customers">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="customer" minOccurs="0" maxOccurs="unbounded">
                    <xsd:complexType>

                    </xsd:complexType>
                </xsd:element>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

不过,解决方案并不那么复杂。看看这个修改后的 XSD:

<?xml version="1.0" encoding="utf-8" ?>
<!-- XML Schema generated by QTAssistant/XSD Module (http://www.paschidev.com) -->
<xsd:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" xmlns="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="customers">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="customer" minOccurs="0" maxOccurs="unbounded">
                    <xsd:complexType>

                    </xsd:complexType>
                </xsd:element>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
    <xsd:element name="customer">
        <xsd:complexType>

        </xsd:complexType>
    </xsd:element>
</xsd:schema>

对于此设置,您只需将原始 XSD 作为 XML 打开,克隆customer元素,删除其 minOccurs/maxOccurs 属性,然后将其作为子元素插入schema(它将是 XML 中的文档元素)。这里的想法是您可以即时或手动进行重构等。

总是有可能你不必做任何事情,即如果customer元素已经是全局的,像这样:

<?xml version="1.0" encoding="utf-8" ?>
<!-- XML Schema generated by QTAssistant/XSD Module (http://www.paschidev.com) -->
<xsd:schema targetNamespace="http://tempuri.org/XMLSchema.xsd" xmlns="http://tempuri.org/XMLSchema.xsd" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <xsd:element name="customers">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element ref="customer" minOccurs="0" maxOccurs="unbounded"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
    <xsd:element name="customer">
        <xsd:complexType>

        </xsd:complexType>
    </xsd:element>
</xsd:schema>

可能会出现其他复杂情况,具体取决于您的 XSD 的实际外观,但我可以向您保证,其中没有任何东西可以阻止您进行任何可能需要的重构来实现您想要的。

我宁愿认为能够独立验证每条记录胜过其他任何事情。更重要的是,对于在多核/CPU 机器上运行的海量文件,您可以并行化验证,这将更有效地利用资源来提高吞吐量。

于 2013-02-23T14:49:17.400 回答