Mercurial > pub > ImplabNet
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 } |