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, uint 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 if .encoding == 1
179 {
180 ustr tmp
181 tmp.fromutf8( result )
182 result = tmp
183 }
184 }
185
186 /*-----------------------------------------------------------------------------
187 * Id: xmlitem_gettext F2
188 *
189 * Summary: Gets a text of the current item in the XML tree. This method is
190 applied either to a text item or a tag item, in the latter case,
191 the text is obtained from the child text item.
192 *
193 * Params: result - Result string.
194 *
195 * Return: Returns the string that contains the text of the item. If no text
196 has been found, it returns an empty string.
197 *
198 -----------------------------------------------------------------------------*/
199
200 method str xmlitem.gettext( str result )
201 {
202 uint cur = &this
203 //result.clear()
204 if cur->xmlitem.tgtype & $TG_TAG
205 {
206 cur = &cur->xmlitem.getchildtext()
207 }
208 if cur && cur->xmlitem.tgtype & $TG_TEXT
209 {
210 cur->xmlitem.xml->xml.gettext( result, cur->xmlitem.tgstart,
211 cur->xmlitem.tgend )
212 }
213 return result
214 }
215
216 /*-----------------------------------------------------------------------------
217 * Id: xmlitem_chtag F2
218 *
219 * Summary: Gets a tag item with the help of a "path". Searches through the XML
220 tree for a tag item with the help of the specified "path".
221 A "path" consists of tag names separated by the '/' character,
222 if the first character in a path is the '/' character, the item
223 search begins from the tree root; otherwise -
224 from the current item.
225 *
226 * Params: path - Path of the item.
227 *
228 * Return: Returns the item obtained or zero, if no item has been found.
229 *
230 -----------------------------------------------------------------------------*/
231
232 method xmlitem xmlitem.chtag( str path )
233 {
234 arrstr apath
235 uint id
236 uint i, cur = &this
237 path.split( apath, '/', $SPLIT_QUOTE )
238 if *apath[i] : i=0
239 else
240 {
241 i=1
242 cur = &cur->xmlitem.xml->xml.getroot()
243 }
244 fornum i, *apath
245 {
246 id = cur->xmlitem.xml->xml.hnames[apath[i]]
247 cur = &cur->xmlitem.getchildtag()
248 while cur && cur->xmlitem.tgid != id
249 {
250 cur = &cur->xmlitem.getnexttag()
251 }
252 if !cur : break
253 }
254 return cur->xmlitem
255 }
256
257 method xmlitem xmlitem.findid( uint id )
258 {
259 uint cur = &this
260 uint finded
261
262 cur = &cur->xmlitem.getchildtag()
263 while cur && cur->xmlitem.tgid != id
264 {
265 finded = &cur->xmlitem.findid( id )
266 if finded
267 {
268 return finded->xmlitem
269 }
270 cur = &cur->xmlitem.getnexttag()
271 }
272 return cur->xmlitem
273 }
274
275 /*-----------------------------------------------------------------------------
276 * Id: xmlitem_findtag F2
277 *
278 * Summary: Search for a tag item by the name. Searches through the XML tree
279 for a tag item with the specified name. The item is searched
280 recursively through all child items.
281 *
282 * Params: name - Name of the required tag.
283 *
284 * Return: Returns the item obtained or zero, if no item has been found.
285 *
286 -----------------------------------------------------------------------------*/
287
288 method xmlitem xmlitem.findtag( str name )
289 {
290 return this.findid( this.xml->xml.hnames[name] )
291 }
292
293 /*-----------------------------------------------------------------------------
294 * Id: xmlitem_getattrib F2
295 *
296 * Summary: Gets a tag item attribute value.
297 *
298 * Params: name - Attribute name.
299 result - Result string.
300 *
301 * Return: Returns the string that contains the attribute value. If no
302 attribute has been found, it returns an empty string.
303 *
304 -----------------------------------------------------------------------------*/
305
306 method str xmlitem.getattrib( str name, str result )
307 {
308 uint i
309 uint id
310 result.clear()
311 if this.tgtype & $TG_TAG
312 {
313 id = this.xml->xml.hnames[ name ]
314 fornum i = this.tgstart, this.tgend
315 {
316 if this.xml->xml.attribs[i].attid == id
317 {
318 this.xml->xml.gettext( result, this.xml->xml.attribs[i].attstart,
319 this.xml->xml.attribs[i].attend )
320 break
321 }
322 }
323 }
324 return result
325 }
326
327 /*-----------------------------------------------------------------------------
328 * Id: xmlitem_istext F3
329 *
330 * Summary: Determines if the current item is a text item.
331 *
332 * Return: Returns nonzero if the item is a text item; otherwise, it returns
333 zero.
334 *
335 -----------------------------------------------------------------------------*/
336
337 method uint xmlitem.istext()
338 {
339 return this.tgtype & $TG_TEXT
340 }
341
342 /*-----------------------------------------------------------------------------
343 * Id: xmlitem_istag F3
344 *
345 * Summary: Determines if the current item is a tag item.
346 *
347 * Return: Returns nonzero if the item is a tag item; otherwise, it returns
348 zero.
349 *
350 -----------------------------------------------------------------------------*/
351
352 method uint xmlitem.istag()
353 {
354 return this.tgtype & $TG_TAG
355 }
356
357 /*-----------------------------------------------------------------------------
358 * Id: xmlitem_isemptytag F3
359 *
360 * Summary: Determines if the item is an empty tag item. Determines if the
361 current item is a tag item, that contains no child items
362 #b(#lgt[tag .../]);.
363 *
364 * Return: Returns nonzero if the item is a tag item, that contains no child
365 items; otherwise, it returns zero.
366 *
367 -----------------------------------------------------------------------------*/
368
369 method uint xmlitem.isemptytag()
370 {
371 return this.tgtype == $TG_NOCHILD
372 }
373
374 /*-----------------------------------------------------------------------------
375 * Id: xmlitem_ispitag F3
376 *
377 * Summary: Checks if the item is a tag processing instruction. Determines if
378 the current item is a tag of processing instruction
379 #b(#lgt[?tag ...?]).
380 *
381 * Return: Returns nonzero if the item is a tag of processing instruction,
382 otherwise, it returns zero.
383 *
384 -----------------------------------------------------------------------------*/
385
386 method uint xmlitem.ispitag()
387 {
388 return this.tgtype == $TG_QUEST
389 }
390
391 /*-----------------------------------------------------------------------------
392 * Id: xml_addentity F2
393 *
394 * Summary: Adds an entity description. The entity must have been described
395 before the gettext method is called. Below you can see the list
396 of entities described by default:#br#
397 & - #b(&);#br#
398 " - #b('"');#br#
399 ' - #b("'");#br#
400 > - #b(>);#br#
401 < - #b(<);#br#
402 *
403 * Params: key - Key (an entity name - #b(&entity_name;) ).
404 value - Entity value is a string that will be pasted into the text.
405 *
406 -----------------------------------------------------------------------------*/
407
408 method xml.addentity( str key, str value )
409 {
410 uint n = *this.names
411 this.names.expand( 1 )
412 this.names[n] = value
413 this.hentities[key] = n
414 }
415
416 /*-----------------------------------------------------------------------------
417 * Id: xmlitem_getname F2
418 *
419 * Summary: Gets the name of the XML item.
420 *
421 * Params: res - Result string.
422 *
423 * Return: #lng/retpar( res )
424 *
425 -----------------------------------------------------------------------------*/
426
427 method str xmlitem.getname( str res )
428 {
429 res = this.xml->xml.names[this.tgid]
430 return res
431 }
432 //-----------------------------------------------------------------
433
434 method xmltags xmlitem.tags( xmltags tags )
435 {
436 tags.parent = &this
437 // tags.cur = 0
438 return tags
439 }
440
441 /*-----------------------------------------------------------------------------
442 ** Id: xml_opfor F5
443 *
444 * Summary: Foreach operator. Looking through all items with the help of the
445 #b(foreach) operator. Defining an optional variable of the
446 #b(xmltags) type is required. The foreach statement is used for
447 variables of the #b(xmlitem) type and goes through all child tag
448 items of the current tag.#srcg[
449 |xmltags xtags
450 |xmlitem curtag
451 |...
452 |foreach xmlitem cur, curtag.tags( xtags )
453 |{
454 | ...
455 |}]
456 *
457 * Title: foreach var,xmlitem
458 *
459 * Define: foreach variable,xmlitem.tags( xmltags ) {...}
460 *
461 -----------------------------------------------------------------------------*/
462
463 method uint xmltags.eof( fordata tfd )
464 {
465 //return !this.cur
466 return !tfd.icur
467 }
468
469 method uint xmltags.next( fordata tfd )
470 {
471 /*if !this.cur : return 0
472 this.cur = &this.cur->xmlitem.getnexttag()
473 return this.cur*/
474 if !tfd.icur : return 0
475 tfd.icur = &tfd.icur->xmlitem.getnexttag()
476 return tfd.icur
477 }
478
479 method uint xmltags.first( fordata tfd )
480 {
481 /*this.cur = &this.parent->xmlitem.getchildtag()
482 return this.cur*/
483 tfd.icur = &this.parent->xmlitem.getchildtag()
484 return tfd.icur
485 }
486