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 }