##// END OF EJS Templates
Added tag release v2.1 for changeset f1da3afc3521
Added tag release v2.1 for changeset f1da3afc3521

File last commit:

r180:c32688129f14 ref20160224
r193:0d69c0d6de0d default
Show More
JSONXmlReader.cs
335 lines | 11.7 KiB | text/x-csharp | CSharpLexer
using Implab;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Xml;
namespace Implab.Formats.JSON {
public class JSONXmlReader : XmlReader {
enum ValueContext {
Undefined,
ElementStart,
ElementValue,
ElementEnd,
ElementEmpty
}
struct LocalNameContext {
public string localName;
public bool isArray;
}
JSONParser m_parser;
ValueContext m_valueContext;
ReadState m_state = ReadState.Initial;
Stack<LocalNameContext> m_localNameStack = new Stack<LocalNameContext>();
LocalNameContext m_localName;
int m_depthCorrection;
readonly string m_rootName;
readonly string m_prefix;
readonly string m_namespaceUri;
readonly bool m_flattenArrays;
readonly string m_arrayItemName;
readonly XmlNameTable m_nameTable;
JSONXmlReader(JSONParser parser, JSONXmlReaderOptions options) {
m_parser = parser;
if (options != null) {
m_prefix = options.NodesPrefix ?? String.Empty;
m_namespaceUri = options.NamespaceURI ?? String.Empty;
m_rootName = options.RootName ?? "json";
m_flattenArrays = options.FlattenArrays;
m_arrayItemName = options.ArrayItemName ?? "item";
m_nameTable = options.NameTable ?? new NameTable();
} else {
m_prefix = String.Empty;
m_namespaceUri = String.Empty;
m_rootName = "json";
m_flattenArrays = false;
m_arrayItemName = "item";
m_nameTable = new NameTable();
}
}
/// <summary>
/// Always 0, JSON doesn't support attributes
/// </summary>
public override int AttributeCount {
get { return 0; }
}
public override string BaseURI {
get { return String.Empty; }
}
public override int Depth {
get {
return m_localNameStack.Count + m_depthCorrection;
}
}
public override bool EOF {
get { return m_parser.EOF; }
}
/// <summary>
/// Always throws an exception
/// </summary>
/// <param name="i"></param>
/// <returns></returns>
public override string GetAttribute(int i) {
throw new ArgumentOutOfRangeException();
}
/// <summary>
/// Always returns empty string
/// </summary>
/// <param name="name"></param>
/// <param name="namespaceURI"></param>
/// <returns></returns>
public override string GetAttribute(string name, string namespaceURI) {
return String.Empty;
}
/// <summary>
/// Always returns empty string
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public override string GetAttribute(string name) {
return String.Empty;
}
public override bool IsEmptyElement {
get { return m_parser.ElementType == JSONElementType.Value && m_valueContext == ValueContext.ElementEmpty; }
}
public override string LocalName {
get { return m_localName.localName; }
}
public override string LookupNamespace(string prefix) {
if (String.IsNullOrEmpty(prefix) || prefix == m_prefix)
return m_namespaceUri;
return String.Empty;
}
public override bool MoveToAttribute(string name, string ns) {
return false;
}
public override bool MoveToAttribute(string name) {
return false;
}
public override bool MoveToElement() {
return false;
}
public override bool MoveToFirstAttribute() {
return false;
}
public override bool MoveToNextAttribute() {
return false;
}
public override XmlNameTable NameTable {
get { return m_nameTable; }
}
public override string NamespaceURI {
get { return m_namespaceUri; }
}
public override XmlNodeType NodeType {
get {
switch (m_parser.ElementType) {
case JSONElementType.BeginObject:
case JSONElementType.BeginArray:
return XmlNodeType.Element;
case JSONElementType.EndObject:
case JSONElementType.EndArray:
return XmlNodeType.EndElement;
case JSONElementType.Value:
switch (m_valueContext) {
case ValueContext.ElementStart:
case ValueContext.ElementEmpty:
return XmlNodeType.Element;
case ValueContext.ElementValue:
return XmlNodeType.Text;
case ValueContext.ElementEnd:
return XmlNodeType.EndElement;
default:
throw new InvalidOperationException();
}
default:
throw new InvalidOperationException();
}
}
}
public override string Prefix {
get { return m_prefix; }
}
public override bool Read() {
if (m_state != ReadState.Interactive && m_state != ReadState.Initial)
return false;
if (m_state == ReadState.Initial)
m_state = ReadState.Interactive;
try {
switch (m_parser.ElementType) {
case JSONElementType.Value:
switch (m_valueContext) {
case ValueContext.ElementStart:
SetLocalName(String.Empty);
m_valueContext = ValueContext.ElementValue;
return true;
case ValueContext.ElementValue:
RestoreLocalName();
m_valueContext = ValueContext.ElementEnd;
return true;
case ValueContext.ElementEmpty:
case ValueContext.ElementEnd:
RestoreLocalName();
break;
}
break;
case JSONElementType.EndArray:
case JSONElementType.EndObject:
RestoreLocalName();
break;
}
string itemName = m_parser.ElementType == JSONElementType.None ? m_rootName : m_flattenArrays ? m_localName.localName : m_arrayItemName;
while (m_parser.Read()) {
if (!String.IsNullOrEmpty(m_parser.ElementName))
itemName = m_parser.ElementName;
switch (m_parser.ElementType) {
case JSONElementType.BeginArray:
if (m_flattenArrays && !m_localName.isArray) {
m_depthCorrection--;
SetLocalName(itemName, true);
continue;
}
SetLocalName(itemName, true);
break;
case JSONElementType.BeginObject:
SetLocalName(itemName);
break;
case JSONElementType.EndArray:
if (m_flattenArrays && !m_localNameStack.Peek().isArray) {
RestoreLocalName();
m_depthCorrection++;
continue;
}
break;
case JSONElementType.EndObject:
break;
case JSONElementType.Value:
SetLocalName(itemName);
m_valueContext = m_parser.ElementValue == null ? ValueContext.ElementEmpty : ValueContext.ElementStart;
break;
}
return true;
}
m_state = ReadState.EndOfFile;
return false;
} catch {
m_state = ReadState.Error;
throw;
}
}
public override bool ReadAttributeValue() {
return false;
}
public override ReadState ReadState {
get { return m_state; }
}
public override void ResolveEntity() {
// do nothing
}
public override string Value {
get {
if (m_parser.ElementValue == null)
return String.Empty;
if (Convert.GetTypeCode(m_parser.ElementValue) == TypeCode.Double)
return ((double)m_parser.ElementValue).ToString(CultureInfo.InvariantCulture);
return m_parser.ElementValue.ToString();
}
}
void SetLocalName(string name) {
m_localNameStack.Push(m_localName);
m_localName.localName = name;
m_localName.isArray = false;
}
void SetLocalName(string name, bool isArray) {
m_localNameStack.Push(m_localName);
m_localName.localName = name;
m_localName.isArray = isArray;
}
void RestoreLocalName() {
m_localName = m_localNameStack.Pop();
}
public override void Close() {
}
protected override void Dispose(bool disposing) {
#if MONO
disposing = true;
#endif
if (disposing) {
m_parser.Dispose();
}
base.Dispose(disposing);
}
public static JSONXmlReader Create(string file, JSONXmlReaderOptions options) {
return Create(File.OpenText(file), options);
}
/// <summary>
/// Creates the XmlReader for the specified text stream with JSON data.
/// </summary>
/// <param name="reader">Text reader.</param>
/// <param name="options">Options.</param>
/// <remarks>
/// The reader will be disposed when the XmlReader is disposed.
/// </remarks>
public static JSONXmlReader Create(TextReader reader, JSONXmlReaderOptions options) {
return new JSONXmlReader(new JSONParser(reader), options);
}
/// <summary>
/// Creates the XmlReader for the specified stream with JSON data.
/// </summary>
/// <param name="stream">Stream.</param>
/// <param name="options">Options.</param>
/// <remarks>
/// The stream will be disposed when the XmlReader is disposed.
/// </remarks>
public static JSONXmlReader Create(Stream stream, JSONXmlReaderOptions options) {
Safe.ArgumentNotNull(stream, "stream");
// HACK don't dispose StreaReader to keep stream opened
return Create(new StreamReader(stream), options);
}
}
}