Java 内置数据解析器,用于 JSON 或 XML 或其他 [已关闭]

2022-09-05 00:16:38

我想读取存储在文件中的数据。我还没有决定存储它的格式,但我正在寻找一种易于解析的格式。最初我以为我会使用JSON,但似乎Java没有内置的JSON解析器。

存储的数据将是一堆记录,每条记录由一组字段组成。因此,它不够简单,无法存储在可以逐行读取的文本文件中。这就是为什么我认为我需要像JSON这样的东西。但我不想仅仅为了解析格式而添加外部库。有什么建议吗?我是Java的新手。


答案 1

虽然Java没有标准的JSON解析库,但有几个库可用,快速,可靠且易于使用。许多还允许您使用标准对象绑定方法,例如 JAXB 使用注释定义反序列化映射。

我自己更喜欢杰克逊。Google-GSon也很受欢迎,你可以看到有些人在这个问题中如何比较两者。

您可能希望减少对使用外部库的恐惧。利用具有所需功能的现有库几乎总是更好,而不是编写自己的库。使用 MavenIvy 等工具自动计算和下载项目定义中的依赖项,真的没有理由担心使用库。

话虽如此,在Java XML支持的当前状态下,您应该发现XML具有相同的可访问性。这个答案提供了一个使用javax.xml解析器.DocumentBuilder生成DOM的简单示例。


答案 2

正如许多其他人所指出的那样,Java不会将标准的JSON解析库作为JDK的一部分,因此,如果您想使用绝对没有依赖项的JDK捆绑技术,您有3个XML解析选择:

  • XPathFactory - 基于 XPath 的解析。将整个 XML 读入内存中的数据结构中,并允许您使用 XPath 表达式语言对其执行查询。这可能是最慢和最占用内存的,但是,查询数据最方便的方法之一。你不会用这个来编写股票交易应用程序,但是如果你只需要一个大配置文件中的数据,它非常方便(尽管对于配置,还有许多其他特定的库比滚动你自己的更容易)。
  • DocumentBuilder - 基于 DOM 的解析。将整个 XML 读取到内存中的数据结构中,您可以根据需要查询和遍历。第二慢且相当内存密集,但如果你想/需要XML DOM留在内存中以便你可以对它进行操作,这是必要的。如果您想读取,查询,进行更改并将DOM写回为修改后的XML文件,也很方便。
  • SAXParser - 基于 SAX 的解析。几乎是最快的。从上到下解析 XML,每次命中相应元素时调用 ContentHandler 实现中的存根方法(在解析时提供)。它基本上就像一个健谈的人告诉你他们正在做的一切。由您来实现存根方法,以便在找到数据时实际对它传递给您的数据执行某些操作。
  • XMLStreamReader - 最快的解析方法,并使用最低的开销。这是Java中XML解析的新金子。它类似于 STAX,但不是每次找到新内容时都调用 stubbed 方法,而是翻录 XML 文件,并在看到新内容时通知调用方其修改后的状态,但在您要求它之前,它不会对内容执行任何操作。例如,它会说“现在我正在查看一个打开的标签......现在是一个关闭的标签...现在一些字符...现在评论...”除非你要求它提供有关它所点击的那些元素的信息(获取属性,字符等),否则它永远不会真正解析并处理它们,它只是跳过它们。

现在,话虽如此,使用这些API,特别是如果你是新手,并不是世界上最直观的。如果你以前在Java中做过XML解析,那你就没问题了。

如果您考虑使用一个小型的第三方JAR,我将向您介绍我的Simple Java XML Parser(SJXP)库。它为您提供了XPath的易用性以及STAX解析的性能;老实说(我是公正的,认真的) - 这真是太棒了。

我花了一年多的时间研究这个问题,同时编写了一个非常强大的Feed解析系统,该系统从基于SAX的系统开始,然后转移到STAX,我越是研究它,我就越意识到我是多么容易地用简单的规则抽象出STAX的痛苦。

您可以查看用法示例,但您基本上定义了匹配规则,例如“/图书馆/书籍/标题”将解析所有标签内容;您可以解析属性甚至名称空间限定值(是的,它也支持命名空间!

下面是一个 RSS 源解析器示例:

IRule linkRule = new DefaultRule(Type.CHARACTER, "/rss/channel/item/link") {
    @Override
    public void handleParsedCharacters(XMLParser parser, String text, Object userObject) {
        // Also store the link, or something equivalently fancy
    }
}

然后,只需在创建该规则时将其传递给解析器,如下所示:

XMLParser parser = new XMLParser(linkRule);

你完成了;只需通过解析方法向解析器提供您的XML文件,每次匹配该路径时,您都会获得回调。

我已经对STAX之上的库的开销进行了基准测试,分析和优化,以至于它几乎不存在。实际的补丁匹配是通过缓存的哈希代码完成的,所以我甚至没有在解析器中进行字符串比较。

非常快,可以在Android上运行。

如果你想做JSON,我强烈建议使用GSON。Jackson更快,但API比GSON API复杂37倍。与使用GSON相比,您将花费更多的时间来弄清楚在杰克逊中需要使用哪些类。

此外,自上次GSON版本和流解析器的重写以来,速度差距已经缩小了很多;您可以使用他们的流解析器impl来获得接近杰克逊的解析速度,如果这很重要的话。

话虽如此,如果您需要超越任何东西的终极速度,并且这是优先事项#1,那么请使用Jackson。