/lib/Json45r7/Source/Src/Newtonsoft.Json/Linq/JPath.cs

https://bitbucket.org/wantstudios/bitbucketclient · C# · 208 lines · 156 code · 30 blank · 22 comment · 33 complexity · f0dc333fc80b2caa0e0bd73d42bbe691 MD5 · raw file

  1. #region License
  2. // Copyright (c) 2007 James Newton-King
  3. //
  4. // Permission is hereby granted, free of charge, to any person
  5. // obtaining a copy of this software and associated documentation
  6. // files (the "Software"), to deal in the Software without
  7. // restriction, including without limitation the rights to use,
  8. // copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the
  10. // Software is furnished to do so, subject to the following
  11. // conditions:
  12. //
  13. // The above copyright notice and this permission notice shall be
  14. // included in all copies or substantial portions of the Software.
  15. //
  16. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  17. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  18. // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  19. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  20. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  23. // OTHER DEALINGS IN THE SOFTWARE.
  24. #endregion
  25. using System;
  26. using System.Collections.Generic;
  27. using System.Globalization;
  28. using Newtonsoft.Json.Utilities;
  29. namespace Newtonsoft.Json.Linq
  30. {
  31. internal class JPath
  32. {
  33. private readonly string _expression;
  34. public List<object> Parts { get; private set; }
  35. private int _currentIndex;
  36. public JPath(string expression)
  37. {
  38. ValidationUtils.ArgumentNotNull(expression, "expression");
  39. _expression = expression;
  40. Parts = new List<object>();
  41. ParseMain();
  42. }
  43. private void ParseMain()
  44. {
  45. int currentPartStartIndex = _currentIndex;
  46. bool followingIndexer = false;
  47. while (_currentIndex < _expression.Length)
  48. {
  49. char currentChar = _expression[_currentIndex];
  50. switch (currentChar)
  51. {
  52. case '[':
  53. case '(':
  54. if (_currentIndex > currentPartStartIndex)
  55. {
  56. string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex);
  57. Parts.Add(member);
  58. }
  59. ParseIndexer(currentChar);
  60. currentPartStartIndex = _currentIndex + 1;
  61. followingIndexer = true;
  62. break;
  63. case ']':
  64. case ')':
  65. throw new JsonException("Unexpected character while parsing path: " + currentChar);
  66. case '.':
  67. if (_currentIndex > currentPartStartIndex)
  68. {
  69. string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex);
  70. Parts.Add(member);
  71. }
  72. currentPartStartIndex = _currentIndex + 1;
  73. followingIndexer = false;
  74. break;
  75. default:
  76. if (followingIndexer)
  77. throw new JsonException("Unexpected character following indexer: " + currentChar);
  78. break;
  79. }
  80. _currentIndex++;
  81. }
  82. if (_currentIndex > currentPartStartIndex)
  83. {
  84. string member = _expression.Substring(currentPartStartIndex, _currentIndex - currentPartStartIndex);
  85. Parts.Add(member);
  86. }
  87. }
  88. private void ParseIndexer(char indexerOpenChar)
  89. {
  90. _currentIndex++;
  91. char indexerCloseChar = (indexerOpenChar == '[') ? ']' : ')';
  92. int indexerStart = _currentIndex;
  93. int indexerLength = 0;
  94. bool indexerClosed = false;
  95. while (_currentIndex < _expression.Length)
  96. {
  97. char currentCharacter = _expression[_currentIndex];
  98. if (char.IsDigit(currentCharacter))
  99. {
  100. indexerLength++;
  101. }
  102. else if (currentCharacter == indexerCloseChar)
  103. {
  104. indexerClosed = true;
  105. break;
  106. }
  107. else
  108. {
  109. throw new JsonException("Unexpected character while parsing path indexer: " + currentCharacter);
  110. }
  111. _currentIndex++;
  112. }
  113. if (!indexerClosed)
  114. throw new JsonException("Path ended with open indexer. Expected " + indexerCloseChar);
  115. if (indexerLength == 0)
  116. throw new JsonException("Empty path indexer.");
  117. string indexer = _expression.Substring(indexerStart, indexerLength);
  118. Parts.Add(Convert.ToInt32(indexer, CultureInfo.InvariantCulture));
  119. }
  120. internal JToken Evaluate(JToken root, bool errorWhenNoMatch)
  121. {
  122. JToken current = root;
  123. foreach (object part in Parts)
  124. {
  125. string propertyName = part as string;
  126. if (propertyName != null)
  127. {
  128. JObject o = current as JObject;
  129. if (o != null)
  130. {
  131. current = o[propertyName];
  132. if (current == null && errorWhenNoMatch)
  133. throw new JsonException("Property '{0}' does not exist on JObject.".FormatWith(CultureInfo.InvariantCulture, propertyName));
  134. }
  135. else
  136. {
  137. if (errorWhenNoMatch)
  138. throw new JsonException("Property '{0}' not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, propertyName, current.GetType().Name));
  139. return null;
  140. }
  141. }
  142. else
  143. {
  144. int index = (int) part;
  145. JArray a = current as JArray;
  146. JConstructor c = current as JConstructor;
  147. if (a != null)
  148. {
  149. if (a.Count <= index)
  150. {
  151. if (errorWhenNoMatch)
  152. throw new IndexOutOfRangeException("Index {0} outside the bounds of JArray.".FormatWith(CultureInfo.InvariantCulture, index));
  153. return null;
  154. }
  155. current = a[index];
  156. }
  157. else if (c != null)
  158. {
  159. if (c.Count <= index)
  160. {
  161. if (errorWhenNoMatch)
  162. throw new IndexOutOfRangeException("Index {0} outside the bounds of JConstructor.".FormatWith(CultureInfo.InvariantCulture, index));
  163. return null;
  164. }
  165. current = c[index];
  166. }
  167. else
  168. {
  169. if (errorWhenNoMatch)
  170. throw new JsonException("Index {0} not valid on {1}.".FormatWith(CultureInfo.InvariantCulture, index, current.GetType().Name));
  171. return null;
  172. }
  173. }
  174. }
  175. return current;
  176. }
  177. }
  178. }