28 |
28 |
29 #include <stdio.h> |
29 #include <stdio.h> |
30 #include <stdlib.h> |
30 #include <stdlib.h> |
31 #include <string.h> |
31 #include <string.h> |
32 |
32 |
|
33 |
33 #include "xml.h" |
34 #include "xml.h" |
34 |
35 |
|
36 typedef struct StackElm { |
|
37 WSXmlNode *node; // list of nodes |
|
38 WSXmlNode *parent; // if not NULL, call endcb after node->next is NULL |
|
39 struct StackElm *next; |
|
40 } StackElm; |
35 |
41 |
|
42 #define STACK_PUSH(stack, elm) if(stack) { elm->next = stack; } stack = elm; |
36 |
43 |
|
44 int wsxml_iterator( |
|
45 pool_handle_t *pool, |
|
46 WSXmlNode *node, |
|
47 wsxml_func begincb, |
|
48 wsxml_func endcb, |
|
49 void *udata) |
|
50 { |
|
51 if(!node) { |
|
52 return 0; |
|
53 } |
|
54 |
|
55 StackElm *stack = pool_malloc(pool, sizeof(StackElm)); |
|
56 if(!stack) { |
|
57 return 1; // OOM |
|
58 } |
|
59 stack->next = NULL; |
|
60 stack->node = node; |
|
61 stack->parent = NULL; |
|
62 |
|
63 int ret = 0; |
|
64 int br = 0; |
|
65 while(stack) { |
|
66 StackElm *cur = stack; |
|
67 WSXmlNode *xmlnode = cur->node; // get top stack element |
|
68 stack = cur->next; // and remove it |
|
69 cur->next = NULL; |
|
70 |
|
71 while(xmlnode) { |
|
72 // element begin callback |
|
73 if(begincb(xmlnode, udata)) { |
|
74 br = 1; |
|
75 break; // I don't like break with labels - is this wrong? |
|
76 } |
|
77 |
|
78 if(xmlnode->children) { |
|
79 // put the children on the stack |
|
80 // the next stack iteration will process the children |
|
81 StackElm *newelm = pool_malloc(pool, sizeof(StackElm)); |
|
82 if(!newelm) { |
|
83 ret = 1; |
|
84 br = 1; |
|
85 break; |
|
86 } |
|
87 newelm->next = NULL; |
|
88 newelm->node = xmlnode->children; |
|
89 // setting the parent will make sure endcb will be called |
|
90 // for the current xmlnode after all children are processed |
|
91 newelm->parent = xmlnode; |
|
92 |
|
93 // if xmlnode->next is not NULL, there are still nodes at |
|
94 // this level, therefore we have to put these also on the |
|
95 // stack |
|
96 // this way, the remaining nodes are processed after all |
|
97 // children of the current node are processed |
|
98 if(xmlnode->next) { |
|
99 // reuse current StackElm |
|
100 cur->node = xmlnode->next; |
|
101 STACK_PUSH(stack, cur); |
|
102 cur = NULL; |
|
103 } |
|
104 |
|
105 // now we can put the children on the stack |
|
106 STACK_PUSH(stack, newelm); |
|
107 // break, because we don't want to process xmlnode->next now |
|
108 break; |
|
109 } else { |
|
110 // no children means, the end callback can be called directly |
|
111 // after the begin callback (no intermediate nodes) |
|
112 if(endcb(xmlnode, udata)) { |
|
113 br = 1; |
|
114 break; |
|
115 } |
|
116 } |
|
117 |
|
118 // continue with next node at this level |
|
119 xmlnode = xmlnode->next; |
|
120 } |
|
121 if(br) { |
|
122 break; // break because of an error |
|
123 } |
|
124 |
|
125 if(cur) { |
|
126 if(cur->parent) { |
|
127 if(endcb(cur->parent, udata)) { |
|
128 break; |
|
129 } |
|
130 } |
|
131 pool_free(pool, cur); |
|
132 } |
|
133 } |
|
134 |
|
135 // free all remaining elements |
|
136 StackElm *elm = stack; |
|
137 while(elm) { |
|
138 StackElm *next = elm->next; |
|
139 pool_free(pool, elm); |
|
140 elm = next; |
|
141 } |
|
142 |
|
143 return ret; |
|
144 } |
|
145 |