##// END OF EJS Templates
fixed: JSONXmlReader.Value returns invalid textual representation for numbers.
cin -
r63:908b4f340c69 default
parent child
Show More
@@ -1,310 +1,322
1 1 using Implab;
2 2 using Implab.Parsing;
3 3 using System;
4 4 using System.Collections.Generic;
5 using System.Globalization;
5 6 using System.IO;
6 7 using System.Linq;
7 8 using System.Text;
8 9 using System.Threading.Tasks;
9 10 using System.Xml;
10 11
11 12 namespace Implab.JSON {
12 13 public class JSONXmlReader : XmlReader {
13 14
14 15 enum ValueContext {
15 16 Undefined,
16 17 ElementStart,
17 18 ElementValue,
18 19 ElementEnd,
19 20 ElementEmpty
20 21 }
21 22
22 23 struct LocalNameContext {
23 24 public string localName;
24 25 public bool isArray;
25 26 }
26 27
27 28 JSONParser m_parser;
28 29 ValueContext m_valueContext;
29 30 ReadState m_state = ReadState.Initial;
30 31 Stack<LocalNameContext> m_localNameStack = new Stack<LocalNameContext>();
31 32 LocalNameContext m_localName;
32 33 int m_depthCorrection = 0;
33 34
34 35 readonly string m_rootName;
35 36 readonly string m_prefix;
36 37 readonly string m_namespaceUri;
37 38 readonly bool m_flattenArrays;
38 39 readonly string m_arrayItemName;
39 40 readonly XmlNameTable m_nameTable;
40
41 readonly bool m_disposeParser;
42
41 43 public JSONXmlReader(JSONParser parser, JSONXmlReaderOptions options) {
42 44 Safe.ArgumentNotNull(parser, "parser");
43 45 m_parser = parser;
44 46
45 47 if (options != null) {
46 48 m_prefix = options.NodesPrefix ?? String.Empty;
47 49 m_namespaceUri = options.NamespaceURI ?? String.Empty;
48 50 m_rootName = options.RootName ?? "json";
49 51 m_flattenArrays = options.FlattenArrays;
50 52 m_arrayItemName = options.ArrayItemName ?? "item";
51 53 m_nameTable = options.NameTable ?? new NameTable();
54 m_disposeParser = options.DisposeParser;
52 55 } else {
53 56 m_prefix = String.Empty;
54 57 m_namespaceUri = String.Empty;
55 58 m_rootName = "json";
56 59 m_flattenArrays = false;
57 60 m_arrayItemName = "item";
58 61 m_nameTable = new NameTable();
62 m_disposeParser = false;
59 63 }
60 64 }
61 65
62 66 /// <summary>
63 67 /// Always 0, JSON doesn't support attributes
64 68 /// </summary>
65 69 public override int AttributeCount {
66 70 get { return 0; }
67 71 }
68 72
69 73 public override string BaseURI {
70 74 get { return String.Empty; }
71 75 }
72 76
73 77 public override int Depth {
74 78 get {
75 return m_localNameStack.Count+m_depthCorrection;
79 return m_localNameStack.Count + m_depthCorrection;
76 80 }
77 81 }
78 82
79 83 public override bool EOF {
80 84 get { return m_parser.EOF; }
81 85 }
82 86
83 87 /// <summary>
84 88 /// Always throws an exception
85 89 /// </summary>
86 90 /// <param name="i"></param>
87 91 /// <returns></returns>
88 92 public override string GetAttribute(int i) {
89 93 throw new ArgumentOutOfRangeException();
90 94 }
91 95
92 96 /// <summary>
93 97 /// Always returns empty string
94 98 /// </summary>
95 99 /// <param name="name"></param>
96 100 /// <param name="namespaceURI"></param>
97 101 /// <returns></returns>
98 102 public override string GetAttribute(string name, string namespaceURI) {
99 103 return String.Empty;
100 104 }
101 105
102 106 /// <summary>
103 107 /// Always returns empty string
104 108 /// </summary>
105 109 /// <param name="name"></param>
106 110 /// <returns></returns>
107 111 public override string GetAttribute(string name) {
108 112 return String.Empty;
109 113 }
110 114
111 115 public override bool IsEmptyElement {
112 116 get { return m_parser.ElementType == JSONElementType.Value && m_valueContext == ValueContext.ElementEmpty; }
113 117 }
114 118
115 119 public override string LocalName {
116 120 get { return m_localName.localName; }
117 121 }
118 122
119 123 public override string LookupNamespace(string prefix) {
120 124 if (String.IsNullOrEmpty(prefix) || prefix == m_prefix)
121 125 return m_namespaceUri;
122 126 else
123 127 return String.Empty;
124 128 }
125 129
126 130 public override bool MoveToAttribute(string name, string ns) {
127 131 return false;
128 132 }
129 133
130 134 public override bool MoveToAttribute(string name) {
131 135 return false;
132 136 }
133 137
134 138 public override bool MoveToElement() {
135 139 return false;
136 140 }
137 141
138 142 public override bool MoveToFirstAttribute() {
139 143 return false;
140 144 }
141 145
142 146 public override bool MoveToNextAttribute() {
143 147 return false;
144 148 }
145 149
146 150 public override XmlNameTable NameTable {
147 151 get { return m_nameTable; }
148 152 }
149 153
150 154 public override string NamespaceURI {
151 155 get { return m_namespaceUri; }
152 156 }
153 157
154 158 public override XmlNodeType NodeType {
155 159 get {
156 160 switch (m_parser.ElementType) {
157 161 case JSONElementType.BeginObject:
158 162 case JSONElementType.BeginArray:
159 163 return XmlNodeType.Element;
160 164 case JSONElementType.EndObject:
161 165 case JSONElementType.EndArray:
162 166 return XmlNodeType.EndElement;
163 167 case JSONElementType.Value:
164 168 switch (m_valueContext) {
165 169 case ValueContext.ElementStart:
166 170 case ValueContext.ElementEmpty:
167 171 return XmlNodeType.Element;
168 172 case ValueContext.ElementValue:
169 173 return XmlNodeType.Text;
170 174 case ValueContext.ElementEnd:
171 175 return XmlNodeType.EndElement;
172 176 default:
173 177 throw new InvalidOperationException();
174 178 }
175 179 default:
176 180 throw new InvalidOperationException();
177 181 }
178 182 }
179 183 }
180 184
181 185 public override string Prefix {
182 186 get { return m_prefix; }
183 187 }
184 188
185 189 public override bool Read() {
186 190 if (m_state != System.Xml.ReadState.Interactive && m_state != System.Xml.ReadState.Initial)
187 191 return false;
188 192
189 193 if (m_state == ReadState.Initial)
190 194 m_state = System.Xml.ReadState.Interactive;
191 195
192 196 try {
193 197 switch (m_parser.ElementType) {
194 198 case JSONElementType.Value:
195 199 switch (m_valueContext) {
196 200 case ValueContext.ElementStart:
197 201 SetLocalName(String.Empty);
198 202 m_valueContext = ValueContext.ElementValue;
199 203 return true;
200 204 case ValueContext.ElementValue:
201 205 RestoreLocalName();
202 206 m_valueContext = ValueContext.ElementEnd;
203 207 return true;
204 208 case ValueContext.ElementEmpty:
205 209 case ValueContext.ElementEnd:
206 210 RestoreLocalName();
207 211 break;
208 212 }
209 213 break;
210 214 case JSONElementType.EndArray:
211 215 case JSONElementType.EndObject:
212 216 RestoreLocalName();
213 217 break;
214 218 }
215 219 string itemName = m_parser.ElementType == JSONElementType.None ? m_rootName : m_flattenArrays ? m_localName.localName : m_arrayItemName;
216 220 while (m_parser.Read()) {
217 221 if (!String.IsNullOrEmpty(m_parser.ElementName))
218 222 itemName = m_parser.ElementName;
219 223
220 224 switch (m_parser.ElementType) {
221 225 case JSONElementType.BeginArray:
222 226 if (m_flattenArrays && !m_localName.isArray) {
223 227 m_depthCorrection--;
224 228 SetLocalName(itemName, true);
225 229 continue;
226 230 } else {
227 231 SetLocalName(itemName, true);
228 232 }
229 233 break;
230 234 case JSONElementType.BeginObject:
231 235 SetLocalName(itemName);
232 236 break;
233 237 case JSONElementType.EndArray:
234 238 if (m_flattenArrays && !m_localNameStack.Peek().isArray) {
235 239 RestoreLocalName();
236 240 m_depthCorrection++;
237 241 continue;
238 242 }
239 243 break;
240 244 case JSONElementType.EndObject:
241 245 break;
242 246 case JSONElementType.Value:
243 247 SetLocalName(itemName);
244 248 m_valueContext = m_parser.ElementValue == null ? ValueContext.ElementEmpty : ValueContext.ElementStart;
245 249 break;
246 250 default:
247 251 break;
248 252 }
249 253 return true;
250 254 }
251 255
252 256 m_state = System.Xml.ReadState.EndOfFile;
253 257 return false;
254 258 } catch {
255 259 m_state = System.Xml.ReadState.Error;
256 260 throw;
257 261 }
258 262 }
259 263
260 264 public override bool ReadAttributeValue() {
261 265 return false;
262 266 }
263 267
264 268 public override ReadState ReadState {
265 269 get { return m_state; }
266 270 }
267 271
268 272 public override void ResolveEntity() {
269 273 // do nothing
270 274 }
271 275
272 276 public override string Value {
273 get { return m_parser.ElementValue == null ? String.Empty : m_parser.ElementValue.ToString(); }
277 get {
278 if (m_parser.ElementValue == null)
279 return String.Empty;
280 if (Convert.GetTypeCode(m_parser.ElementValue) == TypeCode.Double)
281 return ((double)m_parser.ElementValue).ToString(CultureInfo.InvariantCulture);
282 else
283 return (string)m_parser.ElementValue;
284 }
274 285 }
275 286
276 287 void SetLocalName(string name) {
277 288 m_localNameStack.Push(m_localName);
278 289 m_localName.localName = name;
279 290 m_localName.isArray = false;
280 291 }
281 292
282 293 void SetLocalName(string name, bool isArray) {
283 294 m_localNameStack.Push(m_localName);
284 295 m_localName.localName = name;
285 296 m_localName.isArray = isArray;
286 297 }
287 298
288 299 void RestoreLocalName() {
289 300 m_localName = m_localNameStack.Pop();
290 301 }
291 302
292 303 public override void Close() {
293
304
294 305 }
295 306
296 307 protected override void Dispose(bool disposing) {
297 308 if (disposing) {
298 m_parser.Dispose();
309 if (m_disposeParser)
310 m_parser.Dispose();
299 311 }
300 312 base.Dispose(disposing);
301 313 }
302 314
303 315
304 316 public static JSONXmlReader OpenFile(string file, JSONXmlReaderOptions options) {
305 317 var stream = File.OpenText(file);
306 318 var parser = new JSONParser(stream, true);
307 319 return new JSONXmlReader(parser, options);
308 320 }
309 321 }
310 322 }
@@ -1,61 +1,69
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Linq;
4 4 using System.Text;
5 5 using System.Xml;
6 6
7 7 namespace Implab.JSON {
8 8 /// <summary>
9 9 /// Набор необязательных параметров для <see cref="JSONXmlReader"/>, позволяющий управлять процессом
10 10 /// интерпретации <c>JSON</c> документа.
11 11 /// </summary>
12 12 public class JSONXmlReaderOptions {
13 13 /// <summary>
14 14 /// Пространство имен в котором будут располагаться читаемые элементы документа
15 15 /// </summary>
16 16 public string NamespaceURI {
17 17 get;
18 18 set;
19 19 }
20 20
21 21 /// <summary>
22 22 /// Интерпретировать массивы как множественные элементы (убирает один уровень вложенности)
23 23 /// </summary>
24 24 public bool FlattenArrays {
25 25 get;
26 26 set;
27 27 }
28 28
29 29 /// <summary>
30 30 /// Префикс, для узлов документа
31 31 /// </summary>
32 32 public string NodesPrefix {
33 33 get;
34 34 set;
35 35 }
36 36
37 37 /// <summary>
38 38 /// Имя корневого элемента в xml документе
39 39 /// </summary>
40 40 public string RootName {
41 41 get;
42 42 set;
43 43 }
44 44
45 45 /// <summary>
46 46 /// Имя элемента для массивов, если не включена опция <see cref="FlattenArrays"/>.
47 47 /// </summary>
48 48 public string ArrayItemName {
49 49 get;
50 50 set;
51 51 }
52 52
53 53 /// <summary>
54 54 /// Таблица атомизированных строк для построения документа.
55 55 /// </summary>
56 56 public XmlNameTable NameTable {
57 57 get;
58 58 set;
59 59 }
60
61 /// <summary>
62 /// Флаг, означающий, что неужно освободить парсер по окончанию работы.
63 /// </summary>
64 public bool DisposeParser {
65 get;
66 set;
67 }
60 68 }
61 69 }
General Comments 0
You need to be logged in to leave comments. Login now