internal void Append(JsonValue value) { value.Parent = this; if (this.LastChild != null) { this.LastChild = this.LastChild.NexSibling = value; } else { this.FirstChild = this.LastChild = value; } }
private static void CheckTop(JsonValue top, int charPosition) { if (top == null) { throw new JsonParserException(charPosition, "Unexpected character"); } }
public static JsonValue Parse(string json) { JsonValue root = null; JsonValue top = null; string name = null; var escaped_newlines = 0; char[] jsonArray = null; var i = 0; for (; i < json.Length; i++) { var ch = json[i]; // skip white space if (ch == '\x20' || ch == '\x9' || ch == '\xD' || ch == '\xA') { continue; } switch (ch) { case '{': case '[': { // create new value var value = new JsonValue { Name = name }; // name name = null; // type value.Type = ch == '{' ? JsonType.Object : JsonType.Array; // set top and root if (top != null) { top.Append(value); } else if (root == null) { root = value; } else { throw new JsonParserException(i, "Second root. Only one root allowed"); } top = value; } break; case '}': case ']': { if (top == null || top.Type != ((ch == '}') ? JsonType.Object : JsonType.Array)) { throw new JsonParserException(i, "Mismatch closing brace/bracket"); } // set top top = top.Parent; } break; case ':': if (top == null || top.Type != JsonType.Object) { throw new JsonParserException(i, "Unexpected character"); } break; case ',': CheckTop(top, i); break; case '"': { CheckTop(top, i); // skip '"' character i++; ch = json[i]; var first = i; var last = i; var ch_last = ch; while (i < json.Length) { if (ch < '\x20') { throw new JsonParserException(first, "Control characters not allowed in strings"); } if (ch == '\\') { switch (json[i + 1]) { case '"': ch_last = '"'; break; case '\\': ch_last = '\\'; break; case '/': ch_last = '/'; break; case 'b': ch_last = '\b'; break; case 'f': ch_last = '\f'; break; case 'n': ch_last = '\n'; ++escaped_newlines; break; case 'r': ch_last = '\r'; break; case 't': ch_last = '\t'; break; case 'u': { if (jsonArray == null) { jsonArray = json.ToCharArray(); } uint codepoint; if (HexToInteger(json.Substring(i + 2, 4), out codepoint) != 4) { throw new JsonParserException(i, "Bad unicode codepoint"); } if (codepoint <= 0x7F) { ch_last = (char)codepoint; } else if (codepoint <= 0x7FF) { last++; jsonArray[last] = (char)(0xC0 | (codepoint >> 6)); last++; jsonArray[last] = (char)(0x80 | (codepoint & 0x3F)); } else if (codepoint <= 0xFFFF) { last++; jsonArray[last] = (char)(0xE0 | (codepoint >> 12)); last++; jsonArray[last] = (char)(0x80 | ((codepoint >> 6) & 0x3F)); last++; jsonArray[last] = (char)(0x80 | (codepoint & 0x3F)); } } i += 4; break; default: throw new JsonParserException(first, "Unrecognized escape sequence"); } last++; i++; } else if (ch == '"') { break; } else { last++; i++; ch = json[i]; } } if (name == null && top.Type == JsonType.Object) { // field name in object name = json.Substring(first, i - first); } else { // new string value var value = new JsonValue { Name = name }; name = null; value.Type = JsonType.String; string s; if (jsonArray != null) { var slice = new char[i - first]; Array.Copy(jsonArray, first, slice, 0, i - first); s = new string(slice); } else { s = json.Substring(first, i - first); } value.Value = new TypeUnion<string, long, decimal, bool>(s); top.Append(value); } } break; case 'n': case 't': case 'f': { CheckTop(top, i); // new null/bool value var value = new JsonValue { Name = name }; name = null; // null if (ch == 'n' && json[i + 1] == 'u' && json[i + 2] == 'l' && json[i + 3] == 'l') { value.Type = JsonType.Null; i += 3; } // true else if (ch == 't' && json[i + 1] == 'r' && json[i + 2] == 'u' && json[i + 3] == 'e') { value.Type = JsonType.Boolean; value.Value = new TypeUnion<string, long, decimal, bool>(true); i += 3; } // false else if (ch == 'f' && json[i + 1] == 'a' && json[i + 2] == 'l' && json[i + 3] == 's' && jsonArray[i + 4] == 'e') { value.Type = JsonType.Boolean; value.Value = new TypeUnion<string, long, decimal, bool>(false); i += 4; } else { throw new JsonParserException(i, "Unknown identifier"); } top.Append(value); } break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { CheckTop(top, i); // new number value var value = new JsonValue { Name = name }; name = null; value.Type = JsonType.Integer; int first = i; while (ch != '\x20' && ch != '\x9' && ch != '\xD' && ch != '\xA' && ch != ',' && ch != ']' && ch != '}') { if (ch == '.' || ch == 'e' || ch == 'E') { value.Type = JsonType.Decimal; } i++; ch = json[i]; } if (value.Type == JsonType.Integer) { long n; if (TextToInteger(json.Substring(first, i - first), out n) != i - first) { throw new JsonParserException(first, "Bad integer number"); } else { value.Value = new TypeUnion<string, long, decimal, bool>(n); } i--; } if (value.Type == JsonType.Decimal) { decimal d; if (TextToDecimal(json.Substring(first, i - first), out d) != i - first) { throw new JsonParserException(first, "Bad decimal number"); } value.Value = new TypeUnion<string, long, decimal, bool>(d); i--; } top.Append(value); } break; default: throw new JsonParserException(i, "Unexpected character"); } } if (top != null) { throw new JsonParserException(i, "Not all objects/arrays have been properly closed"); } return root; }
private static int ComputeTypeMatchRank(JsonValue jsonObject, Type objectType) { var propertyNames = Reflector.GetAllProperties(objectType).Select(p => p.Name); var jsonNames = new HashSet<string>(); var child = jsonObject.FirstChild; while (child != null) { if (child.Name != null) { jsonNames.Add(child.Name); } child = child.NexSibling; } jsonNames.UnionWith(propertyNames); return jsonNames.Count; }
public static object ReadObject(JsonValue root, Type objectType) { JsonValue current = root.FirstChild ?? root; object result = null; object listResult = null; Type elementType = null; var reflectedType = Reflector.GetReflectedType(objectType); var simpleElement = false; var dictionary = false; JsonValue listRoot = null; if (root.Type == JsonType.Object) { if (reflectedType.IsDataEntity) { result = ObjectFactory.Create(objectType); elementType = objectType; } else if (reflectedType.IsDictionary) { var types = objectType.GetGenericArguments(); result = Dictionary.Create(types[0], types[1]); elementType = types[1]; dictionary = true; } } else if (root.Type == JsonType.Array) { if (reflectedType.IsDataEntity) { result = List.Create(objectType); elementType = objectType; } else if (reflectedType.IsDataEntityList) { elementType = reflectedType.ElementType; if (!reflectedType.IsInterface) { listResult = (IList)Nemo.Reflection.Activator.New(objectType); } else { listResult = List.Create(elementType); } result = ObjectFactory.Create(elementType); listRoot = current; } else if (reflectedType.IsSimpleList) { elementType = reflectedType.ElementType; result = List.Create(elementType); simpleElement = true; } } if (elementType == null && root.Parent == null) { return result; } IDictionary<string, ReflectedProperty> propertyMap = null; if (elementType != null && !simpleElement && !dictionary) { propertyMap = Reflector.GetPropertyNameMap(elementType); } if (listRoot != null) { current = listRoot.FirstChild; } while (current != null) { ReflectedProperty property = null; if (propertyMap == null || (current.Name != null && propertyMap.TryGetValue(current.Name, out property))) { switch (current.Type) { case JsonType.Boolean: if (property != null && (root.Type == JsonType.Object || (listRoot != null && listRoot.Type == JsonType.Object))) { ((IDataEntity)result).Property(property.PropertyName, current.Value.As<bool>()); } if (result is IList) { ((IList)result).Add(current.Value.As<bool>()); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, current.Value.As<bool>()); } else { result = current.Value.As<bool>(); } break; case JsonType.Decimal: if (property != null && (root.Type == JsonType.Object || (listRoot != null && listRoot.Type == JsonType.Object))) { var value = current.Value.As<decimal>(); var typeCode = Type.GetTypeCode(property.PropertyType); checked { switch (typeCode) { case TypeCode.Double: ((IDataEntity)result).Property(property.PropertyName, (double)value); break; case TypeCode.Single: ((IDataEntity)result).Property(property.PropertyName, (float)value); break; case TypeCode.Decimal: ((IDataEntity)result).Property(property.PropertyName, value); break; } } } else { var value = current.Value.As<decimal>(); var typeCode = Type.GetTypeCode(elementType ?? objectType); checked { switch (typeCode) { case TypeCode.Double: if (result is IList) { ((IList)result).Add((double)value); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, (double)value); } else { result = (double)value; } break; case TypeCode.Single: if (result is IList) { ((IList)result).Add((float)value); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, (float)value); } else { result = (float)value; } break; case TypeCode.Decimal: if (result is IList) { ((IList)result).Add(value); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, value); } else { result = value; } break; } } } break; case JsonType.Integer: if (property != null && (root.Type == JsonType.Object || (listRoot != null && listRoot.Type == JsonType.Object))) { var value = current.Value.As<long>(); var typeCode = Type.GetTypeCode(property.PropertyType); checked { switch (typeCode) { case TypeCode.Byte: ((IDataEntity)result).Property(property.PropertyName, (byte)value); break; case TypeCode.SByte: ((IDataEntity)result).Property(property.PropertyName, (sbyte)value); break; case TypeCode.Int16: ((IDataEntity)result).Property(property.PropertyName, (short)value); break; case TypeCode.Int32: ((IDataEntity)result).Property(property.PropertyName, (int)value); break; case TypeCode.Int64: ((IDataEntity)result).Property(property.PropertyName, value); break; case TypeCode.UInt16: ((IDataEntity)result).Property(property.PropertyName, (ushort)value); break; case TypeCode.UInt32: ((IDataEntity)result).Property(property.PropertyName, (uint)value); break; case TypeCode.UInt64: ((IDataEntity)result).Property(property.PropertyName, (ulong)value); break; } } } else { var value = current.Value.As<long>(); var typeCode = Type.GetTypeCode(elementType ?? objectType); checked { switch (typeCode) { case TypeCode.Byte: if (result is IList) { ((IList)result).Add((byte)value); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, (byte)value); } else { result = (byte)value; } break; case TypeCode.SByte: if (result is IList) { ((IList)result).Add((sbyte)value); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, (sbyte)value); } else { result = (sbyte)value; } break; case TypeCode.Int16: if (result is IList) { ((IList)result).Add((short)value); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, (short)value); } else { result = (short)value; } break; case TypeCode.Int32: if (result is IList) { ((IList)result).Add((int)value); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, (int)value); } else { result = (int)value; } break; case TypeCode.Int64: if (result is IList) { ((IList)result).Add(value); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, value); } else { result = value; } break; case TypeCode.UInt16: if (result is IList) { ((IList)result).Add((ushort)value); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, (ushort)value); } else { result = (ushort)value; } break; case TypeCode.UInt32: if (result is IList) { ((IList)result).Add((uint)value); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, (uint)value); } else { result = (uint)value; } break; case TypeCode.UInt64: if (result is IList) { ((IList)result).Add((ulong)value); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, (ulong)value); } else { result = (ulong)value; } break; } } } break; case JsonType.String: if (property != null && (root.Type == JsonType.Object || (listRoot != null && listRoot.Type == JsonType.Object))) { var value = current.Value.As<string>(); if (property.PropertyType == typeof(string)) { ((IDataEntity)result).Property(property.PropertyName, value); } else if (property.PropertyType == typeof(DateTime)) { DateTime date; if (DateTime.TryParse(value, out date)) { ((IDataEntity)result).Property(property.PropertyName, date); } } else if (property.PropertyType == typeof(TimeSpan)) { TimeSpan time; if (TimeSpan.TryParse(value, out time)) { ((IDataEntity)result).Property(property.PropertyName, time); } } else if (property.PropertyType == typeof(DateTimeOffset)) { DateTimeOffset date; if (DateTimeOffset.TryParse(value, out date)) { ((IDataEntity)result).Property(property.PropertyName, date); } } else if (property.PropertyType == typeof(Guid)) { Guid guid; if (Guid.TryParse(value, out guid)) { ((IDataEntity)result).Property(property.PropertyName, guid); } } else if (property.PropertyType == typeof(char) && !string.IsNullOrEmpty(value)) { ((IDataEntity)result).Property(property.PropertyName, value[0]); } } else { var value = current.Value.As<string>(); var type = elementType ?? objectType; if (type == typeof(string)) { if (result is IList) { ((IList)result).Add(value); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, value); } else { result = value; } } else if (type == typeof(DateTime)) { DateTime date; if (DateTime.TryParse(value, out date)) { if (result is IList) { ((IList)result).Add(date); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, date); } else { result = date; } } } else if (type == typeof(TimeSpan)) { TimeSpan time; if (TimeSpan.TryParse(value, out time)) { if (result is IList) { ((IList)result).Add(time); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, time); } else { result = time; } } } else if (type == typeof(DateTimeOffset)) { DateTimeOffset date; if (DateTimeOffset.TryParse(value, out date)) { if (result is IList) { ((IList)result).Add(date); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, date); } else { result = date; } } } else if (type == typeof(Guid)) { Guid guid; if (Guid.TryParse(value, out guid)) { if (result is IList) { ((IList)result).Add(guid); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, guid); } else { result = guid; } } } else if (type == typeof(char) && !string.IsNullOrEmpty(value)) { if (result is IList) { ((IList)result).Add(value[0]); } else if (result is IDictionary) { ((IDictionary)result).Add(current.Name, value[0]); } else { result = value[0]; } } } break; case JsonType.Object: { var propertyType = property.PropertyType; var item = ReadObject(current, propertyType); if (root.Type == JsonType.Object) { ((IDataEntity)result).Property(property.PropertyName, item); } else if (root.Type == JsonType.Array) { ((IList)result).Add(item); } } break; case JsonType.Array: { if (root.Type == JsonType.Object) { if (property != null) { IList list; if (!property.IsListInterface) { list = (IList)Nemo.Reflection.Activator.New(property.PropertyType); } else { list = List.Create(property.ElementType, property.Distinct, property.Sorted); } var child = current.FirstChild; while (child != null) { var item = (IDataEntity)ReadObject(child, property.ElementType); list.Add(item); child = child.NexSibling; } ((IDataEntity)result).Property(property.PropertyName, list); } else if (result is IDictionary) { var listType = Reflector.GetReflectedType(elementType); if (elementType.IsArray) { var list = (IList)ReadObject(current, typeof(List<>).MakeGenericType(listType.ElementType)); ((IDictionary)result).Add(current.Name, List.CreateArray(listType.ElementType, list)); } else { var list = (IList)ReadObject(current, elementType); ((IDictionary)result).Add(current.Name, list); } } } break; } } } current = current.NexSibling; if (listRoot != null && current == null) { ((IList)listResult).Add(result); result = ObjectFactory.Create(elementType); listRoot = listRoot.NexSibling; if (listRoot != null) { current = listRoot.FirstChild; } } } return listResult ?? result; }
internal void Append(JsonValue value) { //if (value.Name != null) //{ // _properties.Add(value.Name, value); //} value.Parent = this; if (LastChild != null) { LastChild = LastChild.NexSibling = value; } else { FirstChild = LastChild = value; } }