Mercurial > pub > ImplabNet
annotate Implab/JSON/JSONXmlReader.cs @ 72:d67b95eddaf4 v2
promises refactoring
| author | cin |
|---|---|
| date | Thu, 04 Sep 2014 18:47:12 +0400 |
| parents | a809805210d1 |
| children | 05f74c39a143 |
| rev | line source |
|---|---|
| 58 | 1 using Implab; |
| 2 using Implab.Parsing; | |
| 3 using System; | |
| 4 using System.Collections.Generic; | |
|
63
908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin
parents:
60
diff
changeset
|
5 using System.Globalization; |
| 60 | 6 using System.IO; |
| 58 | 7 using System.Linq; |
| 8 using System.Text; | |
| 9 using System.Threading.Tasks; | |
| 10 using System.Xml; | |
| 11 | |
| 60 | 12 namespace Implab.JSON { |
| 58 | 13 public class JSONXmlReader : XmlReader { |
| 14 | |
| 15 enum ValueContext { | |
| 16 Undefined, | |
| 17 ElementStart, | |
| 18 ElementValue, | |
| 19 ElementEnd, | |
| 20 ElementEmpty | |
| 21 } | |
| 22 | |
| 23 struct LocalNameContext { | |
| 24 public string localName; | |
| 25 public bool isArray; | |
| 26 } | |
| 27 | |
| 28 JSONParser m_parser; | |
| 29 ValueContext m_valueContext; | |
| 30 ReadState m_state = ReadState.Initial; | |
| 31 Stack<LocalNameContext> m_localNameStack = new Stack<LocalNameContext>(); | |
| 32 LocalNameContext m_localName; | |
| 33 int m_depthCorrection = 0; | |
| 34 | |
| 60 | 35 readonly string m_rootName; |
| 36 readonly string m_prefix; | |
| 37 readonly string m_namespaceUri; | |
| 38 readonly bool m_flattenArrays; | |
| 39 readonly string m_arrayItemName; | |
| 40 readonly XmlNameTable m_nameTable; | |
|
63
908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin
parents:
60
diff
changeset
|
41 |
| 64 | 42 JSONXmlReader(JSONParser parser, JSONXmlReaderOptions options) { |
| 58 | 43 m_parser = parser; |
| 60 | 44 |
| 45 if (options != null) { | |
| 46 m_prefix = options.NodesPrefix ?? String.Empty; | |
| 47 m_namespaceUri = options.NamespaceURI ?? String.Empty; | |
| 48 m_rootName = options.RootName ?? "json"; | |
| 49 m_flattenArrays = options.FlattenArrays; | |
| 50 m_arrayItemName = options.ArrayItemName ?? "item"; | |
| 51 m_nameTable = options.NameTable ?? new NameTable(); | |
| 52 } else { | |
| 53 m_prefix = String.Empty; | |
| 54 m_namespaceUri = String.Empty; | |
| 55 m_rootName = "json"; | |
| 56 m_flattenArrays = false; | |
| 57 m_arrayItemName = "item"; | |
| 58 m_nameTable = new NameTable(); | |
| 59 } | |
| 58 | 60 } |
| 61 | |
| 62 /// <summary> | |
| 63 /// Always 0, JSON doesn't support attributes | |
| 64 /// </summary> | |
| 65 public override int AttributeCount { | |
| 66 get { return 0; } | |
| 67 } | |
| 68 | |
| 69 public override string BaseURI { | |
| 70 get { return String.Empty; } | |
| 71 } | |
| 72 | |
| 73 public override int Depth { | |
| 74 get { | |
|
63
908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin
parents:
60
diff
changeset
|
75 return m_localNameStack.Count + m_depthCorrection; |
| 58 | 76 } |
| 77 } | |
| 78 | |
| 79 public override bool EOF { | |
| 80 get { return m_parser.EOF; } | |
| 81 } | |
| 82 | |
| 83 /// <summary> | |
| 84 /// Always throws an exception | |
| 85 /// </summary> | |
| 86 /// <param name="i"></param> | |
| 87 /// <returns></returns> | |
| 88 public override string GetAttribute(int i) { | |
| 89 throw new ArgumentOutOfRangeException(); | |
| 90 } | |
| 91 | |
| 92 /// <summary> | |
| 93 /// Always returns empty string | |
| 94 /// </summary> | |
| 95 /// <param name="name"></param> | |
| 96 /// <param name="namespaceURI"></param> | |
| 97 /// <returns></returns> | |
| 98 public override string GetAttribute(string name, string namespaceURI) { | |
| 99 return String.Empty; | |
| 100 } | |
| 101 | |
| 102 /// <summary> | |
| 103 /// Always returns empty string | |
| 104 /// </summary> | |
| 105 /// <param name="name"></param> | |
| 106 /// <returns></returns> | |
| 107 public override string GetAttribute(string name) { | |
| 108 return String.Empty; | |
| 109 } | |
| 110 | |
| 111 public override bool IsEmptyElement { | |
| 112 get { return m_parser.ElementType == JSONElementType.Value && m_valueContext == ValueContext.ElementEmpty; } | |
| 113 } | |
| 114 | |
| 115 public override string LocalName { | |
| 116 get { return m_localName.localName; } | |
| 117 } | |
| 118 | |
| 119 public override string LookupNamespace(string prefix) { | |
| 120 if (String.IsNullOrEmpty(prefix) || prefix == m_prefix) | |
| 121 return m_namespaceUri; | |
| 122 else | |
| 123 return String.Empty; | |
| 124 } | |
| 125 | |
| 126 public override bool MoveToAttribute(string name, string ns) { | |
| 127 return false; | |
| 128 } | |
| 129 | |
| 130 public override bool MoveToAttribute(string name) { | |
| 131 return false; | |
| 132 } | |
| 133 | |
| 134 public override bool MoveToElement() { | |
| 135 return false; | |
| 136 } | |
| 137 | |
| 138 public override bool MoveToFirstAttribute() { | |
| 139 return false; | |
| 140 } | |
| 141 | |
| 142 public override bool MoveToNextAttribute() { | |
| 143 return false; | |
| 144 } | |
| 145 | |
| 146 public override XmlNameTable NameTable { | |
| 147 get { return m_nameTable; } | |
| 148 } | |
| 149 | |
| 150 public override string NamespaceURI { | |
| 151 get { return m_namespaceUri; } | |
| 152 } | |
| 153 | |
| 154 public override XmlNodeType NodeType { | |
| 155 get { | |
| 156 switch (m_parser.ElementType) { | |
| 157 case JSONElementType.BeginObject: | |
| 158 case JSONElementType.BeginArray: | |
| 159 return XmlNodeType.Element; | |
| 160 case JSONElementType.EndObject: | |
| 161 case JSONElementType.EndArray: | |
| 162 return XmlNodeType.EndElement; | |
| 163 case JSONElementType.Value: | |
| 164 switch (m_valueContext) { | |
| 165 case ValueContext.ElementStart: | |
| 166 case ValueContext.ElementEmpty: | |
| 167 return XmlNodeType.Element; | |
| 168 case ValueContext.ElementValue: | |
| 169 return XmlNodeType.Text; | |
| 170 case ValueContext.ElementEnd: | |
| 171 return XmlNodeType.EndElement; | |
| 172 default: | |
| 173 throw new InvalidOperationException(); | |
| 174 } | |
| 175 default: | |
| 176 throw new InvalidOperationException(); | |
| 177 } | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 public override string Prefix { | |
| 182 get { return m_prefix; } | |
| 183 } | |
| 184 | |
| 185 public override bool Read() { | |
| 186 if (m_state != System.Xml.ReadState.Interactive && m_state != System.Xml.ReadState.Initial) | |
| 187 return false; | |
| 188 | |
| 189 if (m_state == ReadState.Initial) | |
| 190 m_state = System.Xml.ReadState.Interactive; | |
| 191 | |
| 192 try { | |
| 193 switch (m_parser.ElementType) { | |
| 194 case JSONElementType.Value: | |
| 195 switch (m_valueContext) { | |
| 196 case ValueContext.ElementStart: | |
| 197 SetLocalName(String.Empty); | |
| 198 m_valueContext = ValueContext.ElementValue; | |
| 199 return true; | |
| 200 case ValueContext.ElementValue: | |
| 201 RestoreLocalName(); | |
| 202 m_valueContext = ValueContext.ElementEnd; | |
| 203 return true; | |
| 204 case ValueContext.ElementEmpty: | |
| 205 case ValueContext.ElementEnd: | |
| 206 RestoreLocalName(); | |
| 207 break; | |
| 208 } | |
| 209 break; | |
| 210 case JSONElementType.EndArray: | |
| 211 case JSONElementType.EndObject: | |
| 212 RestoreLocalName(); | |
| 213 break; | |
| 214 } | |
| 60 | 215 string itemName = m_parser.ElementType == JSONElementType.None ? m_rootName : m_flattenArrays ? m_localName.localName : m_arrayItemName; |
| 58 | 216 while (m_parser.Read()) { |
| 217 if (!String.IsNullOrEmpty(m_parser.ElementName)) | |
| 218 itemName = m_parser.ElementName; | |
| 219 | |
| 220 switch (m_parser.ElementType) { | |
| 221 case JSONElementType.BeginArray: | |
| 222 if (m_flattenArrays && !m_localName.isArray) { | |
| 223 m_depthCorrection--; | |
| 224 SetLocalName(itemName, true); | |
| 225 continue; | |
| 226 } else { | |
| 227 SetLocalName(itemName, true); | |
| 228 } | |
| 229 break; | |
| 230 case JSONElementType.BeginObject: | |
| 231 SetLocalName(itemName); | |
| 232 break; | |
| 233 case JSONElementType.EndArray: | |
| 234 if (m_flattenArrays && !m_localNameStack.Peek().isArray) { | |
| 235 RestoreLocalName(); | |
| 236 m_depthCorrection++; | |
| 237 continue; | |
| 238 } | |
| 239 break; | |
| 240 case JSONElementType.EndObject: | |
| 241 break; | |
| 242 case JSONElementType.Value: | |
| 243 SetLocalName(itemName); | |
| 244 m_valueContext = m_parser.ElementValue == null ? ValueContext.ElementEmpty : ValueContext.ElementStart; | |
| 245 break; | |
| 246 default: | |
| 247 break; | |
| 248 } | |
| 249 return true; | |
| 250 } | |
| 251 | |
| 252 m_state = System.Xml.ReadState.EndOfFile; | |
| 253 return false; | |
| 254 } catch { | |
| 255 m_state = System.Xml.ReadState.Error; | |
| 256 throw; | |
| 257 } | |
| 258 } | |
| 259 | |
| 260 public override bool ReadAttributeValue() { | |
| 261 return false; | |
| 262 } | |
| 263 | |
| 264 public override ReadState ReadState { | |
| 265 get { return m_state; } | |
| 266 } | |
| 267 | |
| 268 public override void ResolveEntity() { | |
| 269 // do nothing | |
| 270 } | |
| 271 | |
| 272 public override string Value { | |
|
63
908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin
parents:
60
diff
changeset
|
273 get { |
|
908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin
parents:
60
diff
changeset
|
274 if (m_parser.ElementValue == null) |
|
908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin
parents:
60
diff
changeset
|
275 return String.Empty; |
|
908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin
parents:
60
diff
changeset
|
276 if (Convert.GetTypeCode(m_parser.ElementValue) == TypeCode.Double) |
|
908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin
parents:
60
diff
changeset
|
277 return ((double)m_parser.ElementValue).ToString(CultureInfo.InvariantCulture); |
|
908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin
parents:
60
diff
changeset
|
278 else |
|
908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin
parents:
60
diff
changeset
|
279 return (string)m_parser.ElementValue; |
|
908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin
parents:
60
diff
changeset
|
280 } |
| 58 | 281 } |
| 282 | |
| 283 void SetLocalName(string name) { | |
| 284 m_localNameStack.Push(m_localName); | |
| 285 m_localName.localName = name; | |
| 286 m_localName.isArray = false; | |
| 287 } | |
| 288 | |
| 289 void SetLocalName(string name, bool isArray) { | |
| 290 m_localNameStack.Push(m_localName); | |
| 291 m_localName.localName = name; | |
| 292 m_localName.isArray = isArray; | |
| 293 } | |
| 294 | |
| 295 void RestoreLocalName() { | |
| 296 m_localName = m_localNameStack.Pop(); | |
| 297 } | |
| 298 | |
| 299 public override void Close() { | |
|
63
908b4f340c69
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin
parents:
60
diff
changeset
|
300 |
| 58 | 301 } |
| 59 | 302 |
| 303 protected override void Dispose(bool disposing) { | |
| 304 if (disposing) { | |
| 64 | 305 m_parser.Dispose(); |
| 59 | 306 } |
| 307 base.Dispose(disposing); | |
| 308 } | |
| 309 | |
| 64 | 310 public static JSONXmlReader Create(string file, JSONXmlReaderOptions options) { |
| 311 return Create(File.OpenText(file), options); | |
| 312 } | |
| 60 | 313 |
| 64 | 314 public static JSONXmlReader Create(TextReader reader, JSONXmlReaderOptions options) { |
| 315 return new JSONXmlReader(new JSONParser(reader, true), options); | |
| 316 } | |
| 317 | |
| 318 public static JSONXmlReader Create(Stream stream, JSONXmlReaderOptions options) { | |
| 319 Safe.ArgumentNotNull(stream, "stream"); | |
| 320 // HACK don't dispose StreaReader to keep stream opened | |
| 321 return Create(new StreamReader(stream), options); | |
| 60 | 322 } |
| 58 | 323 } |
| 324 } |
