comparison Implab/Formats/JSON/JSONXmlReader.cs @ 190:1c2a16d071a7 v2

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