Mercurial > pub > ImplabNet
comparison Implab/Formats/JSON/JSONXmlReader.cs @ 163:419aa51b04fd ref20160224
JSON moved to Formats namespace
Working in RegularDFA
author | cin |
---|---|
date | Wed, 24 Feb 2016 20:12:52 +0300 |
parents | |
children | c32688129f14 |
comparison
equal
deleted
inserted
replaced
162:0526412bbb26 | 163:419aa51b04fd |
---|---|
1 using Implab; | |
2 using Implab.Parsing; | |
3 using System; | |
4 using System.Collections.Generic; | |
5 using System.Globalization; | |
6 using System.IO; | |
7 using System.Linq; | |
8 using System.Text; | |
9 using System.Threading.Tasks; | |
10 using System.Xml; | |
11 | |
12 namespace Implab.JSON { | |
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 | |
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; | |
41 | |
42 JSONXmlReader(JSONParser parser, JSONXmlReaderOptions options) { | |
43 m_parser = parser; | |
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 } | |
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 { | |
75 return m_localNameStack.Count + m_depthCorrection; | |
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 } | |
215 string itemName = m_parser.ElementType == JSONElementType.None ? m_rootName : m_flattenArrays ? m_localName.localName : m_arrayItemName; | |
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 { | |
273 get { | |
274 if (m_parser.ElementValue == null) | |
275 return String.Empty; | |
276 if (Convert.GetTypeCode(m_parser.ElementValue) == TypeCode.Double) | |
277 return ((double)m_parser.ElementValue).ToString(CultureInfo.InvariantCulture); | |
278 else | |
279 return m_parser.ElementValue.ToString(); | |
280 } | |
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() { | |
300 | |
301 } | |
302 | |
303 protected override void Dispose(bool disposing) { | |
304 #if MONO | |
305 disposing = true; | |
306 #endif | |
307 if (disposing) { | |
308 m_parser.Dispose(); | |
309 } | |
310 base.Dispose(disposing); | |
311 } | |
312 | |
313 public static JSONXmlReader Create(string file, JSONXmlReaderOptions options) { | |
314 return Create(File.OpenText(file), options); | |
315 } | |
316 | |
317 /// <summary> | |
318 /// Creates the XmlReader for the specified text stream with JSON data. | |
319 /// </summary> | |
320 /// <param name="reader">Text reader.</param> | |
321 /// <param name="options">Options.</param> | |
322 /// <remarks> | |
323 /// The reader will be disposed when the XmlReader is disposed. | |
324 /// </remarks> | |
325 public static JSONXmlReader Create(TextReader reader, JSONXmlReaderOptions options) { | |
326 return new JSONXmlReader(new JSONParser(reader, true), options); | |
327 } | |
328 | |
329 /// <summary> | |
330 /// Creates the XmlReader for the specified stream with JSON data. | |
331 /// </summary> | |
332 /// <param name="stream">Stream.</param> | |
333 /// <param name="options">Options.</param> | |
334 /// <remarks> | |
335 /// The stream will be disposed when the XmlReader is disposed. | |
336 /// </remarks> | |
337 public static JSONXmlReader Create(Stream stream, JSONXmlReaderOptions options) { | |
338 Safe.ArgumentNotNull(stream, "stream"); | |
339 // HACK don't dispose StreaReader to keep stream opened | |
340 return Create(new StreamReader(stream), options); | |
341 } | |
342 } | |
343 } |