Skip to content

Instantly share code, notes, and snippets.

@bleroy
Last active February 15, 2016 18:30
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bleroy/a5f48372320c3bdb84ad to your computer and use it in GitHub Desktop.
Save bleroy/a5f48372320c3bdb84ad to your computer and use it in GitHub Desktop.
Helper methods for use with Newtonsoft's JSON library.
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Bleroy
{
public static class JsonHelpers
{
/// <summary>
/// Advances the reader to the first child property with the provided name,
/// no matter how deep it is.
/// After calling this method, the cursor is on the value node.
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="property">The name of the property to search for.</param>
/// <returns>True if a node of that type was found.</returns>
public static bool AdvanceTo(this JsonTextReader reader, string property)
{
var depth = 0;
while (reader.Read() && depth >= 0) {
if (reader.TokenType == JsonToken.PropertyName
&& (string)reader.Value == property)
{
reader.Read();
return true;
}
switch (reader.TokenType)
{
case JsonToken.StartObject:
case JsonToken.StartArray:
case JsonToken.StartConstructor:
depth++;
break;
case JsonToken.EndObject:
case JsonToken.EndArray:
case JsonToken.EndConstructor:
depth--;
break;
}
}
return false;
}
/// <summary>
/// Advances the reader to the first child node with the provided type.
/// </summary>
/// <param name="reader">The reader.</param>
/// <param name="tokenType">The type of token to advance to.</param>
/// <returns>True if a node of that type was found.</returns>
public static bool AdvanceTo(this JsonTextReader reader, JsonToken tokenType)
{
var depth = 0;
while (reader.Read() && depth >= 0)
{
if (reader.TokenType == tokenType) return true;
switch (reader.TokenType)
{
case JsonToken.StartObject:
case JsonToken.StartArray:
case JsonToken.StartConstructor:
depth++;
break;
case JsonToken.EndObject:
case JsonToken.EndArray:
case JsonToken.EndConstructor:
depth--;
break;
}
}
return false;
}
/// <summary>
/// Enumerates the direct children of the current node.
/// The code using this enumeration must entirely consume the current node
/// after each move to the next item.
/// If it doesn't want to do anything with the node, for example, it should
/// call Skip on the reader.
/// If the current node is an object, the method enumerates property names.
/// If the current node is an array, the method advances the reader each time
/// MoveNext is called, but enumerates null values.
/// If the current node is neither an object nor an array, the method skips
/// the node.
/// </summary>
/// <param name="reader">The reader.</param>
/// <returns>An enumeration of all child property names.</returns>
public static IEnumerable<string> Children(this JsonTextReader reader)
{
switch(reader.TokenType)
{
case JsonToken.StartObject:
while (reader.Read())
{
if (reader.TokenType == JsonToken.EndObject)
{
yield break;
}
if (reader.TokenType == JsonToken.PropertyName)
{
var propertyName = reader.Value;
reader.Read(); // move to the value before yielding.
yield return propertyName as string;
}
}
break;
case JsonToken.StartArray:
while (reader.Read())
{
if (reader.TokenType == JsonToken.EndArray)
{
yield break;
}
yield return null;
}
break;
default:
reader.Skip();
reader.Read();
yield break;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment