1 /******************************************************************************
2 *
3 * Copyright (C) 2004-2008, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * Author: Alexander Krivonogov ( algen )
11 *
12 ******************************************************************************/
13
14 /*-----------------------------------------------------------------------------
15 * Id: xml_getroot F3
16 *
17 * Summary: Gets the root item of the XML document tree. Actually, a root item
18 contains all items of an XML document tree only.
19 *
20 * Return: Returns a root item.
21 *
22 -----------------------------------------------------------------------------*/
23
24 method xmlitem xml.getroot()
25 {
26 return this.tags[0]
27 }
28
29 /*-----------------------------------------------------------------------------
30 * Id: xmlitem_getnext F3
31 *
32 * Summary: Gets the next item. However, the next item must be searched
33 through the items with the same parent item.
34 *
35 * Return: Returns the next item or zero, if the item is the last item.
36 *
37 -----------------------------------------------------------------------------*/
38
39 method xmlitem xmlitem.getnext()
40 {
41 return ?( this.nnext, this.xml->xml.tags[this.nnext], 0->xmlitem )
42 }
43
44 /*-----------------------------------------------------------------------------
45 * Id: xmlitem_getnexttext F3
46 *
47 * Summary: Gets the next text item. This method is similar to the
48 #a(xmlitem_getnext) method, but if the next item is not a text item,
49 this operation repeats.
50 *
51 * Return: Returns the next text item or zero, if the item is the last item.
52 *
53 -----------------------------------------------------------------------------*/
54
55 method xmlitem xmlitem.getnexttext()
56 {
57 uint cur = &this
58 while (cur = &cur->xmlitem.getnext()) && !(cur->xmlitem.tgtype & $TG_TEXT) :
59 return cur->xmlitem
60 }
61
62 /*-----------------------------------------------------------------------------
63 * Id: xmlitem_getnexttag F3
64 *
65 * Summary: Gets the next tag item. This method is similar to the
66 #a(xmlitem_getnext) method, but if the next item is not a tag
67 item, this operation repeats.
68 *
69 * Return: Returns the next tag item or zero, if the item is the last item.
70 *
71 -----------------------------------------------------------------------------*/
72
73 method xmlitem xmlitem.getnexttag
74 {
75 uint cur = &this
76 while (cur = &cur->xmlitem.getnext()) && !(cur->xmlitem.tgtype & $TG_TAG) :
77 return cur->xmlitem
78 }
79
80 /*-----------------------------------------------------------------------------
81 * Id: xmlitem_getchild F3
82 *
83 * Summary: Gets the first child item of the current item.
84 *
85 * Return: Returns the child item or zero, if the item does not contain any
86 child items.
87 *
88 -----------------------------------------------------------------------------*/
89
90 method xmlitem xmlitem.getchild()
91 {
92 return ?( this.nchild, this.xml->xml.tags[this.nchild], 0->xmlitem )
93 }
94
95 /*-----------------------------------------------------------------------------
96 * Id: xmlitem_getchildtag F3
97 *
98 * Summary: Gets the first child tag item. This method is similar to the
99 #a(xmlitem_getchild) method; however, if the child item is not a
100 tag item, in this case, the tag item that comes first is searched
101 through the child items.
102 *
103 * Return: Returns the child tag item or zero, if the item does not contain
104 any child tag items.
105 *
106 -----------------------------------------------------------------------------*/
107
108 method xmlitem xmlitem.getchildtag()
109 {
110 uint cur = &this.getchild()
111 if cur && !(cur->xmlitem.tgtype & $TG_TAG) : cur = &cur->xmlitem.getnexttag()
112 return cur->xmlitem
113 }
114
115 /*-----------------------------------------------------------------------------
116 * Id: xmlitem_getchildtext F3
117 *
118 * Summary: Gets the first child text item. This method is similar to the
119 #a(xmlitem_getchild) method; however, if the child item is not a
120 text item, in this case, the text item that comes first is
121 searched through the child items.
122 *
123 * Return: Returns the child text item or zero, if the item does not contain
124 any child text items.
125 *
126 -----------------------------------------------------------------------------*/
127
128 method xmlitem xmlitem.getchildtext()
129 {
130 uint cur = &this.getchild()
131 if cur && !(cur->xmlitem.tgtype & $TG_TEXT)
132 {
133 cur = &cur->xmlitem.getnexttext()
134 }
135 return cur->xmlitem
136 }
137
138 /*-----------------------------------------------------------------------------
139 * Id: xmlitem_getparent F3
140 *
141 * Summary: Gets the parent item of the current item.
142 *
143 * Return: Returns the parent item or zero, if the current item is the
144 root item.
145 *
146 -----------------------------------------------------------------------------*/
147
148 method xmlitem xmlitem.getparent()
149 {
150 if &this != &this.xml->xml.tags[0]
151 {
152 return this.xml->xml.tags[this.nparent]
153 }
154 return 0->xmlitem
155 }
156
157 method xml.gettext( str result, uint start, end )
158 {
159 uint i
160 uint tx
161 fornum i = start, end
162 {
163 tx = &this.texts[i]
164 tx as xtext
165 switch tx.txtype
166 {
167 case $TX_TEXT : result.append( tx.txaddr_code, tx.txlen )
168 case $TX_SYMBOL : result.appendch( tx.txaddr_code )
169 case $TX_ENTITY
170 {
171 if tx.txaddr_code
172 {
173 result += this.names[tx.txaddr_code->uint]
174 }
175 }
176 }
177 }
178 }
179
180 /*-----------------------------------------------------------------------------
181 * Id: xmlitem_gettext F2
182 *
183 * Summary: Gets a text of the current item in the XML tree. This method is
184 applied either to a text item or a tag item, in the latter case,
185 the text is obtained from the child text item.
186 *
187 * Params: result - Result string.
188 *
189 * Return: Returns the string that contains the text of the item. If no text
190 has been found, it returns an empty string.
191 *
192 -----------------------------------------------------------------------------*/
193
194 method str xmlitem.gettext( str result )
195 {
196 uint cur = &this
197 //result.clear()
198 if cur->xmlitem.tgtype & $TG_TAG
199 {
200 cur = &cur->xmlitem.getchildtext()
201 }
202 if cur && cur->xmlitem.tgtype & $TG_TEXT
203 {
204 cur->xmlitem.xml->xml.gettext( result, cur->xmlitem.tgstart,
205 cur->xmlitem.tgend )
206 }
207 return result
208 }
209
210 /*-----------------------------------------------------------------------------
211 * Id: xmlitem_chtag F2
212 *
213 * Summary: Gets a tag item with the help of a "path". Searches through the XML
214 tree for a tag item with the help of the specified "path".
215 A "path" consists of tag names separated by the '/' character,
216 if the first character in a path is the '/' character, the item
217 search begins from the tree root; otherwise -
218 from the current item.
219 *
220 * Params: path - Path of the item.
221 *
222 * Return: Returns the item obtained or zero, if no item has been found.
223 *
224 -----------------------------------------------------------------------------*/
225
226 method xmlitem xmlitem.chtag( str path )
227 {
228 arrstr apath
229 uint id
230 uint i, cur = &this
231 path.split( apath, '/', $SPLIT_QUOTE )
232 if *apath[i] : i=0
233 else
234 {
235 i=1
236 cur = &cur->xmlitem.xml->xml.getroot()
237 }
238 fornum i, *apath
239 {
240 id = cur->xmlitem.xml->xml.hnames[apath[i]]
241 cur = &cur->xmlitem.getchildtag()
242 while cur && cur->xmlitem.tgid != id
243 {
244 cur = &cur->xmlitem.getnexttag()
245 }
246 if !cur : break
247 }
248 return cur->xmlitem
249 }
250
251 method xmlitem xmlitem.findid( uint id )
252 {
253 uint cur = &this
254 uint finded
255
256 cur = &cur->xmlitem.getchildtag()
257 while cur && cur->xmlitem.tgid != id
258 {
259 finded = &cur->xmlitem.findid( id )
260 if finded
261 {
262 return finded->xmlitem
263 }
264 cur = &cur->xmlitem.getnexttag()
265 }
266 return cur->xmlitem
267 }
268
269 /*-----------------------------------------------------------------------------
270 * Id: xmlitem_findtag F2
271 *
272 * Summary: Search for a tag item by the name. Searches through the XML tree
273 for a tag item with the specified name. The item is searched
274 recursively through all child items.
275 *
276 * Params: name - Name of the required tag.
277 *
278 * Return: Returns the item obtained or zero, if no item has been found.
279 *
280 -----------------------------------------------------------------------------*/
281
282 method xmlitem xmlitem.findtag( str name )
283 {
284 return this.findid( this.xml->xml.hnames[name] )
285 }
286
287 /*-----------------------------------------------------------------------------
288 * Id: xmlitem_getattrib F2
289 *
290 * Summary: Gets a tag item attribute value.
291 *
292 * Params: name - Attribute name.
293 result - Result string.
294 *
295 * Return: Returns the string that contains the attribute value. If no
296 attribute has been found, it returns an empty string.
297 *
298 -----------------------------------------------------------------------------*/
299
300 method str xmlitem.getattrib( str name, str result )
301 {
302 uint i
303 uint id
304 result.clear()
305 if this.tgtype & $TG_TAG
306 {
307 id = this.xml->xml.hnames[ name ]
308 fornum i = this.tgstart, this.tgend
309 {
310 if this.xml->xml.attribs[i].attid == id
311 {
312 this.xml->xml.gettext( result, this.xml->xml.attribs[i].attstart,
313 this.xml->xml.attribs[i].attend )
314 break
315 }
316 }
317 }
318 return result
319 }
320
321 /*-----------------------------------------------------------------------------
322 * Id: xmlitem_istext F3
323 *
324 * Summary: Determines if the current item is a text item.
325 *
326 * Return: Returns nonzero if the item is a text item; otherwise, it returns
327 zero.
328 *
329 -----------------------------------------------------------------------------*/
330
331 method uint xmlitem.istext()
332 {
333 return this.tgtype & $TG_TEXT
334 }
335
336 /*-----------------------------------------------------------------------------
337 * Id: xmlitem_istag F3
338 *
339 * Summary: Determines if the current item is a tag item.
340 *
341 * Return: Returns nonzero if the item is a tag item; otherwise, it returns
342 zero.
343 *
344 -----------------------------------------------------------------------------*/
345
346 method uint xmlitem.istag()
347 {
348 return this.tgtype & $TG_TAG
349 }
350
351 /*-----------------------------------------------------------------------------
352 * Id: xmlitem_isemptytag F3
353 *
354 * Summary: Determines if the item is an empty tag item. Determines if the
355 current item is a tag item, that contains no child items
356 #b(#lgt[tag .../]);.
357 *
358 * Return: Returns nonzero if the item is a tag item, that contains no child
359 items; otherwise, it returns zero.
360 *
361 -----------------------------------------------------------------------------*/
362
363 method uint xmlitem.isemptytag()
364 {
365 return this.tgtype == $TG_NOCHILD
366 }
367
368 /*-----------------------------------------------------------------------------
369 * Id: xmlitem_ispitag F3
370 *
371 * Summary: Checks if the item is a tag processing instruction. Determines if
372 the current item is a tag of processing instruction
373 #b(#lgt[?tag ...?]).
374 *
375 * Return: Returns nonzero if the item is a tag of processing instruction,
376 otherwise, it returns zero.
377 *
378 -----------------------------------------------------------------------------*/
379
380 method uint xmlitem.ispitag()
381 {
382 return this.tgtype == $TG_QUEST
383 }
384
385 /*-----------------------------------------------------------------------------
386 * Id: xml_addentity F2
387 *
388 * Summary: Adds an entity description. The entity must have been described
389 before the gettext method is called. Below you can see the list
390 of entities described by default:#br#
391 & - #b(&);#br#
392 " - #b('"');#br#
393 ' - #b("'");#br#
394 > - #b(>);#br#
395 < - #b(<);#br#
396 *
397 * Params: key - Key (an entity name - #b(&entity_name;) ).
398 value - Entity value is a string that will be pasted into the text.
399 *
400 -----------------------------------------------------------------------------*/
401
402 method xml.addentity( str key, str value )
403 {
404 uint n = *this.names
405 this.names.expand( 1 )
406 this.names[n] = value
407 this.hentities[key] = n
408 }
409
410 /*-----------------------------------------------------------------------------
411 * Id: xmlitem_getname F2
412 *
413 * Summary: Gets the name of the XML item.
414 *
415 * Params: res - Result string.
416 *
417 * Return: #lng/retpar( res )
418 *
419 -----------------------------------------------------------------------------*/
420
421 method str xmlitem.getname( str res )
422 {
423 res = this.xml->xml.names[this.tgid]
424 return res
425 }
426 //-----------------------------------------------------------------
427
428 method xmltags xmlitem.tags( xmltags tags )
429 {
430 tags.parent = &this
431 tags.cur = 0
432 return tags
433 }
434
435 /*-----------------------------------------------------------------------------
436 ** Id: xml_opfor F5
437 *
438 * Summary: Foreach operator. Looking through all items with the help of the
439 #b(foreach) operator. Defining an optional variable of the
440 #b(xmltags) type is required. The foreach statement is used for
441 variables of the #b(xmlitem) type and goes through all child tag
442 items of the current tag.#srcg[
443 |xmltags xtags
444 |xmlitem curtag
445 |...
446 |foreach xmlitem cur, curtag.tags( xtags )
447 |{
448 | ...
449 |}]
450 *
451 * Title: foreach var,xmlitem
452 *
453 * Define: foreach variable,xmlitem.tags( xmltags ) {...}
454 *
455 -----------------------------------------------------------------------------*/
456
457 method uint xmltags.eof
458 {
459 return !this.cur
460 }
461
462 method uint xmltags.next
463 {
464 if !this.cur : return 0
465 this.cur = &this.cur->xmlitem.getnexttag()
466 return this.cur
467 }
468
469 method uint xmltags.first
470 {
471 this.cur = &this.parent->xmlitem.getchildtag()
472 return this.cur
473 }