Small updates, code clean up
[SXSI/XMLTree.git] / XMLTree.cpp
1 \r
2 #include "basics.h"\r
3 #include <cstring>\r
4 #include "XMLTree.h"\r
5 \r
6 // functions to convert tag positions to the corresponding tree node and viceversa. \r
7 // These are implemented in order to be able to change the tree and Tags representations, \r
8 // without affecting the code so much.\r
9 // Current implementation corresponds to balanced-parentheses representation for\r
10 // the tree, and storing 2 tags per tree node (opening and closing tags).\r
11 \r
12 // tag position -> tree node\r
13 inline treeNode tagpos2node(int t) \r
14  {\r
15     return (treeNode) t;\r
16  }\r
17 \r
18 // tree node -> tag position\r
19 inline int node2tagpos(treeNode x) \r
20 {\r
21   return (int)x;\r
22 }\r
23 \r
24 // returns NULLT if the test is true\r
25 #define NULLT_IF(x)  do { if (x) return NULLT; } while (0)\r
26 \r
27 \r
28 XMLTree::XMLTree( pb * const par, uint npar,  vector<string> * const TN,  TagIdMap * const tim, uint *empty_texts_bmp, TagType *tags,\r
29             TextCollection * const TC, bool dis_tc)\r
30 \r
31  {\r
32     // creates the data structure for the tree topology\r
33     Par = (bp *)umalloc(sizeof(bp));\r
34     bp_construct(Par, npar, (pb*) par, OPT_DEGREE|0);    \r
35    \r
36     // creates structure for tags\r
37 \r
38     TagName = (vector<string>*)TN;\r
39     tIdMap = (TagIdMap *) tim;\r
40     \r
41     uint max_tag = TN->size() - 1;\r
42       \r
43     static_bitsequence_builder *bmb = new static_bitsequence_builder_sdarray();\r
44     alphabet_mapper *am = new alphabet_mapper_none();\r
45     Tags = new static_sequence_bs((uint*)tags,npar,am,bmb);\r
46     \r
47     cout << "Tags test: " << Tags->test((uint*)tags,npar) << endl;\r
48 \r
49     tags_blen = bits(max_tag);\r
50     tags_len = (uint)npar;\r
51     tags_fix = new uint[uint_len(tags_blen,tags_len)];\r
52     for(uint i=0;i<(uint)npar;i++)\r
53        set_field(tags_fix,tags_blen,i,tags[i]);\r
54 \r
55     delete bmb;    \r
56     free(tags);\r
57     tags = NULL;\r
58     \r
59     Text = (TextCollection*) TC;\r
60 \r
61 \r
62     EBVector = new static_bitsequence_rrr02(empty_texts_bmp,npar,32);\r
63     free(empty_texts_bmp);\r
64     empty_texts_bmp = NULL;\r
65 \r
66     \r
67     disable_tc = dis_tc;\r
68  }\r
69 \r
70 \r
71 // ~XMLTree: frees memory of XML tree.\r
72 XMLTree::~XMLTree() \r
73  { \r
74     int i;\r
75 \r
76     destroyTree(Par);\r
77     free(Par); // frees the memory of struct Par\r
78    \r
79     delete tIdMap;\r
80     tIdMap = NULL;\r
81     \r
82     delete TagName;\r
83     TagName = NULL;\r
84     \r
85     delete Tags;\r
86     Tags = NULL;\r
87 \r
88     delete Text; \r
89     Text = NULL;\r
90 \r
91     delete EBVector;\r
92     EBVector = NULL;\r
93 \r
94 \r
95  }\r
96 \r
97 \r
98 void XMLTree::print_stats() \r
99  {\r
100     uint total_space = Tags->size()+sizeof(static_sequence*);\r
101     total_space += sizeof(uint*)+sizeof(uint)*(2+uint_len(tags_blen,tags_len));\r
102     cout << "Space usage for XMLTree:" << endl\r
103          << " - tags static_sequence: " << Tags->size()+sizeof(static_sequence*) << endl\r
104          << " - tags access array:    " << sizeof(uint*)+sizeof(uint)*(2+uint_len(tags_blen,tags_len)) << endl\r
105          << " ... add Diego structures ... " << endl\r
106          << " *total* " << total_space << endl;\r
107  }\r
108 \r
109 // Save: saves XML tree data structure to file. \r
110 void XMLTree::Save(int fd) \r
111  {\r
112     FILE *fp;\r
113     char filenameaux[1024];\r
114     int i;\r
115 \r
116     fp = fdopen(fd, "wa");\r
117     // first stores the tree topology\r
118     saveTree(Par, fp);\r
119 \r
120     // stores the table with tag names\r
121     int ntags = TagName->size();\r
122 \r
123     ufwrite(&ntags, sizeof(int), 1, fp);\r
124     for (i = 0; i<ntags;i++)\r
125       fprintf(fp, "%s\n",TagName->at(i).c_str());\r
126     \r
127 \r
128     // stores the tags\r
129     Tags->save(fp);\r
130     ufwrite(&tags_blen,sizeof(uint),1,fp);\r
131     ufwrite(&tags_len,sizeof(uint),1,fp);\r
132     ufwrite(tags_fix,sizeof(uint),uint_len(tags_blen,tags_len),fp);\r
133 \r
134     // flags \r
135     ufwrite(&disable_tc, sizeof(bool),1,fp);\r
136     \r
137     //text positions\r
138     EBVector->save(fp);\r
139     \r
140     // stores the texts   \r
141     if (!disable_tc) {\r
142       Text->Save(fp);\r
143     };\r
144 \r
145 \r
146  }\r
147 \r
148 \r
149 // Load: loads XML tree data structure from file. Returns\r
150 // a pointer to the loaded data structure\r
151 XMLTree *XMLTree::Load(int fd) \r
152  {\r
153     FILE *fp;\r
154     char buffer[1024];\r
155     XMLTree *XML_Tree;\r
156     int i;\r
157 \r
158 \r
159 \r
160     fp = fdopen(fd, "r");\r
161 \r
162     XML_Tree = new XMLTree();\r
163 \r
164     // Load the tree structure\r
165     XML_Tree->Par = (bp *)umalloc(sizeof(bp));\r
166 \r
167     loadTree(XML_Tree->Par, fp); \r
168 \r
169     XML_Tree->TagName = new vector<string>();\r
170     XML_Tree->tIdMap = new std::unordered_map<string,int>();\r
171     \r
172     string s;\r
173     int ntags;\r
174     \r
175     // Load the tag names\r
176     ufread(&ntags, sizeof(int), 1, fp);\r
177 \r
178     for (i=0; i<ntags;i++) {\r
179       char * r = fgets(buffer,1023,fp);\r
180        if (r==NULL)\r
181          throw "Cannot read tag list";\r
182        s = (const char*) buffer;\r
183        // remove the trailing \n\r
184        s.erase(s.size()-1);       \r
185        XML_Tree->TagName->push_back(s);\r
186        XML_Tree->tIdMap->insert(std::make_pair(s,i));\r
187        \r
188     };\r
189 \r
190 \r
191     // loads the tag structure\r
192     XML_Tree->Tags = static_sequence::load(fp);\r
193     ufread(&XML_Tree->tags_blen,sizeof(uint),1,fp);\r
194     ufread(&XML_Tree->tags_len,sizeof(uint),1,fp);\r
195     XML_Tree->tags_fix = new uint[uint_len(XML_Tree->tags_blen,XML_Tree->tags_len)];\r
196     ufread(XML_Tree->tags_fix,sizeof(uint),uint_len(XML_Tree->tags_blen,XML_Tree->tags_len),fp);\r
197 \r
198     // TODO ask francisco about this\r
199     /// FIXME:UGLY tests!\r
200     uint * seq = new uint[XML_Tree->tags_len];\r
201     for(uint i=0;i<XML_Tree->tags_len;i++)\r
202       seq[i] = get_field(XML_Tree->tags_fix,XML_Tree->tags_blen,i);\r
203     //cout << "Tags test: " << XML_Tree->Tags->test(seq,XML_Tree->tags_len) << endl;\r
204     XML_Tree->Tags->test(seq,XML_Tree->tags_len);\r
205     delete [] seq;\r
206     /// End ugly tests\r
207     \r
208 \r
209     // loads the flags\r
210     \r
211     ufread(&(XML_Tree->disable_tc), sizeof(bool), 1, fp);\r
212 \r
213     XML_Tree->EBVector = static_bitsequence_rrr02::load(fp);\r
214 \r
215     // Not used  \r
216     int sample_rate_text = 64;\r
217     // loads the texts\r
218     if (!XML_Tree->disable_tc){\r
219       XML_Tree->Text = TextCollection::Load(fp,sample_rate_text);\r
220     }\r
221     else XML_Tree->Text = NULL;\r
222     \r
223     return XML_Tree;\r
224  }\r
225 \r
226 \r
227 // root(): returns the tree root.\r
228 inline treeNode XMLTree::Root() \r
229  {\r
230    return 0; //root_node(Par);\r
231  }\r
232 \r
233 // SubtreeSize(x): the number of nodes (and attributes) in the subtree of node x.\r
234 int XMLTree::SubtreeSize(treeNode x) \r
235  {\r
236     return subtree_size(Par, x);\r
237  }\r
238 \r
239 // SubtreeTags(x,tag): the number of occurrences of tag within the subtree of node x.\r
240 int XMLTree::SubtreeTags(treeNode x, TagType tag) \r
241  {\r
242     if (x == Root())\r
243       x = first_child(Par,x);\r
244     \r
245 \r
246     int s = x + 2*subtree_size(Par, x) - 1;\r
247  \r
248     return Tags->rank(tag, s) - Tags->rank(tag, node2tagpos(x)-1);\r
249  }\r
250 \r
251 // IsLeaf(x): returns whether node x is leaf or not. In the succinct representation\r
252 // this is just a bit inspection.\r
253 bool XMLTree::IsLeaf(treeNode x) \r
254  {\r
255     return isleaf(Par, x);\r
256  } \r
257 \r
258 // IsAncestor(x,y): returns whether node x is ancestor of node y.\r
259 bool XMLTree::IsAncestor(treeNode x, treeNode y) \r
260  {\r
261     return is_ancestor(Par, x, y);\r
262  }\r
263 \r
264 // IsChild(x,y): returns whether node x is parent of node y.\r
265 bool XMLTree::IsChild(treeNode x, treeNode y) \r
266  {\r
267     if (!is_ancestor(Par, x, y)) return false;\r
268     return depth(Par, x) == (depth(Par, y) + 1);\r
269  }\r
270 \r
271 // IsFirstChild(x): returns whether node x is the first child of its parent.\r
272 bool XMLTree::IsFirstChild(treeNode x)\r
273  {\r
274     return ((x != NULLT)&&(x==Root() || prev_sibling(Par,x) == (treeNode)-1));\r
275  }\r
276 \r
277 \r
278 // NumChildren(x): number of children of node x. Constant time with the data structure\r
279 // of Sadakane.\r
280 int XMLTree::NumChildren(treeNode x) \r
281  {\r
282     return degree(Par, x);\r
283  }\r
284 \r
285 // ChildNumber(x): returns i if node x is the i-th children of its parent.\r
286 int XMLTree::ChildNumber(treeNode x) \r
287  {\r
288     return child_rank(Par, x);\r
289  }\r
290 \r
291 // Depth(x): depth of node x, a simple binary rank on the parentheses sequence.\r
292 int XMLTree::Depth(treeNode x) \r
293  {\r
294     return depth(Par, x);\r
295  }\r
296 \r
297 // Preorder(x): returns the preorder number of node x, just counting the tree\r
298 // nodes (i.e., tags, it disregards the texts in the tree).\r
299 int XMLTree::Preorder(treeNode x) \r
300  {\r
301     return preorder_rank(Par, x);\r
302  }\r
303 \r
304 // Postorder(x): returns the postorder number of node x, just counting the tree\r
305 // nodes (i.e., tags, it disregards the texts in the tree).\r
306 int XMLTree::Postorder(treeNode x) \r
307  {\r
308     return postorder_rank(Par, x);\r
309  }\r
310 \r
311 // Tag(x): returns the tag identifier of node x.\r
312 TagType XMLTree::Tag(treeNode x) \r
313  {\r
314     return get_field(tags_fix,tags_blen,node2tagpos(x));\r
315  }\r
316 \r
317 // DocIds(x): returns the range of text identifiers that descend from node x.\r
318 // returns {NULLT, NULLT} when there are no texts descending from x.\r
319 range XMLTree::DocIds(treeNode x) \r
320  {\r
321     range r;\r
322     if (x == NULLT) {\r
323        r.min = NULLT;\r
324        r.max = NULLT;\r
325        return r;\r
326     };\r
327         \r
328     \r
329     int min = EBVector->rank1(x-1);                          \r
330     int max = EBVector->rank1(x+2*subtree_size(Par, x)-2); \r
331     if (min==max) { // range is empty, no texts within the subtree of x\r
332       r.min = NULLT;\r
333       r.max = NULLT;\r
334     }\r
335     else { // the range is non-empty, there are texts within the subtree of x\r
336       r.min = min+1;\r
337       r.max = max;\r
338     }\r
339     return r;\r
340 \r
341  }\r
342 \r
343 // Parent(x): returns the parent node of node x.\r
344 treeNode XMLTree::Parent(treeNode x) \r
345  {\r
346     if (x == Root())\r
347       return NULLT;\r
348     else\r
349       return parent(Par, x);\r
350  }\r
351 \r
352 // Child(x,i): returns the i-th child of node x, assuming it exists.\r
353 treeNode XMLTree::Child(treeNode x, int i) \r
354 {\r
355     if (i <= OPTD) return naive_child(Par, x, i);\r
356     else return child(Par, x, i);\r
357 }\r
358 \r
359 // FirstChild(x): returns the first child of node x, assuming it exists. Very fast in BP.\r
360 treeNode XMLTree::FirstChild(treeNode x) \r
361  {\r
362    NULLT_IF(x==NULLT);\r
363    return first_child(Par, x);\r
364  }\r
365 \r
366 treeNode XMLTree::FirstElement(treeNode x) \r
367  {\r
368    NULLT_IF(x==NULLT);\r
369    treeNode fc = first_child(Par, x);\r
370    //<$> is 2\r
371    return ((fc == NULLT || Tag(fc) != PCDATA_TAG_ID) ? fc : next_sibling(Par,fc));\r
372 \r
373  }\r
374 \r
375 treeNode XMLTree::NextElement(treeNode x) \r
376 {\r
377    NULLT_IF(x==NULLT);\r
378    treeNode ns = next_sibling(Par, x);\r
379    return ((ns == NULLT || Tag(ns) != PCDATA_TAG_ID) ? ns : next_sibling(Par,ns));\r
380 }\r
381 \r
382 // LastChild(x): returns the last child of node x.\r
383 treeNode XMLTree::LastChild(treeNode x)\r
384  {\r
385    NULLT_IF(x==NULLT || x == Root() || isleaf(Par,x));\r
386    return find_open(Par, find_close(Par, x)-1);\r
387  }\r
388 \r
389 \r
390 // NextSibling(x): returns the next sibling of node x, assuming it exists.\r
391 treeNode XMLTree::NextSibling(treeNode x) \r
392  {\r
393    NULLT_IF(x==NULLT || x == Root() );\r
394    return next_sibling(Par, x);\r
395  }\r
396 \r
397 // PrevSibling(x): returns the previous sibling of node x, assuming it exists.\r
398 treeNode XMLTree::PrevSibling(treeNode x) \r
399  {\r
400    NULLT_IF(x==NULLT || x == Root());\r
401    return prev_sibling(Par, x);\r
402  }\r
403 \r
404 // TaggedChild(x,tag): returns the first child of node x tagged tag, or NULLT if there is none.\r
405 // Because of the balanced-parentheses representation of the tree, this operation is not supported\r
406 // efficiently, just iterating among the children of node x until finding the desired child.\r
407 treeNode XMLTree::TaggedChild(treeNode x, TagType tag) \r
408  {\r
409    \r
410    NULLT_IF(x==NULLT || isleaf(Par,x));\r
411 \r
412    treeNode child;   \r
413    child = first_child(Par, x); // starts at first child of node x\r
414    if (get_field(tags_fix,tags_blen,node2tagpos(child)) == tag)\r
415      return child;\r
416    else\r
417      return TaggedFollSibling(child,tag);\r
418  }\r
419 \r
420 // TaggedSibling(x,tag): returns the first sibling of node x tagged tag, or NULLT if there is none.\r
421 treeNode XMLTree::TaggedFollSibling(treeNode x, TagType tag)\r
422 {\r
423   NULLT_IF(x==NULLT);\r
424   treeNode sibling = next_sibling(Par, x); \r
425   while (sibling != NULLT) {\r
426     if (get_field(tags_fix,tags_blen,node2tagpos(sibling)) == tag) // current sibling is labeled with tag of interest\r
427       return sibling; \r
428     sibling = next_sibling(Par, sibling); // OK, let's try with the next sibling\r
429   }\r
430   return NULLT; // no such sibling was found   \r
431 }\r
432 \r
433 treeNode XMLTree::SelectChild(treeNode x, std::unordered_set<int> *tags)\r
434 {\r
435   \r
436   NULLT_IF(x==NULLT || isleaf(Par,x));\r
437   int i;\r
438   treeNode child = first_child(Par, x);  \r
439   TagType t = get_field(tags_fix, tags_blen, node2tagpos(child));\r
440   std::unordered_set<int>::const_iterator tagit = tags->find(t);\r
441   if (tagit != tags->end()) return child;  \r
442   return SelectFollSibling(child,tags);\r
443 }\r
444 \r
445 \r
446 treeNode XMLTree::SelectFollSibling(treeNode x, std::unordered_set<int> *tags)\r
447 {\r
448 \r
449    NULLT_IF(x==NULLT);\r
450    int i;\r
451    TagType t;\r
452    treeNode sibling = next_sibling(Par, x);\r
453    std::unordered_set<int>::const_iterator tagit;\r
454    while (sibling != NULLT) {\r
455      t = get_field(tags_fix, tags_blen, node2tagpos(sibling));\r
456      tagit = tags->find(t);\r
457      if (tagit != tags->end()) return sibling;\r
458      sibling = next_sibling(Par, sibling);\r
459    }\r
460    return NULLT;    \r
461  }\r
462 \r
463 \r
464 // TaggedDesc(x,tag): returns the first node tagged tag with larger preorder than x and within\r
465 // the subtree of x. Returns NULLT if there is none.\r
466 treeNode XMLTree::TaggedDesc(treeNode x, TagType tag) \r
467  {\r
468    NULLT_IF(x==NULLT || isleaf(Par,x));\r
469 \r
470    int s = (int) Tags->select_next(tag,node2tagpos(x));\r
471    NULLT_IF (s == -1);\r
472 \r
473    treeNode y = tagpos2node(s); // transforms the tag position into a node position\r
474    \r
475    return (is_ancestor(Par,x,y) ? y : NULLT);\r
476  }\r
477 \r
478 \r
479 treeNode XMLTree::SelectDesc(treeNode x, std::unordered_set<int> *tags)\r
480  {\r
481    NULLT_IF (x ==NULLT || isleaf(Par,x));\r
482    int i;\r
483    treeNode min = NULLT;\r
484    treeNode fc = first_child(Par,x);\r
485    treeNode aux;\r
486    std::unordered_set<int>::const_iterator tagit;\r
487    for (tagit = tags->begin(); tagit != tags->end(); tagit++) {\r
488      aux = TaggedDesc(x, (TagType) *tagit);\r
489      if (aux == fc) return fc;\r
490      if (aux == NULLT) continue;\r
491      if ((min == NULLT) || (aux < min)) min = aux;\r
492    };\r
493    return min;\r
494  }\r
495 \r
496 \r
497 \r
498 // TaggedPrec(x,tag): returns the first node tagged tag with smaller preorder than x and not an\r
499 // ancestor of x. Returns NULLT if there is none.\r
500 treeNode XMLTree::TaggedPrec(treeNode x, TagType tag) \r
501  {    \r
502     int r, s;\r
503     treeNode node_s, root;\r
504     r = (int)Tags->rank(tag, node2tagpos(x)-1);\r
505     if (r==0) return NULLT; // there is no such node.\r
506     s = (int)Tags->select(tag, r);\r
507     root = root_node(Par);\r
508     node_s = tagpos2node(s);\r
509     while (is_ancestor(Par, node_s, x) && (node_s!=root)) { // the one that we found is an ancestor of x\r
510        r--;\r
511        if (r==0) return NULLT; // there is no such node\r
512        s = (int)Tags->select(tag, r);  // we should use select_prev instead when provided\r
513        node_s = tagpos2node(s);\r
514     }\r
515     return NULLT; // there is no such node \r
516  }\r
517 \r
518 \r
519 // TaggedFoll(x,tag): returns the first node tagged tag with larger preorder than x and not in\r
520 // the subtree of x. Returns NULLT if there is none.\r
521 treeNode XMLTree::TaggedFoll(treeNode x, TagType tag)\r
522  {\r
523    NULLT_IF (x ==NULLT || x == Root());\r
524    \r
525    return tagpos2node(Tags->select_next(tag,find_close(Par, x)));\r
526 \r
527  } \r
528 \r
529 // TaggedFollBelow(x,tag,root): returns the first node tagged tag with larger preorder than x \r
530 // and not in the subtree of x. Returns NULLT if there is none.\r
531 treeNode XMLTree::TaggedFollBelow(treeNode x, TagType tag, treeNode root)\r
532 {\r
533 \r
534   NULLT_IF (x == NULLT || x == Root());\r
535   \r
536   treeNode s = tagpos2node(Tags->select_next(tag, find_close(Par, x)));\r
537   \r
538   if (root == Root()) return s;\r
539   NULLT_IF (s == NULLT || s >= find_close(Par, root));\r
540   \r
541   return s;\r
542\r
543 \r
544 /* Here we inline TaggedFoll to find the min globally, and only at the end\r
545    we check if the min is below the context node */\r
546 treeNode XMLTree::SelectFollBelow(treeNode x, std::unordered_set<int> *tags, treeNode root)\r
547  {\r
548 \r
549    NULLT_IF(x==NULLT || x==Root());\r
550    int i;\r
551    treeNode min = NULLT;\r
552    treeNode ns = next_sibling(Par, x);\r
553    treeNode aux;\r
554    std::unordered_set<int>::const_iterator tagit;\r
555    for (tagit = tags->begin(); tagit != tags->end(); tagit++) {\r
556 \r
557      aux = tagpos2node(Tags->select_next(*tagit, find_close(Par, x)));\r
558      \r
559      // The next sibling of x is guaranteed to be below ctx\r
560      // and is the node with lowest preorder which is after ctx.\r
561      // if we find it, we return early;\r
562      \r
563      if (aux == ns ) return ns;\r
564      if (aux == NULLT) continue;\r
565      if ((min == NULLT) || (aux < min)) min = aux;\r
566    };\r
567      \r
568    // found the smallest node in preorder which is after x.\r
569    // if ctx is the root node, just return what we found.\r
570 \r
571    if (root == Root()) return min;\r
572    // else check whether if is in below the ctx node\r
573 \r
574    NULLT_IF (min == NULLT || min >= find_close(Par, root));\r
575    \r
576    return min;\r
577    \r
578  }\r
579 \r
580 \r
581 // TaggedAncestor(x, tag): returns the closest ancestor of x tagged tag. Return\r
582 // NULLT is there is none.\r
583 treeNode XMLTree::TaggedAncestor(treeNode x, TagType tag)\r
584  {    \r
585     if (x == NULLT || x == Root())\r
586        return NULLT;\r
587     \r
588     treeNode s = parent(Par, x), r = Root();\r
589     while (s != r) {\r
590        if (get_field(tags_fix,tags_blen,node2tagpos(s)) /*Tags->access(node2tagpos(s))*/ == tag) return s;\r
591        s = parent(Par, s);\r
592     }\r
593     return NULLT;\r
594  }\r
595 \r
596 \r
597 \r
598 // MyText(x): returns the document identifier of the text below node x, \r
599 // or NULLT if x is not a leaf node or the text is empty. Assumes Doc \r
600 // ids start from 0.\r
601 DocID XMLTree::MyText(treeNode x) \r
602 {\r
603   TagType tag = Tag(x);\r
604   // seems faster than testing EBVector->access(x);\r
605 \r
606   if (tag == PCDATA_TAG_ID || tag == ATTRIBUTE_DATA_TAG_ID)\r
607     return (DocID) (EBVector->rank1(x)-1); //-1 because document ids start from 0\r
608   else \r
609     return (DocID) NULLT;\r
610   \r
611 }\r
612 \r
613 // TextXMLId(d): returns the preorder of document with identifier d in the tree consisting of\r
614 // all tree nodes and all text nodes. Assumes that the tree root has preorder 1.\r
615 int XMLTree::TextXMLId(DocID d) \r
616  {\r
617    NULLT_IF(d == NULLT);\r
618      int s = EBVector->select1(d+1);\r
619    return rank_open(Par, s) + d + 1; // +1 because root has preorder 1\r
620    \r
621  }\r
622 \r
623 // NodeXMLId(x): returns the preorder of node x in the tree consisting \r
624 // of all tree nodes and all text nodes. Assumes that the tree root has\r
625 // preorder 0;\r
626 int XMLTree::NodeXMLId(treeNode x) \r
627  {\r
628    NULLT_IF(x == NULLT);\r
629    if (x == Root()) return 1; // root node has preorder 1\r
630    return rank_open(Par, x) + EBVector->rank1(x-1);\r
631  }\r
632 \r
633 // ParentNode(d): returns the parent node of document identifier d.\r
634 treeNode XMLTree::ParentNode(DocID d) \r
635  {    \r
636    NULLT_IF (d == NULLT);   \r
637    return (treeNode) EBVector->select1(d+1);     \r
638  }\r
639 \r
640 // GetTagId: returns the tag identifier corresponding to a given tag name.\r
641 // Returns NULLT in case that the tag name does not exists.\r
642 TagType XMLTree::GetTagId(unsigned char *tagname)\r
643  {\r
644   \r
645    string s = (char *) tagname;\r
646    TagIdMapIT it = tIdMap->find(s);    \r
647    return (TagType) ((it != tIdMap->end()) ? it->second : -1);\r
648     \r
649  }\r
650 \r
651 \r
652 // GetTagName(tagid): returns the tag name of a given tag identifier.\r
653 // Returns NULL in case that the tag identifier is not valid.\r
654 unsigned char *XMLTree::GetTagName(TagType tagid)\r
655  {\r
656     unsigned char *s;\r
657     if ( tagid < 0 || tagid >= TagName->size())\r
658       return (unsigned char *) "<INVALID TAG>";\r
659     strcpy((char *)s, TagName->at(tagid).c_str());\r
660     \r
661     return (s == NULL ? (unsigned char*) "<INVALID TAG>" : s);\r
662  }\r
663 \r
664 \r
665 const unsigned char *XMLTree::GetTagNameByRef(TagType tagid)\r
666  {\r
667 \r
668    unsigned char *s;\r
669    if ( tagid < 0 || tagid >= TagName->size())\r
670      return (unsigned char *) "<INVALID TAG>";\r
671    \r
672    return (const unsigned char *) TagName->at(tagid).c_str();\r
673    \r
674  }\r
675 \r
676 \r
677 \r
678 TagType XMLTree::RegisterTag(unsigned char *tagname)\r
679  {  \r
680     TagType id = XMLTree::GetTagId(tagname);\r
681     if (id == NULLT) {\r
682       string s = (char *) tagname;      \r
683       REGISTER_TAG(TagName,tIdMap,s);\r
684       \r
685     };\r
686     \r
687     return id;\r
688  }\r
689 \r
690 \r