Mercurial > pub > ImplabNet
view Implab/JSON/JSONXmlReader.cs @ 63:908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
author | cin |
---|---|
date | Mon, 23 Jun 2014 17:34:40 +0400 |
parents | 10c7337d29e7 |
children | a809805210d1 |
line wrap: on
line source
using Implab; using Implab.Parsing; using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; namespace Implab.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 = 0; readonly string m_rootName; readonly string m_prefix; readonly string m_namespaceUri; readonly bool m_flattenArrays; readonly string m_arrayItemName; readonly XmlNameTable m_nameTable; readonly bool m_disposeParser; public JSONXmlReader(JSONParser parser, JSONXmlReaderOptions options) { Safe.ArgumentNotNull(parser, "parser"); 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(); m_disposeParser = options.DisposeParser; } else { m_prefix = String.Empty; m_namespaceUri = String.Empty; m_rootName = "json"; m_flattenArrays = false; m_arrayItemName = "item"; m_nameTable = new NameTable(); m_disposeParser = false; } } /// <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; else 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 != System.Xml.ReadState.Interactive && m_state != System.Xml.ReadState.Initial) return false; if (m_state == ReadState.Initial) m_state = System.Xml.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; } else { 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; default: break; } return true; } m_state = System.Xml.ReadState.EndOfFile; return false; } catch { m_state = System.Xml.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); else return (string)m_parser.ElementValue; } } 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 (disposing) { if (m_disposeParser) m_parser.Dispose(); } base.Dispose(disposing); } public static JSONXmlReader OpenFile(string file, JSONXmlReaderOptions options) { var stream = File.OpenText(file); var parser = new JSONParser(stream, true); return new JSONXmlReader(parser, options); } } }