3

有没有办法使用 XMLStreamReader 准确地收集 xml 标签的字节偏移量?

我有一个需要随机访问的大型 xml 文件。我不想将整个内容写入数据库,而是希望使用 XMLStreamReader 运行一次以收集重要标签的字节偏移量,然后稍后能够使用 RandomAccessFile 检索标签内容。

XMLStreamReader 似乎没有办法跟踪字符偏移量。相反,人们建议将 XmlStreamReader 附加到跟踪已读取字节数的阅读器(例如apache.commons.io提供的 CountingInputStream )

例如:

CountingInputStream countingReader = new CountingInputStream(new FileInputStream(xmlFile)) ;
XMLStreamReader xmlStreamReader = xmlStreamFactory.createXMLStreamReader(countingReader, "UTF-8") ;


while (xmlStreamReader.hasNext()) {
    int eventCode = xmlStreamReader.next();

    switch (eventCode) {
        case XMLStreamReader.END_ELEMENT :
            System.out.println(xmlStreamReader.getLocalName() + " @" + countingReader.getByteCount()) ;
    }

}
xmlStreamReader.close();

不幸的是,必须进行一些缓冲,因为上面的代码为多个标签打印出相同的字节偏移量。是否有更准确的方法来跟踪 xml 文件中的字节偏移量(最好不要放弃正确的 xml 解析)?

4

6 回答 6

2

您可以在 XMLStreamReader 上使用 getLocation()(或 XMLEvent.getLocation(),如果您使用 XMLEventReader),但我记得在某处读到它不可靠和不精确。看起来它给出了标签的端点,而不是起始位置。

我有类似的需要精确知道文件中标签的位置,我正在查看其他解析器,看看是否有一个可以保证提供必要的位置精度水平。

于 2010-07-05T02:24:18.770 回答
1

您可以在实际输入流周围使用包装器输入流,简单地推迟到实际 I/O 操作的包装流,但使用各种代码保持内部计数机制来检索当前偏移量?

于 2010-07-04T23:56:41.090 回答
1

不幸的是,Aalto 没有实现 LocationInfo 接口。

最后一个 java VTD-XML ximpleware 实现,目前在sourceforgegithub上的 2.11 提供了一些代码,在每次调用其 IReader 实现的 getChar() 方法后维护一个字节偏移量。

在 VTDGen.java 和 VTDGenHuge.java 中提供了各种字符编码的 IReader 实现

为以下编码提供了 IReader 实现

ASCII;
ISO_8859_1
ISO_8859_10
ISO_8859_11
ISO_8859_12
ISO_8859_13
ISO_8859_14
ISO_8859_15
ISO_8859_16
ISO_8859_2
ISO_8859_3
ISO_8859_4
ISO_8859_5
ISO_8859_6
ISO_8859_7
ISO_8859_8
ISO_8859_9
UTF_16BE
UTF_16LE
UTF8;   
WIN_1250
WIN_1251
WIN_1252
WIN_1253
WIN_1254
WIN_1255
WIN_1256
WIN_1257
WIN_1258

使用 getCharOffset() 方法更新 IReader 并通过将 charCount 成员添加到 VTDGen 和 VTDGenHuge 类的偏移成员并在每个 IReader 实现的每个 getChar() 和 skipChar() 调用时递增它来实现它应该给你一个开始的一个解决方案。

于 2014-04-27T18:02:16.970 回答
0

我想我找到了另一种选择。如果您将switch块替换为以下内容,它将立即转储结束元素标记之后的位置。

        switch (eventCode) {
        case XMLStreamReader.END_ELEMENT :
            System.out.println(xmlStreamReader.getLocalName() + " end@" + xmlStreamReader.getLocation().getCharacterOffset()) ;
        }

该解决方案还要求必须手动计算结束标记的实际开始位置,并且具有不需要外部 JAR 文件的优点。

我无法追踪数据管理中的一些细微的不一致(我认为这与我如何初始化我XMLStreamReader的 .

希望这可以帮助!

于 2010-07-05T01:28:30.870 回答
0

我最近为如何使用 java 在大 XML 文件中查找字符偏移量的类似问题制定了一个解决方案?. 我认为它提供了一个基于 ANTLR 生成的 XML-Parser 的很好的解决方案。

于 2017-05-16T15:08:18.023 回答
0

我刚刚为此度过了一个漫长的周末,并且部分由于这里的一些线索而得到了解决方案。值得注意的是,自从 OP 发布这个问题以来,我认为这在 10 年里并没有变得容易得多。

TL;DR 使用Woodstox和 char 偏移

第一个要解决的问题是,当您询问大多数 XMLStreamReader 实现的当前偏移量时,它们似乎提供了不准确的结果。然而,伍德斯托克斯在这方面似乎坚如磐石。

第二个问题是您使用的实际偏移类型。不幸的是,如果您需要使用多字节字符集,您似乎必须使用字符偏移,这意味着从文件中进行随机访问检索不会非常有效 - 您不能只将指针设置为文件在您的偏移量并开始阅读,您必须通读直到到达偏移量,然后开始提取。可能有一种更有效的方法可以做到这一点,但我还没有想到,但性能对于我的情况是可以接受的。500MB 的文件非常快。

[编辑] 所以这变成了我脑海中的那些分裂之一,我最终编写了一个 FilterReader,它在读取文件时将字节偏移缓冲区保存到字符偏移映射。当我们需要获取字节偏移量时,我们首先向 Woodstox 询问 char 偏移量,然后让自定义阅读器告诉我们 char 偏移量的实际字节偏移量。我们可以从元素的开头和结尾获取字节偏移量,为我们提供我们需要进入的内容,并通过将文件作为 RandomAccessFile 打开来从文件中提取元素。

我为此创建了一个库,它位于GitHubMaven Central上。如果您只想获取重要信息,那么派对技巧就在ByteTrackingReader中。[/编辑]

关于这个还有另一个类似的问题(但接受的答案让我感到害怕和困惑),有些人评论说这整件事是个坏主意,你为什么要这样做?XML 是一种传输机制,您只需将其导入数据库并使用更合适的工具处理数据。在大多数情况下,这是正确的,但如果您正在构建通过 XML 通信的应用程序或集成(在 2020 年仍然很强大),您需要工具来分析和操作交换的文件。我每天都会收到验证提要内容的请求,能够从大量文件中快速提取一组特定的项目,不仅可以验证内容,而且格式本身也是必不可少的。

无论如何,希望这可以为某人节省几个小时,或者至少让他们更接近解决方案。如果你在 2030 年发现这个问题,上帝会帮助你,试图解决同样的问题。

于 2020-09-05T05:53:14.277 回答