#region License // Copyright (c) 2007 James Newton-King // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following // conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR // OTHER DEALINGS IN THE SOFTWARE. #endregion using System; using System.Collections.Generic; using System.Linq; using System.IO; using Newtonsoft.Json.Utilities; using System.Diagnostics; using System.Globalization; using System.Collections; using System.ComponentModel; namespace Newtonsoft.Json.Linq { /// /// Represents an abstract JSON token. /// public abstract class JToken : IJEnumerable, IJsonLineInfo { private JContainer _parent; internal JToken _next; private static JTokenEqualityComparer _equalityComparer; private int? _lineNumber; private int? _linePosition; /// /// Gets a comparer that can compare two tokens for value equality. /// /// A that can compare two nodes for value equality. public static JTokenEqualityComparer EqualityComparer { get { if (_equalityComparer == null) _equalityComparer = new JTokenEqualityComparer(); return _equalityComparer; } } /// /// Gets or sets the parent. /// /// The parent. public JContainer Parent { [DebuggerStepThrough] get { return _parent; } internal set { _parent = value; } } /// /// Gets the root of this . /// /// The root of this . public JToken Root { get { JContainer parent = Parent; if (parent == null) return this; while (parent.Parent != null) { parent = parent.Parent; } return parent; } } internal abstract JToken CloneToken(); internal abstract bool DeepEquals(JToken node); /// /// Gets the node type for this . /// /// The type. public abstract JTokenType Type { get; } /// /// Gets a value indicating whether this token has childen tokens. /// /// /// true if this token has child values; otherwise, false. /// public abstract bool HasValues { get; } /// /// Compares the values of two tokens, including the values of all descendant tokens. /// /// The first to compare. /// The second to compare. /// true if the tokens are equal; otherwise false. public static bool DeepEquals(JToken t1, JToken t2) { return (t1 == t2 || (t1 != null && t2 != null && t1.DeepEquals(t2))); } /// /// Gets the next sibling token of this node. /// /// The that contains the next sibling token. public JToken Next { get { if (_parent != null && _next != _parent.First) return _next; return null; } internal set { _next = value; } } /// /// Gets the previous sibling token of this node. /// /// The that contains the previous sibling token. public JToken Previous { get { if (_parent == null) return null; JToken parentNext = _parent.Content._next; JToken parentNextBefore = null; while (parentNext != this) { parentNextBefore = parentNext; parentNext = parentNext.Next; } return parentNextBefore; } } internal JToken() { } /// /// Adds the specified content immediately after this token. /// /// A content object that contains simple content or a collection of content objects to be added after this token. public void AddAfterSelf(object content) { if (_parent == null) throw new InvalidOperationException("The parent is missing."); _parent.AddInternal((Next == null), this, content); } /// /// Adds the specified content immediately before this token. /// /// A content object that contains simple content or a collection of content objects to be added before this token. public void AddBeforeSelf(object content) { if (_parent == null) throw new InvalidOperationException("The parent is missing."); JToken previous = Previous; if (previous == null) previous = _parent.Last; _parent.AddInternal(false, previous, content); } /// /// Returns a collection of the ancestor tokens of this token. /// /// A collection of the ancestor tokens of this token. public IEnumerable Ancestors() { for (JToken parent = Parent; parent != null; parent = parent.Parent) { yield return parent; } } /// /// Returns a collection of the sibling tokens after this token, in document order. /// /// A collection of the sibling tokens after this tokens, in document order. public IEnumerable AfterSelf() { if (Parent == null) yield break; for (JToken o = Next; o != null; o = o.Next) yield return o; } /// /// Returns a collection of the sibling tokens before this token, in document order. /// /// A collection of the sibling tokens before this token, in document order. public IEnumerable BeforeSelf() { for (JToken o = Parent.First; o != this; o = o.Next) yield return o; } /// /// Gets the with the specified key. /// /// The with the specified key. public virtual JToken this[object key] { get { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); } set { throw new InvalidOperationException("Cannot set child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); } } /// /// Gets the with the specified key converted to the specified type. /// /// The type to convert the token to. /// The token key. /// The converted token value. public virtual T Value(object key) { JToken token = this[key]; return Extensions.Convert(token); } /// /// Get the first child token of this token. /// /// A containing the first child token of the . public virtual JToken First { get { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); } } /// /// Get the last child token of this token. /// /// A containing the last child token of the . public virtual JToken Last { get { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); } } /// /// Returns a collection of the child tokens of this token, in document order. /// /// An of containing the child tokens of this , in document order. public virtual JEnumerable Children() { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); } /// /// Returns a collection of the child tokens of this token, in document order, filtered by the specified type. /// /// The type to filter the child tokens on. /// A containing the child tokens of this , in document order. public JEnumerable Children() where T : JToken { return new JEnumerable(Children().OfType()); } /// /// Returns a collection of the child values of this token, in document order. /// /// The type to convert the values to. /// A containing the child values of this , in document order. public virtual IEnumerable Values() { throw new InvalidOperationException("Cannot access child value on {0}.".FormatWith(CultureInfo.InvariantCulture, GetType())); } /// /// Removes this token from its parent. /// public void Remove() { if (_parent == null) throw new InvalidOperationException("The parent is missing."); _parent.RemoveItem(this); } /// /// Replaces this token with the specified token. /// /// The value. public void Replace(JToken value) { if (_parent == null) throw new InvalidOperationException("The parent is missing."); _parent.ReplaceItem(this, value); } /// /// Writes this token to a . /// /// A into which this method will write. /// A collection of which will be used when writing the token. public abstract void WriteTo(JsonWriter writer, params JsonConverter[] converters); /// /// Returns the indented JSON for this token. /// /// /// The indented JSON for this token. /// public override string ToString() { return ToString(Formatting.Indented); } /// /// Returns the JSON for this token using the given formatting and converters. /// /// Indicates how the output is formatted. /// A collection of which will be used when writing the token. /// The JSON for this token using the given formatting and converters. public string ToString(Formatting formatting, params JsonConverter[] converters) { using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture)) { JsonTextWriter jw = new JsonTextWriter(sw); jw.Formatting = formatting; WriteTo(jw, converters); return sw.ToString(); } } private static JValue EnsureValue(JToken value) { if (value == null) throw new ArgumentNullException("value"); if (value is JProperty) value = ((JProperty)value).Value; JValue v = value as JValue; return v; } private static string GetType(JToken token) { ValidationUtils.ArgumentNotNull(token, "token"); if (token is JProperty) token = ((JProperty)token).Value; return token.Type.ToString(); } private static bool IsNullable(JToken o) { return (o.Type == JTokenType.Undefined || o.Type == JTokenType.Null); } private static bool ValidateFloat(JToken o, bool nullable) { return (o.Type == JTokenType.Float || o.Type == JTokenType.Integer || (nullable && IsNullable(o))); } private static bool ValidateInteger(JToken o, bool nullable) { return (o.Type == JTokenType.Integer || (nullable && IsNullable(o))); } private static bool ValidateDate(JToken o, bool nullable) { return (o.Type == JTokenType.Date || (nullable && IsNullable(o))); } private static bool ValidateBoolean(JToken o, bool nullable) { return (o.Type == JTokenType.Boolean || (nullable && IsNullable(o))); } private static bool ValidateString(JToken o) { return (o.Type == JTokenType.String || o.Type == JTokenType.Comment || o.Type == JTokenType.Raw || IsNullable(o)); } private static bool ValidateBytes(JToken o) { return (o.Type == JTokenType.Bytes || IsNullable(o)); } #region Cast from operators /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator bool(JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateBoolean(v, false)) throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (bool)v.Value; } #if !PocketPC && !NET20 /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator DateTimeOffset(JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateDate(v, false)) throw new ArgumentException("Can not convert {0} to DateTimeOffset.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (DateTimeOffset)v.Value; } #endif /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator bool?(JToken value) { if (value == null) return null; JValue v = EnsureValue(value); if (v == null || !ValidateBoolean(v, true)) throw new ArgumentException("Can not convert {0} to Boolean.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (bool?)v.Value; } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator long(JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, false)) throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (long)v.Value; } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator DateTime?(JToken value) { if (value == null) return null; JValue v = EnsureValue(value); if (v == null || !ValidateDate(v, true)) throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (DateTime?)v.Value; } #if !PocketPC && !NET20 /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator DateTimeOffset?(JToken value) { if (value == null) return null; JValue v = EnsureValue(value); if (v == null || !ValidateDate(v, true)) throw new ArgumentException("Can not convert {0} to DateTimeOffset.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (DateTimeOffset?)v.Value; } #endif /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator decimal?(JToken value) { if (value == null) return null; JValue v = EnsureValue(value); if (v == null || !ValidateFloat(v, true)) throw new ArgumentException("Can not convert {0} to Decimal.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (v.Value != null) ? (decimal?)Convert.ToDecimal(v.Value, CultureInfo.InvariantCulture) : null; } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator double?(JToken value) { if (value == null) return null; JValue v = EnsureValue(value); if (v == null || !ValidateFloat(v, true)) throw new ArgumentException("Can not convert {0} to Double.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (double?)v.Value; } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator int(JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, false)) throw new ArgumentException("Can not convert {0} to Int32.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return Convert.ToInt32(v.Value, CultureInfo.InvariantCulture); } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator int?(JToken value) { if (value == null) return null; JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, true)) throw new ArgumentException("Can not convert {0} to Int32.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (v.Value != null) ? (int?)Convert.ToInt32(v.Value, CultureInfo.InvariantCulture) : null; } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator DateTime(JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateDate(v, false)) throw new ArgumentException("Can not convert {0} to DateTime.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (DateTime)v.Value; } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator long?(JToken value) { if (value == null) return null; JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, true)) throw new ArgumentException("Can not convert {0} to Int64.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (long?)v.Value; } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator float?(JToken value) { if (value == null) return null; JValue v = EnsureValue(value); if (v == null || !ValidateFloat(v, true)) throw new ArgumentException("Can not convert {0} to Single.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (v.Value != null) ? (float?)Convert.ToSingle(v.Value, CultureInfo.InvariantCulture) : null; } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator decimal(JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateFloat(v, false)) throw new ArgumentException("Can not convert {0} to Decimal.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return Convert.ToDecimal(v.Value, CultureInfo.InvariantCulture); } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator uint?(JToken value) { if (value == null) return null; JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, true)) throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (uint?)v.Value; } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator ulong?(JToken value) { if (value == null) return null; JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, true)) throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (ulong?)v.Value; } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator double(JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateFloat(v, false)) throw new ArgumentException("Can not convert {0} to Double.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (double)v.Value; } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator float(JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateFloat(v, false)) throw new ArgumentException("Can not convert {0} to Single.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return Convert.ToSingle(v.Value, CultureInfo.InvariantCulture); } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator string(JToken value) { if (value == null) return null; JValue v = EnsureValue(value); if (v == null || !ValidateString(v)) throw new ArgumentException("Can not convert {0} to String.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (string)v.Value; } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator uint(JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, false)) throw new ArgumentException("Can not convert {0} to UInt32.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return Convert.ToUInt32(v.Value, CultureInfo.InvariantCulture); } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator ulong(JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateInteger(v, false)) throw new ArgumentException("Can not convert {0} to UInt64.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return Convert.ToUInt64(v.Value, CultureInfo.InvariantCulture); } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator byte[](JToken value) { JValue v = EnsureValue(value); if (v == null || !ValidateBytes(v)) throw new ArgumentException("Can not convert {0} to byte array.".FormatWith(CultureInfo.InvariantCulture, GetType(value))); return (byte[])v.Value; } #endregion #region Cast to operators /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(bool value) { return new JValue(value); } #if !PocketPC && !NET20 /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(DateTimeOffset value) { return new JValue(value); } #endif /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(bool? value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(long value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(DateTime? value) { return new JValue(value); } #if !PocketPC && !NET20 /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(DateTimeOffset? value) { return new JValue(value); } #endif /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(decimal? value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(double? value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(ushort value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(int value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(int? value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(DateTime value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(long? value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(float? value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(decimal value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(ushort? value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(uint? value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(ulong? value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(double value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(float value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(string value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(uint value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(ulong value) { return new JValue(value); } /// /// Performs an implicit conversion from to . /// /// The value to create a from. /// The initialized with the specified value. public static implicit operator JToken(byte[] value) { return new JValue(value); } #endregion IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return Children().GetEnumerator(); } internal abstract int GetDeepHashCode(); IJEnumerable IJEnumerable.this[object key] { get { return this[key]; } } /// /// Creates an for this token. /// /// An that can be used to read this token and its descendants. public JsonReader CreateReader() { return new JTokenReader(this); } internal static JToken FromObjectInternal(object o, JsonSerializer jsonSerializer) { ValidationUtils.ArgumentNotNull(o, "o"); ValidationUtils.ArgumentNotNull(jsonSerializer, "jsonSerializer"); JToken token; using (JTokenWriter jsonWriter = new JTokenWriter()) { jsonSerializer.Serialize(jsonWriter, o); token = jsonWriter.Token; } return token; } /// /// Creates a from an object. /// /// The object that will be used to create . /// A with the value of the specified object public static JToken FromObject(object o) { return FromObjectInternal(o, new JsonSerializer()); } /// /// Creates a from an object using the specified . /// /// The object that will be used to create . /// The that will be used when reading the object. /// A with the value of the specified object public static JToken FromObject(object o, JsonSerializer jsonSerializer) { return FromObjectInternal(o, jsonSerializer); } /// /// Creates a from a . /// /// An positioned at the token to read into this . /// /// An that contains the token and its descendant tokens /// that were read from the reader. The runtime type of the token is determined /// by the token type of the first token encountered in the reader. /// public static JToken ReadFrom(JsonReader reader) { ValidationUtils.ArgumentNotNull(reader, "reader"); if (reader.TokenType == JsonToken.None) { if (!reader.Read()) throw new Exception("Error reading JToken from JsonReader."); } if (reader.TokenType == JsonToken.StartObject) return JObject.Load(reader); if (reader.TokenType == JsonToken.StartArray) return JArray.Load(reader); if (reader.TokenType == JsonToken.PropertyName) return JProperty.Load(reader); if (reader.TokenType == JsonToken.StartConstructor) return JConstructor.Load(reader); // hack. change to look at TokenType rather than using value if (!JsonReader.IsStartToken(reader.TokenType)) return new JValue(reader.Value); // TODO: loading constructor and parameters? throw new Exception("Error reading JToken from JsonReader. Unexpected token: {0}".FormatWith(CultureInfo.InvariantCulture, reader.TokenType)); } internal void SetLineInfo(IJsonLineInfo lineInfo) { if (lineInfo == null || !lineInfo.HasLineInfo()) return; SetLineInfo(lineInfo.LineNumber, lineInfo.LinePosition); } internal void SetLineInfo(int lineNumber, int linePosition) { _lineNumber = lineNumber; _linePosition = linePosition; } bool IJsonLineInfo.HasLineInfo() { return (_lineNumber != null && _linePosition != null); } int IJsonLineInfo.LineNumber { get { return _lineNumber ?? 0; } } int IJsonLineInfo.LinePosition { get { return _linePosition ?? 0; } } /// /// Selects the token that matches the object path. /// /// /// The object path from the current to the /// to be returned. This must be a string of property names or array indexes separated /// by periods, such as Tables[0].DefaultView[0].Price in C# or /// Tables(0).DefaultView(0).Price in Visual Basic. /// /// The that matches the object path or a null reference if no matching token is found. public JToken SelectToken(string path) { return SelectToken(path, false); } /// /// Selects the token that matches the object path. /// /// /// The object path from the current to the /// to be returned. This must be a string of property names or array indexes separated /// by periods, such as Tables[0].DefaultView[0].Price in C# or /// Tables(0).DefaultView(0).Price in Visual Basic. /// /// A flag to indicate whether an error should be thrown if no token is found. /// The that matches the object path. public JToken SelectToken(string path, bool errorWhenNoMatch) { JPath p = new JPath(path); return p.Evaluate(this, errorWhenNoMatch); } } }