4. JSON字符串是如何被解析的?JsonParser了解一下(中)

简介: 4. JSON字符串是如何被解析的?JsonParser了解一下(中)

JsonParser的Feature


它是JsonParser的一个内部枚举类,共15个枚举值:


public enum Feature {
  AUTO_CLOSE_SOURCE(true),
  ALLOW_COMMENTS(false),
  ALLOW_YAML_COMMENTS(false),
  ALLOW_UNQUOTED_FIELD_NAMES(false),
  ALLOW_SINGLE_QUOTES(false),
  @Deprecated
  ALLOW_UNQUOTED_CONTROL_CHARS(false),
  @Deprecated
  ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER(false),
  @Deprecated
  ALLOW_NUMERIC_LEADING_ZEROS(false),
  @Deprecated
  ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS(false),
  @Deprecated
  ALLOW_NON_NUMERIC_NUMBERS(false),
  @Deprecated
  ALLOW_MISSING_VALUES(false),
  @Deprecated
  ALLOW_TRAILING_COMMA(false),
  STRICT_DUPLICATE_DETECTION(false),
  IGNORE_UNDEFINED(false),
  INCLUDE_SOURCE_IN_LOCATION(true);
}


小贴士:枚举值均为bool类型,括号内为默认值


每个枚举值都控制着JsonParser不同的行为。下面分类进行解释


底层I/O流相关


自2.10版本后,使用StreamReadFeature#AUTO_CLOSE_SOURCE代替


Jackson的流式API指的是I/O流,所以即使是读,底层也是用I/O流(Reader)去读取然后解析的。


AUTO_CLOSE_SOURCE(true)


原理和JsonGenerator的AUTO_CLOSE_TARGET(true)一样,不再解释,详见上篇文章对应部分。


支持非标准格式


JSON是有规范的,在它的规范里并没有描述到对注释的规定、对控制字符的处理等等,也就是说这些均属于非标准行为。比如这个JSON串:


{
  "name" : "YourBarman", // 名字
  "age" : 18 // 年龄
}


你看,若你这么写IDEA都会飘红提示你:


image.png

但是,在很多使用场景(特别是JavaScript)里,我们会在JSON串里写注释(属性多时尤甚)那么对于这种串,JsonParser如何控制处理呢?它提供了对非标准JSON格式的兼容,通过下面这些特征值来控制。

ALLOW_COMMENTS(false)


自2.10版本后,使用JsonReadFeature#ALLOW_JAVA_COMMENTS代替


是否允许/* */或者//这种类型的注释出现。


@Test
public void test4() throws IOException {
    String jsonStr = "{\n" +
            "\t\"name\" : \"YourBarman\", // 名字\n" +
            "\t\"age\" : 18 // 年龄\n" +
            "}";
    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {
      // 开启注释支持
        // jsonParser.enable(JsonParser.Feature.ALLOW_COMMENTS);
        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("name".equals(fieldname)) {
                jsonParser.nextToken();
                System.out.println(jsonParser.getText());
            } else if ("age".equals(fieldname)) {
                jsonParser.nextToken();
                System.out.println(jsonParser.getIntValue());
            }
        }
    }
}


运行程序,抛出异常:


com.fasterxml.jackson.core.JsonParseException: Unexpected character ('/' (code 47)): maybe a (non-standard) comment? (not recognized as one since Feature 'ALLOW_COMMENTS' not enabled for parser)
 at [Source: (String)"{
  "name" : "YourBarman", // 名字
  "age" : 18 // 年龄
}"; line: 2, column: 26]

放开注释的代码,再次运行程序,正常work。


ALLOW_YAML_COMMENTS(false)


自2.10版本后,使用JsonReadFeature#ALLOW_YAML_COMMENTS代替


顾名思义,开启后将支持Yaml格式的的注释,也就是#形式的注释语法。


ALLOW_UNQUOTED_FIELD_NAMES(false)


自2.10版本后,使用JsonReadFeature#ALLOW_UNQUOTED_FIELD_NAMES代替


是否允许属性名不带双引号"",比较简单,示例略。


ALLOW_SINGLE_QUOTES(false)


自2.10版本后,使用JsonReadFeature#ALLOW_SINGLE_QUOTES代替


是否允许属性名支持单引号,也就是使用''包裹,形如这样:


{
    'age' : 18
}


ALLOW_UNQUOTED_CONTROL_CHARS(false)

自2.10版本后,使用JsonReadFeature#ALLOW_UNESCAPED_CONTROL_CHARS代替


是否允许JSON字符串包含非引号控制字符(值小于32的ASCII字符,包含制表符和换行符)。 由于JSON规范要求对所有控制字符使用引号,这是一个非标准的特性,因此默认禁用。


那么,哪些字符属于控制字符呢?做个简单科普:我们一般说的ASCII码共128个字符(7bit),共分为两大类


控制字符


控制字符,也叫不可打印字符。第0~32号及第127号(共34个)是控制字符,例如常见的:LF(换行)、CR(回车)、FF(换页)、DEL(删除)、BS(退格)等都属于此类。


控制字符大部分已经废弃不用了,它们的用途主要是用来操控已经处理过的文字,ASCII值为8、9、10 和13 分别转换为退格、制表、换行和回车字符。它们并没有特定的图形显示,但会依不同的应用程序,而对文本显示有不同的影响。


话外音:你看不见我,但我对你影响还蛮大


非控制字符


也叫可显示字符,或者可打印字符,能从键盘直接输入的字符。比如0-9数字,逗号、分号这些等等。


话外音:你肉眼能看到的字符就属于非控制字符


ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER(false)


自2.10版本后,使用JsonReadFeature#ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER代替


是否允许**反斜杠**转义任何字符。这句话不是非常好理解,看下面这个例子:


@Test
public void test4() throws IOException {
    String jsonStr = "{\"name\" : \"YourB\\'atman\" }";
    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {
        // jsonParser.enable(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER);
        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("name".equals(fieldname)) {
                jsonParser.nextToken();
                System.out.println(jsonParser.getText());
            }
        }
    }
}


运行程序,报错:


com.fasterxml.jackson.core.JsonParseException: Unrecognized character escape ''' (code 39)
 at [Source: (String)"{"name" : "YourB\'atman" }"; line: 1, column: 19]
 ...

放开注释掉的代码,再次运行程序,一切正常,输出:YourB'atman。


ALLOW_NUMERIC_LEADING_ZEROS(false)


自2.10版本后,使用JsonReadFeature#ALLOW_LEADING_ZEROS_FOR_NUMBERS代替


是否允许像00001这样的“数字”出现(而不报错)。看例子:


@Test
public void test5() throws IOException {
    String jsonStr = "{\"age\" : 00018 }";
    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {
        // jsonParser.enable(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS);
        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("age".equals(fieldname)) {
                jsonParser.nextToken();
                System.out.println(jsonParser.getIntValue());
            }
        }
    }
}


运行程序,输出:

com.fasterxml.jackson.core.JsonParseException: Invalid numeric value: Leading zeroes not allowed
 at [Source: (String)"{"age" : 00018 }"; line: 1, column: 11]
 ...


放开注掉的代码,再次运行程序,一切正常。输出18。


ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS(false)


自2.10版本后,使用


JsonReadFeature#ALLOW_LEADING_DECIMAL_POINT_FOR_NUMBERS代替


是否允许小数点.打头,也就是说.1这种小数格式是否合法。默认是不合法的,需要开启此特征才能支持,例子就略了,基本同上。


ALLOW_NON_NUMERIC_NUMBERS(false)


自2.10版本后,使用JsonReadFeature#ALLOW_NON_NUMERIC_NUMBERS代替


是否允许一些解析器识别一组**“非数字”(如NaN)**作为合法的浮点数值。这个属性和上篇文章的JsonGenerator#QUOTE_NON_NUMERIC_NUMBERS特征值是遥相呼应的。


@Test
public void test5() throws IOException {
    String jsonStr = "{\"percent\" : NaN }";
    JsonFactory factory = new JsonFactory();
    try (JsonParser jsonParser = factory.createParser(jsonStr)) {
        // jsonParser.enable(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS);
        while (jsonParser.nextToken() != JsonToken.END_OBJECT) {
            String fieldname = jsonParser.getCurrentName();
            if ("percent".equals(fieldname)) {
                jsonParser.nextToken();
                System.out.println(jsonParser.getFloatValue());
            }
        }
    }
}


运行程序,抛错:


/

com.fasterxml.jackson.core.JsonParseException: Non-standard token 'NaN': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow
 at [Source: (String)"{"percent" : NaN }"; line: 1, column: 17]


放开注释掉的代码,再次运行,一切正常。输出:

NaN


小贴士:NaN也可以表示一个Float对象,是的你没听错,即使它不是数字但它也是Float类型。具体你可以看看Float源码里的那几个常量

相关文章
|
2月前
|
JSON 人工智能 Go
在Golang中序列化JSON字符串的教程
在Golang中,使用`json.Marshal()`可将数据结构序列化为JSON格式。若直接对JSON字符串进行序列化,会因转义字符导致错误。解决方案包括使用`[]byte`或`json.RawMessage()`来避免双引号被转义,从而正确实现JSON的序列化与反序列化。
114 7
|
6月前
|
数据采集 JSON 数据可视化
JSON数据解析实战:从嵌套结构到结构化表格
在信息爆炸的时代,从杂乱数据中提取精准知识图谱是数据侦探的挑战。本文以Google Scholar为例,解析嵌套JSON数据,提取文献信息并转换为结构化表格,通过Graphviz制作技术关系图谱,揭示文献间的隐秘联系。代码涵盖代理IP、请求头设置、JSON解析及可视化,提供完整实战案例。
412 4
JSON数据解析实战:从嵌套结构到结构化表格
|
6月前
|
存储 机器学习/深度学习 缓存
🚀 力扣热题 394:字符串解码(详细解析)(Go语言版)
文章提供了两种解法:栈结构和递归解法。栈解法通过维护数字栈与字符串栈,依次处理 `[` 和 `]`,构造解码结果;递归解法则利用函数调用逐层解析嵌套结构。两者时间复杂度均为 $O(n)$,空间复杂度也为 $O(n)$。栈解法直观易懂,适合初学者;递归解法优雅简洁,适合处理深度嵌套规则。掌握这两种方法,可灵活应对类似问题,提升解题能力。
186 11
|
8月前
|
JSON 前端开发 搜索推荐
关于商品详情 API 接口 JSON 格式返回数据解析的示例
本文介绍商品详情API接口返回的JSON数据解析。最外层为`product`对象,包含商品基本信息(如id、name、price)、分类信息(category)、图片(images)、属性(attributes)、用户评价(reviews)、库存(stock)和卖家信息(seller)。每个字段详细描述了商品的不同方面,帮助开发者准确提取和展示数据。具体结构和字段含义需结合实际业务需求和API文档理解。
|
8月前
|
JSON 小程序 UED
微信小程序 app.json 配置文件解析与应用
本文介绍了微信小程序中 `app.json` 配置文件的详细
1225 12
|
8月前
|
JSON 缓存 API
解析电商商品详情API接口系列,json数据示例参考
电商商品详情API接口是电商平台的重要组成部分,提供了商品的详细信息,支持用户进行商品浏览和购买决策。通过合理的API设计和优化,可以提升系统性能和用户体验。希望本文的解析和示例能够为开发者提供参考,帮助构建高效、可靠的电商系统。
262 12
|
7月前
|
JSON JavaScript 前端开发
处理从API返回的JSON数据时返回Unicode编码字符串怎么处理
在处理API返回的JSON数据时,遇到类似`\u7f51\u7edc\u8fde\u63a5\u9519\u8bef`的Unicode编码字符串,可使用JavaScript内置方法转换为可读文字。主要方法包括:1. 使用`JSON.parse`自动解析;2. 使用`decodeURIComponent`和`escape`组合解码;3. 在API调用中直接处理响应数据。这些方法能有效处理多语言内容,确保正确显示非ASCII字符。
|
27天前
|
JSON API 数据格式
淘宝/天猫图片搜索API接口,json返回数据。
淘宝/天猫平台虽未开放直接的图片搜索API,但可通过阿里妈妈淘宝联盟或天猫开放平台接口实现类似功能。本文提供基于淘宝联盟的图片关联商品搜索Curl示例及JSON响应说明,适用于已获权限的开发者。如需更高精度搜索,可选用阿里云视觉智能API。
|
25天前
|
JSON API 数据安全/隐私保护
深度分析淘宝卖家订单详情API接口,用json返回数据
淘宝卖家订单详情API(taobao.trade.fullinfo.get)是淘宝开放平台提供的重要接口,用于获取单个订单的完整信息,包括订单状态、买家信息、商品明细、支付与物流信息等,支撑订单管理、ERP对接及售后处理。需通过appkey、appsecret和session认证,并遵守调用频率与数据权限限制。本文详解其使用方法并附Python调用示例。
|
1月前
|
JSON 缓存 API
淘宝店铺所有商品API,json数据返回
淘宝店铺所有商品API的JSON数据返回通常包含商品的基本信息、动态数据以及分页信息等。以下是一个详细的JSON数据返回示例,以及相关字段的说明

推荐镜像

更多
  • DNS