View Javadoc

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             // progrept.setProgressText("line " + lno);
112         }
113         return xmlt;
114     }
115 
116 
117 
118     public void readFieldIntoParent(XMLTokenizer tkz, Object parent, XMLToken start) {
119 
120 
121 
122         // read the child object that is known to the parent as item.name
123         // if the parent is a vector, the object is added as a new element;
124         // if the parent is a string, the xml is just apended;
125         // otherwise the field is set.
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             // attributes may contain the class - the instantiator processes
144             // all the attributes here
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                 // in this case, set its length to 0. Subseqnet parts of the
157                 // string will get appended to the current value, so want to
158                 // keep track of the fact that it is a string, without keeping
159                 // the default that may have come from above;
160                 child = new StringBuffer();
161 
162 
163             } else if (child.getClass().isArray()) {
164                 // make it an array list for the time being, then
165                 // give the lsit to teh instantiator to make into theright sort of
166                 // array;
167                 child = new ArrayList();
168             }
169 
170 
171             if (start.isClose()) {
172                 // the tag was both an open and a close tag, so now that we've
173                 // processed the attributes, we're done;
174 
175 
176             } else {
177                 // read on and fill in fields until we get a closing tag which
178                 // matches the start tag
179                 // the fields will be inserted in target;
180 
181                 XMLToken next = readToken(tkz);
182 
183                 while (true) {
184                     if (next.isNone()) {
185                         // should mean EOF, but could also be an error
186                         // return whatever;
187                         break;
188 
189 
190                     } else if (next.isOpen()) {
191                         // open tags could mean anything - elementary field, array,
192                         // or object, but in any case, pass them back to this method;
193                         readFieldIntoParent(tkz, child, next);
194 
195 
196                     } else if (next.isClose()) {
197                         if (next.closes(start)) {
198                             // fine - close item
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                         // stop anyway - either its the right close item, or
213                         // the wrong one but lets cary on and see what happens;
214                         break;
215 
216 
217                     } else if (next.isString()) {
218                         // this occurs if we're just reading a simple string
219                         // field into the parent, or if we're in an array of strings;
220                         // first case obj is defined, so reset it;
221                         // second case put it in the vector;
222 
223 
224                         if (child instanceof ArrayList) {
225                             E.error("attempted to read string into array list?  - ignored" + next.svalue);
226 
227                             // ((ArrayList)child).add(next.svalue);
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                                 // april 06 - is this needed anywhere? reads floating attribues
250                                 // when written as elements (?)
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             // presumably got a close object, and have done one of:
272             // a) filled the parameters of obj;
273             // b) replaced obj with a new object of the same type
274             // c) filled the vector with strings, doubles or objects;
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                 // ((ArrayList)parent).add(child);
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