##// END OF EJS Templates
Container configuration cleanup, RC2
Container configuration cleanup, RC2

File last commit:

r236:302ca905c19e v2
r279:8714471e8d78 v3
Show More
JsonReader.cs
318 lines | 11.9 KiB | text/x-csharp | CSharpLexer
using System;
using System.Diagnostics;
using System.IO;
using Implab.Automaton;
using Implab.Automaton.RegularExpressions;
using System.Linq;
using Implab.Components;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
namespace Implab.Formats.Json {
/// <summary>
/// Pull парсер JSON данных.
/// </summary>
/// <remarks>
/// Следует отметить отдельную интерпретацию свойства <see cref="Level"/>,
/// оно означает текущий уровень вложенности объектов, однако закрывающий
/// элемент объекта и массива имеет уровень меньше, чем сам объект.
/// <code>
/// { // Level = 1
/// "name" : "Peter", // Level = 1
/// "address" : { // Level = 2
/// city : "Stern" // Level = 2
/// } // Level = 1
/// } // Level = 0
/// </code>
/// </remarks>
public class JsonReader : Disposable {
enum MemberContext {
MemberName,
MemberValue
}
#region Parser rules
struct ParserContext {
readonly int[,] m_dfa;
int m_state;
readonly JsonElementContext m_elementContext;
public ParserContext(int[,] dfa, int state, JsonElementContext context) {
m_dfa = dfa;
m_state = state;
m_elementContext = context;
}
public bool Move(JsonTokenType token) {
var next = m_dfa[m_state, (int)token];
if (next == AutomatonConst.UnreachableState)
return false;
m_state = next;
return true;
}
public JsonElementContext ElementContext {
get { return m_elementContext; }
}
}
static readonly ParserContext _jsonContext;
static readonly ParserContext _objectContext;
static readonly ParserContext _arrayContext;
static JsonReader() {
var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression);
var objectExpression = memberExpression
.Cat(
MakeToken(JsonTokenType.ValueSeparator)
.Cat(memberExpression)
.EClosure()
)
.Optional()
.Cat(MakeToken(JsonTokenType.EndObject))
.End();
var arrayExpression = valueExpression
.Cat(
MakeToken(JsonTokenType.ValueSeparator)
.Cat(valueExpression)
.EClosure()
)
.Optional()
.Cat(MakeToken(JsonTokenType.EndArray))
.End();
var jsonExpression = valueExpression.End();
_jsonContext = CreateParserContext(jsonExpression, JsonElementContext.None);
_objectContext = CreateParserContext(objectExpression, JsonElementContext.Object);
_arrayContext = CreateParserContext(arrayExpression, JsonElementContext.Array);
}
static Token MakeToken(params JsonTokenType[] input) {
return Token.New( input.Select(t => (int)t).ToArray() );
}
static ParserContext CreateParserContext(Token expr, JsonElementContext context) {
var dfa = new DFATable();
var builder = new RegularExpressionVisitor(dfa);
expr.Accept(builder);
builder.BuildDFA();
return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context);
}
#endregion
readonly JsonScanner m_scanner;
// json starts from the value context and may content even a single literal
MemberContext m_memberContext = MemberContext.MemberValue;
JsonElementType m_elementType;
string m_elementValue;
string m_memberName = String.Empty;
Stack<ParserContext> m_stack = new Stack<ParserContext>();
ParserContext m_context = _jsonContext;
/// <summary>
/// Создает новый парсер на основе строки, содержащей JSON
/// </summary>
/// <param name="text"></param>
JsonReader(JsonScanner scanner) {
m_scanner = scanner;
}
public int Level {
get { return m_stack.Count; }
}
/// <summary>
/// Тип текущего элемента на котором стоит парсер.
/// </summary>
public JsonElementType ElementType {
get { return m_elementType; }
}
/// <summary>
/// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда
/// пустая строка.
/// </summary>
public string ElementName {
get { return m_memberName; }
}
/// <summary>
/// Значение элемента. Только для элементов типа <see cref="JsonElementType.Value"/>, для остальных <c>null</c>
/// </summary>
public string ElementValue {
get { return m_elementValue; }
}
/// <summary>
/// Читает слеюудущий объект из потока
/// </summary>
/// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns>
public bool Read() {
string tokenValue;
JsonTokenType tokenType;
m_memberName = String.Empty;
while (m_scanner.ReadToken(out tokenValue, out tokenType)) {
if(!m_context.Move(tokenType))
UnexpectedToken(tokenValue, tokenType);
switch (tokenType) {
case JsonTokenType.BeginObject:
m_stack.Push(m_context);
m_context = _objectContext;
m_elementValue = null;
m_memberContext = MemberContext.MemberName;
m_elementType = JsonElementType.BeginObject;
return true;
case JsonTokenType.EndObject:
if (m_stack.Count == 0)
UnexpectedToken(tokenValue, tokenType);
m_context = m_stack.Pop();
m_elementValue = null;
m_elementType = JsonElementType.EndObject;
return true;
case JsonTokenType.BeginArray:
m_stack.Push(m_context);
m_context = _arrayContext;
m_elementValue = null;
m_memberContext = MemberContext.MemberValue;
m_elementType = JsonElementType.BeginArray;
return true;
case JsonTokenType.EndArray:
if (m_stack.Count == 0)
UnexpectedToken(tokenValue, tokenType);
m_context = m_stack.Pop();
m_elementValue = null;
m_elementType = JsonElementType.EndArray;
return true;
case JsonTokenType.String:
if (m_memberContext == MemberContext.MemberName) {
m_memberName = tokenValue;
break;
}
m_elementType = JsonElementType.Value;
m_elementValue = tokenValue;
return true;
case JsonTokenType.Number:
m_elementType = JsonElementType.Value;
m_elementValue = tokenValue;
return true;
case JsonTokenType.Literal:
m_elementType = JsonElementType.Value;
m_elementValue = tokenValue == "null" ? null : tokenValue;
return true;
case JsonTokenType.NameSeparator:
m_memberContext = MemberContext.MemberValue;
break;
case JsonTokenType.ValueSeparator:
m_memberContext = m_context.ElementContext == JsonElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
break;
default:
UnexpectedToken(tokenValue, tokenType);
break;
}
}
if (m_context.ElementContext != JsonElementContext.None)
throw new ParserException("Unexpedted end of data");
Eof = true;
return false;
}
object ParseLiteral(string literal) {
switch (literal) {
case "null":
return null;
case "false":
return false;
case "true":
return true;
default:
UnexpectedToken(literal, JsonTokenType.Literal);
return null; // avoid compliler error
}
}
void UnexpectedToken(object value, JsonTokenType tokenType) {
throw new ParserException(String.Format("Unexpected token {0}: '{1}'", tokenType, value));
}
/// <summary>
/// Признак конца потока
/// </summary>
public bool Eof {
get;
private set;
}
protected override void Dispose(bool disposing) {
if (disposing)
m_scanner.Dispose();
}
/// <summary>
/// Переходит в конец текущего объекта.
/// </summary>
public void SeekElementEnd() {
var level = Level - 1;
Debug.Assert(level >= 0);
while (Level != level)
Read();
}
public static JsonReader Create(string file, Encoding encoding) {
return new JsonReader(JsonTextScanner.Create(file, encoding));
}
public static JsonReader Create(string file) {
return new JsonReader(JsonTextScanner.Create(file));
}
public static JsonReader Create(Stream stream, Encoding encoding) {
return new JsonReader(JsonTextScanner.Create(stream, encoding));
}
public static JsonReader Create(Stream stream) {
return new JsonReader(JsonTextScanner.Create(stream));
}
public static JsonReader Create(TextReader reader) {
return new JsonReader(JsonTextScanner.Create(reader));
}
public static JsonReader ParseString(string data) {
return new JsonReader(JsonStringScanner.Create(data));
}
public static JsonReader ParseString(string data, int offset, int length) {
return new JsonReader(JsonStringScanner.Create(data, offset, length));
}
public static JsonReader ParseString(char[] data, int offset, int lenght) {
return new JsonReader(JsonStringScanner.Create(data, offset, lenght));
}
}
}