Mercurial > pub > ImplabNet
comparison 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 |
comparison
equal
deleted
inserted
replaced
228:6fa235c5a760 | 229:5f7a3e1d32b9 |
---|---|
10 struct JsonContext { | 10 struct JsonContext { |
11 public string localName; | 11 public string localName; |
12 public bool skip; | 12 public bool skip; |
13 } | 13 } |
14 | 14 |
15 JsonParser m_parser; | 15 JsonReader m_parser; |
16 JsonXmlReaderOptions m_options; | 16 JsonXmlReaderOptions m_options; |
17 JsonXmlReaderPosition m_position = JsonXmlReaderPosition.Initial; | 17 JsonXmlReaderPosition m_position = JsonXmlReaderPosition.Initial; |
18 XmlNameTable m_nameTable; | 18 XmlNameTable m_nameTable; |
19 | 19 |
20 readonly string m_jsonRootName; | 20 readonly string m_jsonRootName; |
55 readonly string m_xmlnsNamespace; | 55 readonly string m_xmlnsNamespace; |
56 readonly string m_xsiPrefix; | 56 readonly string m_xsiPrefix; |
57 readonly string m_xsiNamespace; | 57 readonly string m_xsiNamespace; |
58 | 58 |
59 | 59 |
60 public JsonXmlReader(JsonParser parser, JsonXmlReaderOptions options) { | 60 public JsonXmlReader(JsonReader parser, JsonXmlReaderOptions options) { |
61 Safe.ArgumentNotNull(parser, nameof(parser)); | 61 Safe.ArgumentNotNull(parser, nameof(parser)); |
62 m_parser = parser; | 62 m_parser = parser; |
63 | 63 |
64 m_options = options ?? new JsonXmlReaderOptions(); | 64 m_options = options ?? new JsonXmlReaderOptions(); |
65 | 65 |
75 m_xsiPrefix = m_nameTable.Add(XmlNameContext.XsiPrefix); | 75 m_xsiPrefix = m_nameTable.Add(XmlNameContext.XsiPrefix); |
76 m_xsiNamespace = m_nameTable.Add(XmlNameContext.XsiNamespace); | 76 m_xsiNamespace = m_nameTable.Add(XmlNameContext.XsiNamespace); |
77 | 77 |
78 // TODO validate m_jsonRootName, m_jsonArrayItemName | 78 // TODO validate m_jsonRootName, m_jsonArrayItemName |
79 | 79 |
80 m_context = new XmlNameContext(null); | 80 m_context = new XmlNameContext(null, 0); |
81 } | 81 } |
82 | 82 |
83 public override int AttributeCount { | 83 public override int AttributeCount { |
84 get { | 84 get { |
85 return m_attributes == null ? 0 : m_attributes.Length; | 85 return m_attributes == null ? 0 : m_attributes.Length; |
312 case XmlNodeType.Attribute: // after attribute only it's content can be iterated with ReadAttributeValue method | 312 case XmlNodeType.Attribute: // after attribute only it's content can be iterated with ReadAttributeValue method |
313 return false; | 313 return false; |
314 case XmlNodeType.Element: | 314 case XmlNodeType.Element: |
315 // if the elemnt is empty the next element will be it's sibling | 315 // if the elemnt is empty the next element will be it's sibling |
316 return m_isEmpty; | 316 return m_isEmpty; |
317 | |
318 case XmlNodeType.Document: | |
319 case XmlNodeType.DocumentFragment: | |
320 case XmlNodeType.Entity: | |
321 case XmlNodeType.Text: | |
322 case XmlNodeType.CDATA: | |
323 case XmlNodeType.EntityReference: | |
324 case XmlNodeType.ProcessingInstruction: | |
325 case XmlNodeType.Comment: | |
326 case XmlNodeType.DocumentType: | |
327 case XmlNodeType.Notation: | |
328 case XmlNodeType.Whitespace: | |
329 case XmlNodeType.SignificantWhitespace: | |
330 case XmlNodeType.EndElement: | |
331 case XmlNodeType.EndEntity: | |
332 case XmlNodeType.XmlDeclaration: | |
333 default: | 317 default: |
334 return true; | 318 return true; |
335 } | 319 } |
336 } | 320 } |
337 | 321 |
349 | 333 |
350 void ElementNode(string name, string ns, XmlSimpleAttribute[] attrs, bool empty) { | 334 void ElementNode(string name, string ns, XmlSimpleAttribute[] attrs, bool empty) { |
351 if (!IsSibling()) // the node is nested | 335 if (!IsSibling()) // the node is nested |
352 m_xmlDepth++; | 336 m_xmlDepth++; |
353 | 337 |
354 m_context = new XmlNameContext(m_context); | 338 var context = m_context; |
355 List<XmlSimpleAttribute> definedAttrs = null; | 339 List<XmlSimpleAttribute> definedAttrs = null; |
356 | 340 |
357 // define new namespaces | 341 // define new namespaces |
358 if (attrs != null) { | 342 if (attrs != null) { |
359 foreach (var attr in attrs) { | 343 foreach (var attr in attrs) { |
360 if (attr.QName.Name == "xmlns") { | 344 if (attr.QName.Name == "xmlns") { |
361 m_context.DefinePrefix(ConvertValueToString(attr.Value), string.Empty); | 345 if (context == m_context) |
346 context = new XmlNameContext(m_context, m_xmlDepth); | |
347 context.DefinePrefix(ConvertValueToString(attr.Value), string.Empty); | |
362 } else if (attr.Prefix == m_xmlnsPrefix) { | 348 } else if (attr.Prefix == m_xmlnsPrefix) { |
363 m_context.DefinePrefix(ConvertValueToString(attr.Value), attr.QName.Name); | 349 if (context == m_context) |
350 context = new XmlNameContext(m_context, m_xmlDepth); | |
351 context.DefinePrefix(ConvertValueToString(attr.Value), attr.QName.Name); | |
364 } else { | 352 } else { |
365 string attrPrefix; | 353 string attrPrefix; |
366 if (string.IsNullOrEmpty(attr.QName.Namespace)) | 354 if (string.IsNullOrEmpty(attr.QName.Namespace)) |
367 continue; | 355 continue; |
368 | 356 |
369 // auto-define prefixes | 357 // auto-define prefixes |
370 if (!m_context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) { | 358 if (!context.LookupNamespacePrefix(attr.QName.Namespace, out attrPrefix) || string.IsNullOrEmpty(attrPrefix)) { |
371 // new namespace prefix added | 359 // new namespace prefix added |
372 attrPrefix = m_context.CreateNamespacePrefix(attr.QName.Namespace); | 360 attrPrefix = context.CreateNamespacePrefix(attr.QName.Namespace); |
373 attr.Prefix = attrPrefix; | 361 attr.Prefix = attrPrefix; |
374 | 362 |
375 if (definedAttrs == null) | 363 if (definedAttrs == null) |
376 definedAttrs = new List<XmlSimpleAttribute>(); | 364 definedAttrs = new List<XmlSimpleAttribute>(); |
377 | 365 |
381 } | 369 } |
382 } | 370 } |
383 | 371 |
384 string p; | 372 string p; |
385 // auto-define prefixes | 373 // auto-define prefixes |
386 if (!m_context.LookupNamespacePrefix(ns, out p)) { | 374 if (!context.LookupNamespacePrefix(ns, out p)) { |
387 p = m_context.CreateNamespacePrefix(ns); | 375 if (context == m_context) |
376 context = new XmlNameContext(m_context, m_xmlDepth); | |
377 p = context.CreateNamespacePrefix(ns); | |
388 if (definedAttrs == null) | 378 if (definedAttrs == null) |
389 definedAttrs = new List<XmlSimpleAttribute>(); | 379 definedAttrs = new List<XmlSimpleAttribute>(); |
390 | 380 |
391 definedAttrs.Add(new XmlSimpleAttribute(p, m_xmlnsNamespace, m_xmlnsPrefix, ns)); | 381 definedAttrs.Add(new XmlSimpleAttribute(p, m_xmlnsNamespace, m_xmlnsPrefix, ns)); |
392 } | 382 } |
394 if (definedAttrs != null) { | 384 if (definedAttrs != null) { |
395 if (attrs != null) | 385 if (attrs != null) |
396 definedAttrs.AddRange(attrs); | 386 definedAttrs.AddRange(attrs); |
397 attrs = definedAttrs.ToArray(); | 387 attrs = definedAttrs.ToArray(); |
398 } | 388 } |
389 | |
390 if (!empty) | |
391 m_context = context; | |
399 | 392 |
400 m_nodeType = XmlNodeType.Element; | 393 m_nodeType = XmlNodeType.Element; |
401 m_qName = new XmlQualifiedName(name, ns); | 394 m_qName = new XmlQualifiedName(name, ns); |
402 m_prefix = p; | 395 m_prefix = p; |
403 m_value = null; | 396 m_value = null; |
404 m_isEmpty = empty; | 397 m_isEmpty = empty; |
405 m_attributes = attrs; | 398 m_attributes = attrs; |
406 } | 399 } |
407 | 400 |
408 void EndElementNode(string name, string ns) { | 401 void EndElementNode(string name, string ns) { |
409 if (IsSibling()) // closing the element which has children | 402 if (IsSibling()) { |
403 // closing the element which has children | |
410 m_xmlDepth--; | 404 m_xmlDepth--; |
405 } | |
411 | 406 |
412 string p; | 407 string p; |
413 if (!m_context.LookupNamespacePrefix(ns, out p)) | 408 if (!m_context.LookupNamespacePrefix(ns, out p)) |
414 throw new Exception($"Failed to lookup namespace '{ns}'"); | 409 throw new Exception($"Failed to lookup namespace '{ns}'"); |
415 | 410 |
416 m_context = m_context.ParentContext; | 411 if (m_context.Depth == m_xmlDepth) |
412 m_context = m_context.ParentContext; | |
413 | |
417 m_nodeType = XmlNodeType.EndElement; | 414 m_nodeType = XmlNodeType.EndElement; |
418 m_prefix = p; | 415 m_prefix = p; |
419 m_qName = new XmlQualifiedName(name, ns); | 416 m_qName = new XmlQualifiedName(name, ns); |
420 m_value = null; | 417 m_value = null; |
421 m_attributes = null; | 418 m_attributes = null; |
454 new XmlSimpleAttribute(m_jsonPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_jsonNamespace) | 451 new XmlSimpleAttribute(m_jsonPrefix, m_xmlnsNamespace, m_xmlnsPrefix, m_jsonNamespace) |
455 }; | 452 }; |
456 break; | 453 break; |
457 case JsonXmlReaderPosition.ValueElement: | 454 case JsonXmlReaderPosition.ValueElement: |
458 if (!m_isEmpty) { | 455 if (!m_isEmpty) { |
459 ValueNode(m_parser.ElementValue); | 456 if (m_parser.ElementValue != null && !m_parser.ElementValue.Equals(string.Empty)) |
457 ValueNode(m_parser.ElementValue); | |
458 else | |
459 goto case JsonXmlReaderPosition.ValueContent; | |
460 m_position = JsonXmlReaderPosition.ValueContent; | 460 m_position = JsonXmlReaderPosition.ValueContent; |
461 return true; | 461 return true; |
462 } else { | 462 } else { |
463 m_position = JsonXmlReaderPosition.ValueEndElement; | 463 m_position = JsonXmlReaderPosition.ValueEndElement; |
464 break; | 464 break; |
519 new XmlSimpleAttribute("nil", m_xsiNamespace, m_xsiPrefix, true) | 519 new XmlSimpleAttribute("nil", m_xsiNamespace, m_xsiPrefix, true) |
520 }, | 520 }, |
521 true | 521 true |
522 ); | 522 ); |
523 else | 523 else |
524 ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue as string == string.Empty); | 524 ElementNode(m_jsonValueName, m_jsonNamespace, elementAttrs, m_parser.ElementValue.Equals(string.Empty)); |
525 break; | 525 break; |
526 default: | 526 default: |
527 throw new Exception($"Unexpected JSON element {m_parser.ElementType}: {m_parser.ElementName}"); | 527 throw new Exception($"Unexpected JSON element {m_parser.ElementType}: {m_parser.ElementName}"); |
528 } | 528 } |
529 return true; | 529 return true; |