chrome代码中base::JSONReader类的阅读分析(一)

1、json语法

      json文本是一个标记(token)序列,标记包含6种结构字符,字符串,数字和3个字面量。

     1)6中结构字符:

          begin-array = ws %x5B ws; [ 左中括号

          begin-object = ws %x7B ws;{ 左大括号

          end-array = ws %x5D ws;]右中括号

          end-object = ws %7D ws;}右大括号

          name-separator = ws %x3A ws; :冒号

          value-separator = ws % 2C ws; ,逗号

     2)字符串:

          字符串用引号作为开头和结尾。

     3)数字包含一个可选的减号为前缀的整数部分,其后面可以有小数部分和/,或者指数部分。

          八进制和十六机制是不允许的,以0开头是不允许的。

     4)3个字符面量:

          a)false;

          b)null;

          c)true;

          三个字面量必须是小写的,其他字面量不允许使用。

     5)对象

     对象结构表示为一对大括号包含着0到多个名/值对(或者叫成员)。

     6)数组

     数组结构表示为一对中括号包含着0到多个值(或者叫元素),值与值之间用逗号分隔。

2、chrome的base::JSONReader类中针上述语法的定义:

class BASE_EXPORT JSONReader {

 public:
 // A struct to hold a JS token.
 class Token {
 public:

 enum Type {
     OBJECT_BEGIN,           // {
     OBJECT_END,             // }
     ARRAY_BEGIN,            // [
     ARRAY_END,              // ]
     STRING,
     NUMBER,
     BOOL_TRUE,              // true
     BOOL_FALSE,             // false
     NULL_TOKEN,             // null
     LIST_SEPARATOR,         // ,
     OBJECT_PAIR_SEPARATOR,  // :
     END_OF_INPUT,
     INVALID_TOKEN,
};

//其他代码暂忽略

};

//其他代码暂忽略

}; 

代码中的定义的枚举类型对应了上面的6种结构字符,字符串,数字和3个字面量。


3、Json的反序列化

     Value* JsonToValue(const std::string& json, bool check_root, bool allow_trailing_comma);

     参数:

     1)json,符合json格式的一个字符串;如果字符串json不符合json的格式,该函数将返回空指针NULL,并且还有一个详细的错误码能够通过error_message()获取;

     2)check_root;如果check_root为true,那么json字符串类型必须是一个对象或者数组,否则json字符串将是一个无效的json类型;

     3)allow_trailing_comma;如果allow_trailing_comma为true,那么json对象或者数组末尾含有的逗号将被忽略。

     返回值:

     通过读取解析字符串json,返回一个指向Value对象的指针。

4、函数Value* JsonToValue(const std::string& json, bool check_root, bool allow_trailing_comma)的实现逻辑

1)函数JSonToValue的实现:

Value* JSONReader::JsonToValue(const std::string& json, bool check_root,
                               bool allow_trailing_comma) {
  // 输入的字符串必须是UTF-8格式的。
  if (!IsStringUTF8(json.c_str())) {
    error_code_ = JSON_UNSUPPORTED_ENCODING;
    return NULL;
  }

  std::wstring json_wide(UTF8ToWide(json));
  start_pos_ = json_wide.c_str();
  if (!json_wide.empty() && start_pos_[0] == 0xFEFF) {
    ++start_pos_;
  }

  json_pos_ = start_pos_;
  allow_trailing_comma_ = allow_trailing_comma;
  stack_depth_ = 0;
  error_code_ = JSON_NO_ERROR;

//依据输入的字符串给出相应的Value类型。

  scoped_ptr<Value> root(BuildValue(check_root));
  if (root.get()) {
    if (ParseToken().type == Token::END_OF_INPUT) {
      return root.release();
    } else {
      SetErrorCode(JSON_UNEXPECTED_DATA_AFTER_ROOT, json_pos_);
    }
  }

 
  if (error_code_ == 0)
    SetErrorCode(JSON_SYNTAX_ERROR, json_pos_);

  return NULL;
}

2)函数BuildValue的实现:

Value* JSONReader::BuildValue(bool is_root) {
  ++stack_depth_;
  if (stack_depth_ > kStackLimit) {
    SetErrorCode(JSON_TOO_MUCH_NESTING, json_pos_);
    return NULL;
  }

   //判断输入的字符串符合哪种json序列(是布尔值,空指针,数字,字符串,数组还是对象)

  Token token = ParseToken();
  // The root token must be an array or an object.
  if (is_root && token.type != Token::OBJECT_BEGIN &&
      token.type != Token::ARRAY_BEGIN) {
    SetErrorCode(JSON_BAD_ROOT_ELEMENT_TYPE, json_pos_);
    return NULL;
  }

  scoped_ptr<Value> node;

  switch (token.type) {
    case Token::END_OF_INPUT:
    case Token::INVALID_TOKEN:
      return NULL;

   //空指针

    case Token::NULL_TOKEN:
      node.reset(Value::CreateNullValue());
      break;

   //布尔值true

    case Token::BOOL_TRUE:
      node.reset(Value::CreateBooleanValue(true));
      break;

   //布尔值false 

   case Token::BOOL_FALSE:
      node.reset(Value::CreateBooleanValue(false));
      break;

   //数字

    case Token::NUMBER:
      node.reset(DecodeNumber(token));
      if (!node.get())
        return NULL;
      break;

    //字符串

    case Token::STRING:
      node.reset(DecodeString(token));
      if (!node.get())
        return NULL;
      break;

    //数组

    case Token::ARRAY_BEGIN:
      {
        json_pos_ += token.length;
        token = ParseToken();

        node.reset(new ListValue());
        while (token.type != Token::ARRAY_END) {
          Value* array_node = BuildValue(false);
          if (!array_node)
            return NULL;
          static_cast<ListValue*>(node.get())->Append(array_node);

          // After a list value, we expect a comma or the end of the list.
          token = ParseToken();
          if (token.type == Token::LIST_SEPARATOR) {
            json_pos_ += token.length;
            token = ParseToken();
            // Trailing commas are invalid according to the JSON RFC, but some
            // consumers need the parsing leniency, so handle accordingly.
            if (token.type == Token::ARRAY_END) {
              if (!allow_trailing_comma_) {
                SetErrorCode(JSON_TRAILING_COMMA, json_pos_);
                return NULL;
              }
              // Trailing comma OK, stop parsing the Array.
              break;
            }
          } else if (token.type != Token::ARRAY_END) {
            // Unexpected value after list value.  Bail out.
            return NULL;
          }
        }
        if (token.type != Token::ARRAY_END) {
          return NULL;
        }
        break;
      }

    //对象

    case Token::OBJECT_BEGIN:
      {
        json_pos_ += token.length;
        token = ParseToken();

        node.reset(new DictionaryValue);
        while (token.type != Token::OBJECT_END) {
          if (token.type != Token::STRING) {
            SetErrorCode(JSON_UNQUOTED_DICTIONARY_KEY, json_pos_);
            return NULL;
          }
          scoped_ptr<Value> dict_key_value(DecodeString(token));
          if (!dict_key_value.get())
            return NULL;

          // Convert the key into a wstring.
          std::string dict_key;
          bool success = dict_key_value->GetAsString(&dict_key);
          DCHECK(success);

          json_pos_ += token.length;
          token = ParseToken();
          if (token.type != Token::OBJECT_PAIR_SEPARATOR)
            return NULL;

          json_pos_ += token.length;
          token = ParseToken();
          Value* dict_value = BuildValue(false);
          if (!dict_value)
            return NULL;
          static_cast<DictionaryValue*>(node.get())->SetWithoutPathExpansion(
              dict_key, dict_value);

          // After a key/value pair, we expect a comma or the end of the
          // object.
          token = ParseToken();
          if (token.type == Token::LIST_SEPARATOR) {
            json_pos_ += token.length;
            token = ParseToken();
            // Trailing commas are invalid according to the JSON RFC, but some
            // consumers need the parsing leniency, so handle accordingly.
            if (token.type == Token::OBJECT_END) {
              if (!allow_trailing_comma_) {
                SetErrorCode(JSON_TRAILING_COMMA, json_pos_);
                return NULL;
              }
              // Trailing comma OK, stop parsing the Object.
              break;
            }
          } else if (token.type != Token::OBJECT_END) {
            // Unexpected value after last object value.  Bail out.
            return NULL;
          }
        }
        if (token.type != Token::OBJECT_END)
          return NULL;

        break;
      }

    default:
      // We got a token that's not a value.
      return NULL;
  }
  json_pos_ += token.length;

  --stack_depth_;
  return node.release();
}

3)函数ParseToken()的实现:

JSONReader::Token JSONReader::ParseToken() {
  EatWhitespaceAndComments();

  Token token(Token::INVALID_TOKEN, 0, 0);
  switch (*json_pos_) {

    //当前字符为’\0‘,返回Token:END_OF_INPUT(输入结束)
    case '\0':
      token.type = Token::END_OF_INPUT;
      break;

    //匹配空指针

    case 'n':
      if (NextStringMatch(kNullString, arraysize(kNullString) - 1))
        token = Token(Token::NULL_TOKEN, json_pos_, 4);
      break;

    //匹配布尔值true

    case 't':
      if (NextStringMatch(kTrueString, arraysize(kTrueString) - 1))
        token = Token(Token::BOOL_TRUE, json_pos_, 4);
      break;

    //匹配布尔值false

    case 'f':
      if (NextStringMatch(kFalseString, arraysize(kFalseString) - 1))
        token = Token(Token::BOOL_FALSE, json_pos_, 5);
      break;

    //匹配右中括号,返回数组类型序列

    case '[':
      token = Token(Token::ARRAY_BEGIN, json_pos_, 1);
      break;

    case ']':
      token = Token(Token::ARRAY_END, json_pos_, 1);
      break;

    case ',':
      token = Token(Token::LIST_SEPARATOR, json_pos_, 1);
      break;

    //匹配对象序列

    case '{':
      token = Token(Token::OBJECT_BEGIN, json_pos_, 1);
      break;

    case '}':
      token = Token(Token::OBJECT_END, json_pos_, 1);
      break;

    case ':':
      token = Token(Token::OBJECT_PAIR_SEPARATOR, json_pos_, 1);
      break;

    //匹配数字序列

    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    case '-':
      token = ParseNumberToken();
      break;

    //匹配字符串序列

    case '"':
      token = ParseStringToken();
      break;
  }
  return token;
}

阅读上述代码可知,函数JsonToValue中调用了函数BuildValue,函数BuildValue依据字符串json的Token类型(字符串、数字、数组或者是对象),来最终给出字符串json反序列化后的Value类型。

【参考文献】

1)http://laichendong.com/rfc4627-zh_cn/

2)http://www.rfc-editor.org/rfc/rfc4627.txt




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值