如何编写基本的JSON解析类

时间:2013-06-12 10:54:55

标签: java json parsing

有人可以指导如何编写一个可以获取JSON数据的类,并尝试将其解析为一个简单的缓冲列表,我们可以从中回读数据吗?

实施例。 JSON

{ name: 'John', age: 56 } 

..将被解析为一个关键值对表

name John
age  56

如何编写一个有助于创建更快更简单的解析方法?

请不要建议任何现有的图书馆。提供解析JSON的概念。

5 个答案:

答案 0 :(得分:22)

这个答案假设您真的想要编写一个解析器并准备投入所需的工作。

您必须从JSON的正式规范开始。我找到了http://www.ietf.org/rfc/rfc4627.txt。这精确地定义了语言。您必须实现规范中的所有内容并为其编写测试。您的解析器必须满足不正确的JSON(与您的一样)并抛出异常。

如果你想编写解析器,请停止,思考,然后不要。让它正常工作需要做很多工作。无论你做什么,做一个正确的工作 - 不完整的解析器是一个威胁,永远不应该分发。

你必须编写符合的代码。以下是规范中的一些短语。如果您不理解它们,您将需要仔细研究并确保理解:

  

“JSON文本应以Unicode编码。默认编码为   UTF-8“。

     

“JSON解析器必须接受符合JSON的所有文本   语法“。

“编码注意事项:UTF-8为8位; UTF-16或UTF-32为二进制

  JSON may be represented using UTF-8, UTF-16, or UTF-32.  When JSON
  is written in UTF-8, JSON is 8bit compatible.  When JSON is
  written in UTF-16 or UTF-32, the binary content-transfer-encoding
  must be used.

  

“任何角色都可能被转义。如果角色在基本中   多语言平面(U + 0000到U + FFFF),然后它可能是
  表示为六个字符的序列:反向固相,然后是
  用小写字母u,后跟四个十六进制数字   编码角色的代码点。十六进制字母A到
  F可以是大写或小写。因此,例如,包含
的字符串   只有一个反向固相字符可以表示为
  “\ u005C”。 “

如果您理解这些并仍想编写解析器,那么请查看其他解析器,并查看其中是否有任何解析器。借用这些用于您自己的应用程序。

如果你仍然敏锐,你应该强烈考虑使用解析器生成器。例如JAVACC,CUP和我首选的工具ANTLR。 ANTLR非常强大,但很难开始。另请参阅Parboiled的建议,我现在推荐。 JSON相对简单,它将是一个有用的练习。大多数解析器生成器生成一个完整的解析器,可以创建可执行代码或生成JSON的解析树。

如果允许您查看它,则在http://www.antlr.org/wiki/display/ANTLR3/JSON+Interpreter使用ANTLR的JSON解析器生成器。我刚刚发现了Parboiled parser-generator for JSON。如果编写解析器的主要原因是学习如何操作,这可能是一个很好的起点。

如果您不允许(或不想)使用解析器生成器,则必须创建自己的解析器。这通常分为两部分:

lexer / tokenizer 。这可以识别语言规范中定义的基本原语。在这种情况下,它必须识别大括号,引号等。它可能还会构建数字的表示。

一个AbstractSyntaxTree http://en.wikipedia.org/wiki/Abstract_syntax_tree,AST)生成器。在这里编写代码来汇编表示JSON抽象的树(例如,空格和curlies已被丢弃)。

当你拥有AST时,应该很容易迭代节点并创建所需的输出。

但编写解析器生成器,即使是像JSON这样的简单语言,也是很多工作。

答案 1 :(得分:6)

如果你的“JSON”真的是这样的话,你应该首先拿一根棒球棒然后敲击它的制作人。严重。

如果真的坚持编写自己的类(为什么?),你可以使用如下界面:

public interface MyParser
{
    boolean parse()
        throws MyParsingException;
    MyParser next();
}

然后,实现将CharBuffer作为参数和地图构建器类;并解析你会做:

final CharBuffer buf = CharBuffer.wrap(yourSource);
final MyMapBuilder builder = new MyMapBuilder();

MyParser parser = new OpenBracketParser(buf, builder);

while (parser.parse())
    parser = parser.next();

// result is builer.build()

这只是一个例子......

第二种解决方案,您希望使用现有的解析工具;在这种情况下,请查看Parboiled。因为用纯Java编写语法,所以比antlr,jflex或其他人更容易使用。

最后,如果你认为足够了,并且决定使用JSON库(你真的应该这样做),那么请使用Jackson,它甚至可以读取这样格式错误的JSON:

public static void main(final String... args)
    throws IOException
{
    final ObjectMapper mapper = new ObjectMapper()
        .configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)
        .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

    final JsonNode node = mapper.readTree("{name: 'John'}");
    System.out.println(node); // {"name":"John"}
}

答案 2 :(得分:5)

我之前写过一篇。步骤进行:

  1. 使用表示JSON文本的字符串。

  2. 创建一个JsonToken类。我叫我的JToken。

  3. 查看步骤#1中的整个文本并解析出JToken。

  4. 以递归方式对您的JToken进行分组和嵌套。

  5. 尝试保持简单统一。所有JToken节点都有一个子数组,可以有0个或更多子节点。如果node是数组,则标记为数组。如果是OBJECT或ARRAY,子数组用于节点的子节点。唯一改变的是它被标记为的东西。还要将所有值保留为字符串类型。这样你只需要一个名为" value"的节点上的一个成员。在完成所有艰苦工作后,可以将其解释为正确的数据类型。

  6. 使用防御性编码和单元测试。编写解析器的所有组件的测试。最好再花3个小时以偏执的方式编写代码,假设你每秒都犯错,而不是花3个小时追捕错误。代码偏执不够,在调试时你很少会花时间沮丧。

  7. 示例代码: 当我在code-eval.com上做一个简单(具有讽刺意味)的挑战时。 有一个json菜单解析挑战。我以为这会是作弊 使用任何内置函数,因为对我来说代码挑战的重点 是测试你的算法问题解决能力。 挑战在于:https://www.codeeval.com/open_challenges/102/

    My Code,它使用从头开始构建的解析器来传递此挑战 的javascript:

    CODE: https://pastebin.com/BReK9iij
    Was not able to post it on stack-overflow because it is too much code.
    Put it in a non-expiring paste-bin post.
    

    注意:此代码可以使用一些改进。其中一些效率非常低 它不会使用Unicode。

    除非您以某种非标准方式解释JSON,否则我不建议您编写自己的JSON解析器。

    例如:我目前正在使用JSONedit来组织基于文本的分支 冒险。我只使用JSON文件格式,因为它是紧凑的,查看器允许我扩展和收缩项目。 GOLang附带的标准解析器并不像我想要的那样解释信息,所以我正在编写自己的解析器。

答案 3 :(得分:0)

public abstract class AbstractMessageObject {
  public String toString() {
    Gson gson = new Gson();
    //here mapping Object class name is prefixed to json message so otherwise knows the mapping object
    return "^" + this.getClass().getName() + "^" + gson.toJson(this);
  }
}

您可以通过扩展此AbstractMessageObject来创建任何bean。每当您想要将该对象解析为json时,您只需要调用toString方法

答案 4 :(得分:0)

我用Kotlin写了一个简单的解析器,它还不完整。但是,它可以作为您自己实施的起点。

感谢@ peter.murray.rust给出的想法,它也受h2database parser的启发。

它主要是逐个字符读取JSON字符串(使用StringReader),并尝试根据预期的JSON令牌进行解析。它实现了读取令牌,未读取char并最终将结果转换为AST的功能。

您可以在github上找到the codetest cases