1 // Ver .91 Feb 21 1998
  2 //////////////////////////////////////////////////////////////
  3 //
  4 // Copyright 1998 Jeremie
  5 // Free for public non-commercial use and modification
  6 // as long as this header is kept intact and unmodified.
  7 // Please see http://www.jeremie.com for more information
  8 // or email jer@jeremie.com with questions/suggestions.
  9 //
 10 ///////////////////////////////////////////////////////////////
 11 ///////////////////////////////////////////////////////////////
 12 ////////// Simple XML Processing Library //////////////////////
 13 ///////////////////////////////////////////////////////////////
 14 ///////////////////////////////////////////////////////////////
 15 ////   Fully complies to the XML 1.0 spec 
 16 ////   as a well-formed processor, with the
 17 ////   exception of full error reporting and
 18 ////   the document type declaration(and it's
 19 ////   related features, internal entities, etc).
 20 ///////////////////////////////////////////////////////////////
 21 
 22 
 23 /////////////////////////
 24 //// the object constructors for the hybrid DOM
 25 
 26 function _element()
 27 {
 28    this.type = "element";
 29    this.name = new String();
 30    this.attributes = new Array();
 31    this.contents = new Array();
 32    this.uid = _Xparse_count++;
 33    _Xparse_index[this.uid]=this;
 34 }
 35 
 36 function _chardata()
 37 {
 38    this.type = "chardata";
 39    this.value = new String();
 40 }
 41 
 42 function _pi()
 43 {
 44    this.type = "pi";
 45    this.value = new String();
 46 }
 47 
 48 function _comment()
 49 {
 50    this.type = "comment";
 51    this.value = new String();
 52 }
 53 
 54 // an internal fragment that is passed between functions
 55 function _frag()
 56 {
 57    this.str = new String();
 58    this.ary = new Array();
 59    this.end = new String();
 60 }
 61 
 62 /////////////////////////
 63 
 64 
 65 // global vars to track element UID's for the index
 66 var _Xparse_count = 0;
 67 var _Xparse_index = new Array();
 68 
 69 
 70 /////////////////////////
 71 //// Main public function that is called to 
 72 //// parse the XML string and return a root element object
 73 
 74 function Xparse(src)
 75 {
 76    var frag = new _frag();
 77 
 78    // remove bad \r characters and the prolog
 79    frag.str = _prolog(src);
 80 
 81    // create a root element to contain the document
 82    var root = new _element();
 83    root.name="ROOT";
 84 
 85    // main recursive function to process the xml
 86    frag = _compile(frag);
 87 
 88    // all done, lets return the root element + index + document
 89    root.contents = frag.ary;
 90    root.index = _Xparse_index;
 91    _Xparse_index = new Array();
 92    return root;
 93 }
 94 
 95 /////////////////////////
 96 
 97 
 98 /////////////////////////
 99 //// transforms raw text input into a multilevel array
100 function _compile(frag)
101 {
102    // keep circling and eating the str
103    while(1)
104    {
105       // when the str is empty, return the fragment
106       if(frag.str.length == 0)
107       {
108          return frag;
109       }
110 
111       var TagStart = frag.str.indexOf("<");
112 
113       if(TagStart != 0)
114       {
115          // theres a chunk of characters here, store it and go on
116          var thisary = frag.ary.length;
117          frag.ary[thisary] = new _chardata();
118          if(TagStart == -1)
119          {
120             frag.ary[thisary].value = _entity(frag.str);
121             frag.str = "";
122          }
123          else
124          {
125             frag.ary[thisary].value = _entity(frag.str.substring(0,TagStart));
126             frag.str = frag.str.substring(TagStart,frag.str.length);
127          }
128       }
129       else
130       {
131          // determine what the next section is, and process it
132          if(frag.str.substring(1,2) == "?")
133          {
134             frag = _tag_pi(frag);
135          }
136          else
137          {
138             if(frag.str.substring(1,4) == "!--")
139             {
140                frag = _tag_comment(frag);
141             }
142             else
143             {
144                if(frag.str.substring(1,9) == "![CDATA[")
145                {
146                   frag = _tag_cdata(frag);
147                }
148                else
149                {
150                   if(frag.str.substring(1,frag.end.length + 3) == "/" + frag.end + ">" || _strip(frag.str.substring(1,frag.end.length + 3)) == "/" + frag.end)
151                   {
152                      // found the end of the current tag, end the recursive process and return
153                      frag.str = frag.str.substring(frag.end.length + 3,frag.str.length);
154                      frag.end = "";
155                      return frag;
156                   }
157                   else
158                   {
159                      frag = _tag_element(frag);
160                   }
161                }
162             }
163          }
164 
165       }
166    }
167    return "";
168 }
169 ///////////////////////
170 
171 
172 ///////////////////////
173 //// functions to process different tags
174 
175 function _tag_element(frag)
176 {
177    // initialize some temporary variables for manipulating the tag
178    var close = frag.str.indexOf(">");
179    var empty = (frag.str.substring(close - 1,close) == "/");
180    if(empty)
181    {
182       close -= 1;
183    }
184 
185    // split up the name and attributes
186    var starttag = _normalize(frag.str.substring(1,close));
187    var nextspace = starttag.indexOf(" ");
188    var attribs = new String();
189    var name = new String();
190    if(nextspace != -1)
191    {
192       name = starttag.substring(0,nextspace);
193       attribs = starttag.substring(nextspace + 1,starttag.length);
194    }
195    else
196    {
197       name = starttag;
198    }
199 
200    var thisary = frag.ary.length;
201    frag.ary[thisary] = new _element();
202    frag.ary[thisary].name = _strip(name);
203    if(attribs.length > 0)
204    {
205       frag.ary[thisary].attributes = _attribution(attribs);
206    }
207    if(!empty)
208    {
209       // !!!! important, 
210       // take the contents of the tag and parse them
211       var contents = new _frag();
212       contents.str = frag.str.substring(close + 1,frag.str.length);
213       contents.end = name;
214       contents = _compile(contents);
215       frag.ary[thisary].contents = contents.ary;
216       frag.str = contents.str;
217    }
218    else
219    {
220       frag.str = frag.str.substring(close + 2,frag.str.length);
221    }
222    return frag;
223 }
224 
225 function _tag_pi(frag)
226 {
227    var close = frag.str.indexOf("?>");
228    var val = frag.str.substring(2,close);
229    var thisary = frag.ary.length;
230    frag.ary[thisary] = new _pi();
231    frag.ary[thisary].value = val;
232    frag.str = frag.str.substring(close + 2,frag.str.length);
233    return frag;
234 }
235 
236 function _tag_comment(frag)
237 {
238    var close = frag.str.indexOf("-->");
239    var val = frag.str.substring(4,close);
240    var thisary = frag.ary.length;
241    frag.ary[thisary] = new _comment();
242    frag.ary[thisary].value = val;
243    frag.str = frag.str.substring(close + 3,frag.str.length);
244    return frag;
245 }
246 
247 function _tag_cdata(frag)
248 {
249    var close = frag.str.indexOf("]]>");
250    var val = frag.str.substring(9,close);
251    var thisary = frag.ary.length;
252    frag.ary[thisary] = new _chardata();
253    frag.ary[thisary].value = val;
254    frag.str = frag.str.substring(close + 3,frag.str.length);
255    return frag;
256 }
257 
258 /////////////////////////
259 
260 
261 //////////////////
262 //// util for element attribute parsing
263 //// returns an array of all of the keys = values
264 function _attribution(str)
265 {
266    var all = new Array();
267    while(1)
268    {
269       var eq = str.indexOf("=");
270       if(str.length == 0 || eq == -1)
271       {
272          return all;
273       }
274 
275       var id1 = str.indexOf("\'");
276       var id2 = str.indexOf("\"");
277       var ids = new Number();
278       var id = new String();
279       if((id1 < id2 && id1 != -1) || id2 == -1)
280       {
281          ids = id1;
282          id = "\'";
283       }
284       if((id2 < id1 || id1 == -1) && id2 != -1)
285       {
286          ids = id2;
287          id = "\"";
288       }
289       var nextid = str.indexOf(id,ids + 1);
290       var val = str.substring(ids + 1,nextid);
291 
292       var name = _strip(str.substring(0,eq));
293       all[name] = _entity(val);
294       str = str.substring(nextid + 1,str.length);
295    }
296    return "";
297 }
298 ////////////////////
299 
300 
301 //////////////////////
302 //// util to remove \r characters from input string
303 //// and return xml string without a prolog
304 function _prolog(str)
305 {
306    var A = new Array();
307 
308    A = str.split("\r\n");
309    str = A.join("\n");
310    A = str.split("\r");
311    str = A.join("\n");
312 
313    var start = str.indexOf("<");
314    if(str.substring(start,start + 3) == "<?x" || str.substring(start,start + 3) == "<?X" )
315    {
316       var close = str.indexOf("?>");
317       str = str.substring(close + 2,str.length);
318    }
319    var start = str.indexOf("<!DOCTYPE");
320    if(start != -1)
321    {
322       var close = str.indexOf(">",start) + 1;
323       var dp = str.indexOf("[",start);
324       if(dp < close && dp != -1)
325       {
326          close = str.indexOf("]>",start) + 2;
327       }
328       str = str.substring(close,str.length);
329    }
330    return str;
331 }
332 //////////////////
333 
334 
335 //////////////////////
336 //// util to remove white characters from input string
337 function _strip(str)
338 {
339    var A = new Array();
340 
341    A = str.split("\n");
342    str = A.join("");
343    A = str.split(" ");
344    str = A.join("");
345    A = str.split("\t");
346    str = A.join("");
347 
348    return str;
349 }
350 //////////////////
351 
352 
353 //////////////////////
354 //// util to replace white characters in input string
355 function _normalize(str)
356 {
357    var A = new Array();
358 
359    A = str.split("\n");
360    str = A.join(" ");
361    A = str.split("\t");
362    str = A.join(" ");
363 
364    return str;
365 }
366 //////////////////
367 
368 
369 //////////////////////
370 //// util to replace internal entities in input string
371 function _entity(str)
372 {
373    var A = new Array();
374 
375    A = str.split("&lt;");
376    str = A.join("<");
377    A = str.split("&gt;");
378    str = A.join(">");
379    A = str.split("&quot;");
380    str = A.join("\"");
381    A = str.split("&apos;");
382    str = A.join("\'");
383    A = str.split("&amp;");
384    str = A.join("&");
385 
386    return str;
387 }
388 //////////////////


syntax highlighted by Code2HTML, v. 0.9.1