##// END OF EJS Templates
Reimplemented JsonXmlReader, added support for null values: JSON null values are...
Reimplemented JsonXmlReader, added support for null values: JSON null values are mapped to empty nodes with 'xsi:nil' attribute set to 'true'

File last commit:

r227:8d5de4eb9c2c v2
r227:8d5de4eb9c2c v2
Show More
JSONParser.cs
294 lines | 11.1 KiB | text/x-csharp | CSharpLexer
cin
DFA refactoring
r165 using System;
cin
JSON moved to Formats namespace...
r163 using System.Diagnostics;
using System.IO;
cin
DFA refactoring
r165 using Implab.Automaton;
using Implab.Automaton.RegularExpressions;
using System.Linq;
using Implab.Components;
cin
refactoring complete, JSONParser rewritten
r180 using System.Collections.Generic;
cin
JSON moved to Formats namespace...
r163
cin
DFA refactoring
r165 namespace Implab.Formats.JSON {
cin
JSON moved to Formats namespace...
r163 /// <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>
cin
DFA refactoring
r165 public class JSONParser : Disposable {
cin
JSON moved to Formats namespace...
r163
enum MemberContext {
MemberName,
MemberValue
}
cin
working on JSON parser
r178 #region Parser rules
cin
DFA refactoring
r165 struct ParserContext {
cin
working on JSON parser
r178 readonly int[,] m_dfa;
int m_state;
readonly JSONElementContext m_elementContext;
cin
DFA refactoring
r165
cin
working on JSON parser
r178 public ParserContext(int[,] dfa, int state, JSONElementContext context) {
m_dfa = dfa;
m_state = state;
m_elementContext = context;
}
public bool Move(JsonTokenType token) {
cin
refactoring complete, JSONParser rewritten
r180 var next = m_dfa[m_state, (int)token];
cin
working on JSON parser
r178 if (next == AutomatonConst.UNREACHABLE_STATE)
return false;
m_state = next;
cin
refactoring complete, JSONParser rewritten
r180 return true;
cin
working on JSON parser
r178 }
public JSONElementContext ElementContext {
get { return m_elementContext; }
}
}
cin
JSON moved to Formats namespace...
r163
cin
refactoring complete, JSONParser rewritten
r180 static readonly ParserContext _jsonContext;
static readonly ParserContext _objectContext;
static readonly ParserContext _arrayContext;
cin
JSON moved to Formats namespace...
r163 static JSONParser() {
cin
refactoring complete, JSONParser rewritten
r180 var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression);
cin
JSON moved to Formats namespace...
r163
var objectExpression = memberExpression
.Cat(
cin
refactoring complete, JSONParser rewritten
r180 MakeToken(JsonTokenType.ValueSeparator)
cin
JSON moved to Formats namespace...
r163 .Cat(memberExpression)
.EClosure()
)
.Optional()
cin
refactoring complete, JSONParser rewritten
r180 .Cat(MakeToken(JsonTokenType.EndObject))
cin
working on JSON parser
r178 .End();
cin
JSON moved to Formats namespace...
r163 var arrayExpression = valueExpression
.Cat(
cin
refactoring complete, JSONParser rewritten
r180 MakeToken(JsonTokenType.ValueSeparator)
cin
JSON moved to Formats namespace...
r163 .Cat(valueExpression)
.EClosure()
)
.Optional()
cin
refactoring complete, JSONParser rewritten
r180 .Cat(MakeToken(JsonTokenType.EndArray))
cin
working on JSON parser
r178 .End();
cin
JSON moved to Formats namespace...
r163
cin
working on JSON parser
r178 var jsonExpression = valueExpression.End();
cin
JSON moved to Formats namespace...
r163
cin
refactoring complete, JSONParser rewritten
r180 _jsonContext = CreateParserContext(jsonExpression, JSONElementContext.None);
_objectContext = CreateParserContext(objectExpression, JSONElementContext.Object);
_arrayContext = CreateParserContext(arrayExpression, JSONElementContext.Array);
cin
JSON moved to Formats namespace...
r163 }
cin
refactoring complete, JSONParser rewritten
r180 static Token MakeToken(params JsonTokenType[] input) {
cin
working on JSON parser
r178 return Token.New( input.Select(t => (int)t).ToArray() );
cin
DFA refactoring
r165 }
cin
working on JSON parser
r178 static ParserContext CreateParserContext(Token expr, JSONElementContext context) {
var dfa = new DFATable();
var builder = new RegularExpressionVisitor(dfa);
cin
JSON moved to Formats namespace...
r163 expr.Accept(builder);
cin
working on JSON parser
r178 builder.BuildDFA();
cin
JSON moved to Formats namespace...
r163
cin
working on JSON parser
r178 return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context);
cin
JSON moved to Formats namespace...
r163 }
cin
working on JSON parser
r178 #endregion
cin
refactoring complete, JSONParser rewritten
r180 readonly JSONScanner m_scanner;
cin
Reimplemented JsonXmlReader, added support for null values: JSON null values are...
r227 // json starts from the value context and may content even a single literal
MemberContext m_memberContext = MemberContext.MemberValue;
cin
JSON moved to Formats namespace...
r163
JSONElementType m_elementType;
object m_elementValue;
cin
refactoring complete, JSONParser rewritten
r180 string m_memberName = String.Empty;
Stack<ParserContext> m_stack = new Stack<ParserContext>();
ParserContext m_context = _jsonContext;
cin
JSON moved to Formats namespace...
r163
/// <summary>
/// Создает новый парсер на основе строки, содержащей JSON
/// </summary>
/// <param name="text"></param>
cin
refactoring complete, JSONParser rewritten
r180 public JSONParser(string text) {
cin
JSON moved to Formats namespace...
r163 Safe.ArgumentNotEmpty(text, "text");
cin
refactoring complete, JSONParser rewritten
r180 m_scanner = new JSONScanner(text);
cin
JSON moved to Formats namespace...
r163 }
/// <summary>
/// Создает новый экземпляр парсера, на основе текстового потока.
/// </summary>
/// <param name="reader">Текстовый поток.</param>
cin
refactoring complete, JSONParser rewritten
r180 public JSONParser(TextReader reader) {
cin
JSON moved to Formats namespace...
r163 Safe.ArgumentNotNull(reader, "reader");
cin
refactoring complete, JSONParser rewritten
r180 m_scanner = new JSONScanner(reader);
}
public int Level {
get { return m_stack.Count; }
cin
JSON moved to Formats namespace...
r163 }
/// <summary>
/// Тип текущего элемента на котором стоит парсер.
/// </summary>
public JSONElementType ElementType {
get { return m_elementType; }
}
/// <summary>
/// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда
/// пустая строка.
/// </summary>
public string ElementName {
cin
refactoring complete, JSONParser rewritten
r180 get { return m_memberName; }
cin
JSON moved to Formats namespace...
r163 }
/// <summary>
/// Значение элемента. Только для элементов типа <see cref="JSONElementType.Value"/>, для остальных <c>null</c>
/// </summary>
public object ElementValue {
get { return m_elementValue; }
}
/// <summary>
/// Читает слеюудущий объект из потока
/// </summary>
/// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns>
public bool Read() {
object tokenValue;
JsonTokenType tokenType;
cin
refactoring complete, JSONParser rewritten
r180
m_memberName = String.Empty;
cin
JSON moved to Formats namespace...
r163 while (m_scanner.ReadToken(out tokenValue, out tokenType)) {
cin
refactoring complete, JSONParser rewritten
r180 if(!m_context.Move(tokenType))
cin
JSON moved to Formats namespace...
r163 UnexpectedToken(tokenValue, tokenType);
cin
refactoring complete, JSONParser rewritten
r180
cin
JSON moved to Formats namespace...
r163 switch (tokenType) {
case JsonTokenType.BeginObject:
cin
refactoring complete, JSONParser rewritten
r180 m_stack.Push(m_context);
m_context = _objectContext;
cin
JSON moved to Formats namespace...
r163 m_elementValue = null;
m_memberContext = MemberContext.MemberName;
m_elementType = JSONElementType.BeginObject;
return true;
case JsonTokenType.EndObject:
cin
refactoring complete, JSONParser rewritten
r180 if (m_stack.Count == 0)
UnexpectedToken(tokenValue, tokenType);
m_context = m_stack.Pop();
cin
JSON moved to Formats namespace...
r163 m_elementValue = null;
m_elementType = JSONElementType.EndObject;
return true;
case JsonTokenType.BeginArray:
cin
refactoring complete, JSONParser rewritten
r180 m_stack.Push(m_context);
m_context = _arrayContext;
cin
JSON moved to Formats namespace...
r163 m_elementValue = null;
m_memberContext = MemberContext.MemberValue;
m_elementType = JSONElementType.BeginArray;
return true;
case JsonTokenType.EndArray:
cin
refactoring complete, JSONParser rewritten
r180 if (m_stack.Count == 0)
UnexpectedToken(tokenValue, tokenType);
m_context = m_stack.Pop();
cin
JSON moved to Formats namespace...
r163 m_elementValue = null;
m_elementType = JSONElementType.EndArray;
return true;
case JsonTokenType.String:
if (m_memberContext == MemberContext.MemberName) {
cin
refactoring complete, JSONParser rewritten
r180 m_memberName = (string)tokenValue;
cin
JSON moved to Formats namespace...
r163 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 = ParseLiteral((string)tokenValue);
return true;
case JsonTokenType.NameSeparator:
m_memberContext = MemberContext.MemberValue;
break;
case JsonTokenType.ValueSeparator:
cin
refactoring complete, JSONParser rewritten
r180 m_memberContext = m_context.ElementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
cin
JSON moved to Formats namespace...
r163 break;
default:
UnexpectedToken(tokenValue, tokenType);
break;
}
}
cin
refactoring complete, JSONParser rewritten
r180 if (m_context.ElementContext != JSONElementContext.None)
cin
JSON moved to Formats namespace...
r163 throw new ParserException("Unexpedted end of data");
cin
refactoring complete, JSONParser rewritten
r180
EOF = true;
cin
JSON moved to Formats namespace...
r163 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 {
cin
refactoring complete, JSONParser rewritten
r180 get;
private set;
cin
JSON moved to Formats namespace...
r163 }
cin
DFA refactoring
r165 protected override void Dispose(bool disposing) {
cin
refactoring complete, JSONParser rewritten
r180 if (disposing)
cin
RunnableComponent.Dispose(bool,Exception) changed to standart Dispose(bool)...
r208 m_scanner.Dispose();
cin
JSON moved to Formats namespace...
r163 }
/// <summary>
/// Переходит в конец текущего объекта.
/// </summary>
public void SeekElementEnd() {
var level = Level - 1;
Debug.Assert(level >= 0);
while (Level != level)
Read();
}
}
}