1 package org.catacomb.serial.xml;
2
3 import org.catacomb.be.ReReferencable;
4 import org.catacomb.interlish.report.PrintProgressReport;
5 import org.catacomb.interlish.structure.*;
6 import org.catacomb.report.E;
7
8
9 import java.util.ArrayList;
10 import java.util.StringTokenizer;
11
12
13 public class XMLReader {
14
15 ProgressReport progrept;
16 Constructor instantiator;
17 int sourceLength;
18 int nerror;
19
20 double progressFraction;
21
22 String startText;
23
24 public XMLReader(Constructor insta) {
25 instantiator = insta;
26 }
27
28
29 public void setProgressReport(ProgressReport pr) {
30 progrept = pr;
31 }
32
33
34 public void err(String s) {
35 System.out.println(s);
36 }
37
38
39 public Object readObject(String s) {
40 return readFromString(s);
41 }
42
43
44 public Object read(String s) {
45 return readFromString(s);
46 }
47
48
49
50 public Object readFromString(String sin) {
51 String s = sin;
52 s = XMLChecker.deGarbage(s);
53
54 if (s == null) {
55 return null;
56 }
57
58 startText = s.substring(0, Math.min(200, s.length()));
59
60 progressFraction = 0.;
61
62 nerror = 0;
63 sourceLength = (new StringTokenizer(s, "\n")).countTokens();
64
65
66 if (progrept != null) {
67 progrept.setFraction(0.);
68 } else if (sourceLength > 10000) {
69 progrept = new PrintProgressReport();
70 progrept.setFraction(0.);
71 }
72
73 XMLTokenizer tkz = new XMLTokenizer(s);
74
75 XMLToken xmlt = tkz.nextToken();
76 while (xmlt.isIntro() || xmlt.isComment()) {
77 xmlt = tkz.nextToken();
78 }
79
80
81
82 XMLHolder xmlHolder = new XMLHolder();
83
84 readFieldIntoParent(tkz, xmlHolder, xmlt);
85
86 return xmlHolder.getContent();
87 }
88
89
90
91
92
93 public XMLToken readToken(XMLTokenizer tkz) {
94 XMLToken xmlt = tkz.nextToken();
95
96 int lno = tkz.lineno();
97 if (nerror > 4) {
98 err("too many errors - aborting parse at line " + lno);
99 xmlt.setType(XMLToken.NONE);
100 if (progrept != null) {
101 progrept.setText("aborted at line " + lno);
102 }
103 }
104
105 if (progrept != null) {
106 double ff = lno / (sourceLength + 1.);
107 if (ff > progressFraction + 0.005) {
108 progrept.setFraction(ff);
109 progressFraction = ff;
110 }
111
112 }
113 return xmlt;
114 }
115
116
117
118 public void readFieldIntoParent(XMLTokenizer tkz, Object parent, XMLToken start) {
119
120
121
122
123
124
125
126
127
128 if (!start.isOpen()) {
129 nerror++;
130 err("ERROR - read object start item was not an open tag " + start);
131 return;
132 }
133
134
135 Object child = null;
136
137 if (parent instanceof String || parent instanceof StringBuffer) {
138 child = new StringBuffer();
139 ((StringBuffer)child).append(start.getOpenTagString());
140
141 } else {
142
143
144
145 Attribute[] atts = start.getAttributes();
146 child = instantiator.getChildObject(parent, start.getName(), atts);
147 if (child != null) {
148 instantiator.applyAttributes(child, atts);
149 }
150
151
152 if (child == null) {
153 child = new ArrayList();
154
155 } else if (child instanceof String) {
156
157
158
159
160 child = new StringBuffer();
161
162
163 } else if (child.getClass().isArray()) {
164
165
166
167 child = new ArrayList();
168 }
169
170
171 if (start.isClose()) {
172
173
174
175
176 } else {
177
178
179
180
181 XMLToken next = readToken(tkz);
182
183 while (true) {
184 if (next.isNone()) {
185
186
187 break;
188
189
190 } else if (next.isOpen()) {
191
192
193 readFieldIntoParent(tkz, child, next);
194
195
196 } else if (next.isClose()) {
197 if (next.closes(start)) {
198
199
200 if (parent instanceof String || parent instanceof StringBuffer) {
201 ((StringBuffer)child).append(next.getCloseTagString());
202 }
203
204
205 } else {
206 nerror++;
207 E.shortError(" non-matching close item \n" + "start Item was: \n"
208 + start.toString() + "\n" + "but close was: \n" + next.toString() + "\n" +
209 "start text was \n" + startText);
210 }
211
212
213
214 break;
215
216
217 } else if (next.isString()) {
218
219
220
221
222
223
224 if (child instanceof ArrayList) {
225 E.error("attempted to read string into array list? - ignored" + next.svalue);
226
227
228
229
230 } else if (child instanceof StringBuffer) {
231 E.deprecate("xml reader - string added to string buffer " + next.svalue);
232
233 StringBuffer sbo = (StringBuffer)child;
234 String ssf = sbo.toString();
235 if (ssf.endsWith(">") || next.svalue.startsWith("<") || ssf.length() == 0) {
236 sbo.append(next.svalue);
237
238 } else {
239 sbo.append(" ");
240 sbo.append(next.svalue);
241 }
242
243
244 } else {
245 if (child instanceof String && ((String)child).length() > 0) {
246 child = child + " " + next.svalue;
247 E.deprecate("appended string to string " + next.svalue);
248
249
250
251 } else if (child instanceof Double && ((Double)child).doubleValue() == 0.0) {
252 child = new Double(next.svalue);
253
254 } else if (child == null) {
255 child = next.svalue;
256
257 } else {
258 instantiator.appendContent(child, next.svalue);
259
260 }
261 }
262
263
264 } else if (next.isNumber()) {
265 E.shortError("XMLReader sjhould never return numbers....!!!! but " + "just got " + next);
266 }
267 next = readToken(tkz);
268 }
269 }
270
271
272
273
274
275
276
277
278 if (child instanceof StringBuffer) {
279 child = ((StringBuffer)child).toString();
280 }
281
282
283 if (child instanceof ReReferencable) {
284 ((ReReferencable)child).reReference();
285 }
286
287
288 if (parent instanceof StringBuffer) {
289 StringBuffer psb = (StringBuffer)parent;
290 psb.append(child);
291 psb.append("\n");
292
293
294 } else if (parent instanceof XMLHolder) {
295 ((XMLHolder)parent).setContent(child);
296
297 } else if (parent instanceof ArrayList) {
298 E.missing("Array list parent in xmlreader is ignored! - child discarded " + child
299 + " parent=" + parent + " " + start.getName());
300
301 setListChild(parent, child);
302
303 } else {
304 instantiator.setField(parent, start.getName(), child);
305 }
306 }
307 }
308
309
310
311 @SuppressWarnings( {"unchecked"})
312 private void setListChild(Object parent, Object child) {
313 ((ArrayList)parent).add(child);
314 }
315 }
316
317
318
319
320 class XMLHolder {
321
322 Object content;
323
324
325 public void setContent(Object obj) {
326 content = obj;
327 }
328
329
330 public Object getContent() {
331 return content;
332 }
333 }
334
335