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 |
|
34 #include "xml.h" |
33 #include "xml.h" |
35 |
34 |
36 typedef struct StackElm { |
35 typedef struct StackElm { |
37 WSXmlNode *node; // list of nodes |
36 WSXmlNode *node; // list of nodes |
38 WSXmlNode *parent; // if not NULL, call endcb after node->next is NULL |
37 //WSXmlNode *parent; // if not NULL, call endcb after node->next is NULL |
|
38 int endonly; |
39 struct StackElm *next; |
39 struct StackElm *next; |
40 } StackElm; |
40 } StackElm; |
41 |
41 |
42 #define STACK_PUSH(stack, elm) if(stack) { elm->next = stack; } stack = elm; |
42 #define STACK_PUSH(stack, elm) if(stack) { elm->next = stack; } stack = elm; |
43 |
43 |
56 if(!stack) { |
56 if(!stack) { |
57 return 1; // OOM |
57 return 1; // OOM |
58 } |
58 } |
59 stack->next = NULL; |
59 stack->next = NULL; |
60 stack->node = node; |
60 stack->node = node; |
61 stack->parent = NULL; |
61 stack->endonly = 0; |
|
62 //stack->parent = NULL; |
62 |
63 |
63 int ret = 0; |
64 int ret = 0; |
64 int br = 0; |
65 int br = 0; |
65 while(stack) { |
66 while(stack) { |
66 StackElm *cur = stack; |
67 StackElm *cur = stack; |
67 WSXmlNode *xmlnode = cur->node; // get top stack element |
68 WSXmlNode *xmlnode = cur->node; // get top stack element |
68 stack = cur->next; // and remove it |
69 stack = cur->next; // and remove it |
69 cur->next = NULL; |
70 cur->next = NULL; |
70 |
71 |
71 while(xmlnode) { |
72 while(xmlnode && !cur->endonly) { |
72 // element begin callback |
73 // element begin callback |
73 if(begincb(xmlnode, udata)) { |
74 if(begincb(xmlnode, udata)) { |
74 br = 1; |
75 br = 1; |
75 break; // I don't like break with labels - is this wrong? |
76 break; // I don't like break with labels - is this wrong? |
76 } |
77 } |
86 } |
87 } |
87 newelm->next = NULL; |
88 newelm->next = NULL; |
88 newelm->node = xmlnode->children; |
89 newelm->node = xmlnode->children; |
89 // setting the parent will make sure endcb will be called |
90 // setting the parent will make sure endcb will be called |
90 // for the current xmlnode after all children are processed |
91 // for the current xmlnode after all children are processed |
91 newelm->parent = xmlnode; |
92 //newelm->parent = xmlnode; |
|
93 newelm->endonly = 0; |
92 |
94 |
93 // if xmlnode->next is not NULL, there are still nodes at |
95 // if xmlnode->next is not NULL, there are still nodes at |
94 // this level, therefore we have to put these also on the |
96 // this level, therefore we have to put these also on the |
95 // stack |
97 // stack |
96 // this way, the remaining nodes are processed after all |
98 // this way, the remaining nodes are processed after all |
97 // children of the current node are processed |
99 // children and the end tag are processed |
98 if(xmlnode->next) { |
100 if(xmlnode->next) { |
99 // reuse current StackElm |
101 StackElm *nextelm = pool_malloc(pool, sizeof(StackElm)); |
100 cur->node = xmlnode->next; |
102 if(!nextelm) { |
101 STACK_PUSH(stack, cur); |
103 ret = 1; |
102 cur = NULL; |
104 br = 1; |
|
105 break; |
|
106 } |
|
107 nextelm->node = xmlnode->next; |
|
108 nextelm->next = NULL; |
|
109 nextelm->endonly = 0; |
|
110 STACK_PUSH(stack, nextelm); |
103 } |
111 } |
|
112 |
|
113 // we have to put the end tag of the current element |
|
114 // on the stack to ensure endcb is called for the current |
|
115 // element, after all children are processed |
|
116 // reuse cur |
|
117 cur->node = xmlnode; |
|
118 cur->endonly = 1; |
|
119 STACK_PUSH(stack, cur); |
|
120 |
|
121 cur = NULL; |
104 |
122 |
105 // now we can put the children on the stack |
123 // now we can put the children on the stack |
106 STACK_PUSH(stack, newelm); |
124 STACK_PUSH(stack, newelm); |
107 // break, because we don't want to process xmlnode->next now |
125 // break, because we don't want to process xmlnode->next now |
108 break; |
126 break; |
109 } else { |
127 } else { |
110 // no children means, the end callback can be called directly |
128 // no children means, the end callback can be called directly |
111 // after the begin callback (no intermediate nodes) |
129 // after the begin callback (no intermediate nodes) |
|
130 cur->node = NULL; |
112 if(endcb(xmlnode, udata)) { |
131 if(endcb(xmlnode, udata)) { |
113 br = 1; |
132 br = 1; |
114 break; |
133 break; |
115 } |
134 } |
116 } |
135 } |