public override IValue DeepCopy() { ListValue result = new ListValue(); foreach(IValue value in list_) { result.Append(value.DeepCopy()); } return result; }
/// <summary> /// Recursively build <see cref="Value"/>. /// </summary> /// <param name="is_root">true to verify if the root is either an object or an array; otherwise, false.</param> /// <returns>An IDictionary&alt;string, string> containing the parsed JSON string or a null reference /// if we don't have a valid JSON string.</returns> /// <exception cref="ArgumentException">Too much nesting.</exception> IValue BuildValue(bool is_root) { ++stack_depth_; if (stack_depth_ > kStackLimit) { throw new InvalidOperationException( Resources.Resources.InvalidOperation_TooMuchNesting); } Token token = ParseToken(); // The root token must be an array or an object. if (is_root && token.type != Token.TokenType.OBJECT_BEGIN && token.type != Token.TokenType.ARRAY_BEGIN) return null; IValue node; switch (token.type) { case Token.TokenType.END_OF_INPUT: case Token.TokenType.INVALID_TOKEN: return null; case Token.TokenType.NULL_TOKEN: node = Value.CreateNullValue(); break; case Token.TokenType.BOOL_TRUE: node = Value.CreateBooleanValue(true); break; case Token.TokenType.BOOL_FALSE: node = Value.CreateBooleanValue(false); break; case Token.TokenType.NUMBER: node = DecodeNumber(token); break; case Token.TokenType.STRING: node = DecodeString(token); break; case Token.TokenType.ARRAY_BEGIN: { json_pos_ += token.length; token = ParseToken(); node = new ListValue(); while (token.type != Token.TokenType.ARRAY_END) { IValue array_node = BuildValue(false); if (array_node == null) return null; ((ListValue)node).Append(array_node); // After a list value, we expect a comma ot the end of the list. token = ParseToken(); if (token.type == Token.TokenType.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.TokenType.ARRAY_END) { if (!allow_trailing_comma_) { throw new InvalidOperationException(string.Format( Resources.Resources.InvalidOperation_json_TrailingComma, json_pos_)); } // Trailing comma OK, stop parsing the Array. break; } } else if (token.type != Token.TokenType.ARRAY_END) { // Unexpected value after list value. Bail out. return null; } } if (token.type != Token.TokenType.ARRAY_END) { return null; } break; } case Token.TokenType.OBJECT_BEGIN: { json_pos_ += token.length; token = ParseToken(); node = new DictionaryValue(); while (token.type != Token.TokenType.OBJECT_END) { if (token.type != Token.TokenType.STRING) { throw new InvalidOperationException(string.Format( Resources.Resources.InvalidOperation_json_UnquotedDictionaryKey, json_pos_)); } IValue dict_key_value = DecodeString(token); if (dict_key_value == null) return null; // Converts the key into a string. string dict_key; bool success = dict_key_value.GetAsString(out dict_key); json_pos_ += token.length; token = ParseToken(); if (token.type != Token.TokenType.OBJECT_PAIR_SEPARATOR) return null; json_pos_ += token.length; //token = ParseToken(); IValue dict_value = BuildValue(false); if (dict_value == null) return null; (node as DictionaryValue)[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.TokenType.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.TokenType.OBJECT_END) { if (!allow_trailing_comma_) { throw new InvalidOperationException(string.Format( Resources.Resources.InvalidOperation_json_TrailingComma, json_pos_)); } // Trailing comma OK, stop parsing the object. break; } } else if (token.type != Token.TokenType.OBJECT_END) { // Unexpected value after last object value. Bail out. return null; } } if (token.type != Token.TokenType.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; }
/// <summary> /// Convenience form of Get(). /// </summary> /// <param name="index">The zero-based index of the element to get.</param> /// <param name="out_value">When this method returns, contains the <see cref="Value"/> associated /// with the specified index if the index falls within the current list range; otherwise null</param> /// <returns>true if the index falls within the current list range; otherwise false.</returns> public bool GetList(int index, out ListValue out_value) { IValue value; out_value = null; if (!Get(index, out value) || value.IsType(ValueType.List)) return false; out_value = value as ListValue; return true; }