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