diff Implab/Xml/JsonXmlReader.cs @ 229:5f7a3e1d32b9 v2

JsonXmlReader performance tuning JsonScanner now operates strings and doesn't parses number and literals. Added SerializationHelpers to common serialize/deserialize operations
author cin
date Tue, 12 Sep 2017 19:07:42 +0300
parents 6fa235c5a760
children 302ca905c19e
line wrap: on
line diff
--- a/Implab/Xml/JsonXmlReader.cs	Tue Sep 12 01:19:12 2017 +0300
+++ b/Implab/Xml/JsonXmlReader.cs	Tue Sep 12 19:07:42 2017 +0300
@@ -12,7 +12,7 @@
             public bool skip;
         }
 
-        JsonParser m_parser;
+        JsonReader m_parser;
         JsonXmlReaderOptions m_options;
         JsonXmlReaderPosition m_position = JsonXmlReaderPosition.Initial;
         XmlNameTable m_nameTable;
@@ -57,7 +57,7 @@
         readonly string m_xsiNamespace;
 
 
-        public JsonXmlReader(JsonParser parser, JsonXmlReaderOptions options) {
+        public JsonXmlReader(JsonReader parser, JsonXmlReaderOptions options) {
             Safe.ArgumentNotNull(parser, nameof(parser));
             m_parser = parser;
 
@@ -77,7 +77,7 @@
 
             // TODO validate m_jsonRootName, m_jsonArrayItemName
 
-            m_context = new XmlNameContext(null);
+            m_context = new XmlNameContext(null, 0);
         }
 
         public override int AttributeCount {
@@ -314,22 +314,6 @@
                 case XmlNodeType.Element:
                     // if the elemnt is empty the next element will be it's sibling
                     return m_isEmpty;
-
-                case XmlNodeType.Document:
-                case XmlNodeType.DocumentFragment:
-                case XmlNodeType.Entity:
-                case XmlNodeType.Text:
-                case XmlNodeType.CDATA:
-                case XmlNodeType.EntityReference:
-                case XmlNodeType.ProcessingInstruction:
-                case XmlNodeType.Comment:
-                case XmlNodeType.DocumentType:
-                case XmlNodeType.Notation:
-                case XmlNodeType.Whitespace:
-                case XmlNodeType.SignificantWhitespace:
-                case XmlNodeType.EndElement:
-                case XmlNodeType.EndEntity:
-                case XmlNodeType.XmlDeclaration:
                 default:
                     return true;
             }
@@ -351,25 +335,29 @@
             if (!IsSibling()) // the node is nested
                 m_xmlDepth++;
 
-            m_context = new XmlNameContext(m_context);
+            var context = m_context;
             List<XmlSimpleAttribute> definedAttrs = null;
 
             // define new namespaces
             if (attrs != null) {
                 foreach (var attr in attrs) {
                     if (attr.QName.Name == "xmlns") {
-                        m_context.DefinePrefix(ConvertValueToString(attr.Value), string.Empty);
+                        if (context == m_context)
+                             context = new XmlNameContext(m_context, m_xmlDepth);
+                        context.DefinePrefix(ConvertValueToString(attr.Value), string.Empty);
                     } else if (attr.Prefix == m_xmlnsPrefix) {
-                        m_context.DefinePrefix(ConvertValueToString(attr.Value), attr.QName.Name);
+                        if (context == m_context)
+                            context = new XmlNameContext(m_context, m_xmlDepth);
+                        context.DefinePrefix(ConvertValueToString(attr.Value), attr.QName.Name);
                     } else {
                         string attrPrefix;
                         if (string.IsNullOrEmpty(attr.QName.Namespace))
                             continue;
 
                         // auto-define prefixes
-                        if (!m_context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) {
+                        if (!context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) {
                             // new namespace prefix added
-                            attrPrefix = m_context.CreateNamespacePrefix(attr.QName.Namespace);
+                            attrPrefix = context.CreateNamespacePrefix(attr.QName.Namespace);
                             attr.Prefix = attrPrefix;
 
                             if (definedAttrs == null)
@@ -383,8 +371,10 @@
 
             string p;
             // auto-define prefixes
-            if (!m_context.LookupNamespacePrefix(ns, out p)) {
-                p = m_context.CreateNamespacePrefix(ns);
+            if (!context.LookupNamespacePrefix(ns, out p)) {
+                if (context == m_context)
+                    context = new XmlNameContext(m_context, m_xmlDepth);
+                p = context.CreateNamespacePrefix(ns);
                 if (definedAttrs == null)
                     definedAttrs = new List<XmlSimpleAttribute>();
 
@@ -397,6 +387,9 @@
                 attrs = definedAttrs.ToArray();
             }
 
+            if (!empty)
+                m_context = context;
+
             m_nodeType = XmlNodeType.Element;
             m_qName = new XmlQualifiedName(name, ns);
             m_prefix = p;
@@ -406,14 +399,18 @@
         }
 
         void EndElementNode(string name, string ns) {
-            if (IsSibling()) // closing the element which has children
+            if (IsSibling()) {
+                // closing the element which has children
                 m_xmlDepth--;
+            }
 
             string p;
             if (!m_context.LookupNamespacePrefix(ns, out p))
                 throw new Exception($"Failed to lookup namespace '{ns}'");
 
-            m_context = m_context.ParentContext;
+            if (m_context.Depth == m_xmlDepth)
+                m_context = m_context.ParentContext;
+
             m_nodeType = XmlNodeType.EndElement;
             m_prefix = p;
             m_qName = new XmlQualifiedName(name, ns);
@@ -456,7 +453,10 @@
                         break;
                     case JsonXmlReaderPosition.ValueElement:
                         if (!m_isEmpty) {
-                            ValueNode(m_parser.ElementValue);
+                            if (m_parser.ElementValue != null && !m_parser.ElementValue.Equals(string.Empty))
+                                ValueNode(m_parser.ElementValue);
+                            else
+                                goto case JsonXmlReaderPosition.ValueContent;
                             m_position = JsonXmlReaderPosition.ValueContent;
                             return true;
                         } else {
@@ -521,7 +521,7 @@
                                     true
                                 );
                             else
-                                ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue as string == string.Empty);
+                                ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue.Equals(string.Empty));
                             break;
                         default:
                             throw new Exception($"Unexpected JSON element {m_parser.ElementType}: {m_parser.ElementName}");