diff Implab/Formats/JSON/JSONXmlReader.cs @ 192:f1da3afc3521 release v2.1

Слияние с v2
author cin
date Fri, 22 Apr 2016 13:10:34 +0300
parents c32688129f14
children 8222a2ab3ab7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Implab/Formats/JSON/JSONXmlReader.cs	Fri Apr 22 13:10:34 2016 +0300
@@ -0,0 +1,335 @@
+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);
+        }
+    }
+}