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("<");
376 str = A.join("<");
377 A = str.split(">");
378 str = A.join(">");
379 A = str.split(""");
380 str = A.join("\"");
381 A = str.split("'");
382 str = A.join("\'");
383 A = str.split("&");
384 str = A.join("&");
385
386 return str;
387 }
388 //////////////////
syntax highlighted by Code2HTML, v. 0.9.1