File Coverage

xpath.c
Criterion Covered Total %
statement 113 180 62.7
branch 49 100 49.0
condition n/a
subroutine n/a
pod n/a
total 162 280 57.8


line stmt bran cond sub pod time code
1             /* $Id$
2             *
3             * This is free software, you may use it and distribute it under the same terms as
4             * Perl itself.
5             *
6             * Copyright 2001-2003 AxKit.com Ltd., 2002-2006 Christian Glahn, 2006-2009 Petr Pajas
7             */
8              
9             #include
10             #include
11             #include
12             #include
13              
14             #include "EXTERN.h"
15              
16             #include "dom.h"
17             #include "xpath.h"
18              
19             void
20 1           perlDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs){
21 1           xmlXPathObjectPtr obj = NULL, obj2 = NULL;
22 1           xmlChar *base = NULL, *URI = NULL;
23              
24              
25 1 50         if ((nargs < 1) || (nargs > 2)) {
    50          
26 0           ctxt->error = XPATH_INVALID_ARITY;
27 0           return;
28             }
29 1 50         if (ctxt->value == NULL) {
30 0           ctxt->error = XPATH_INVALID_TYPE;
31 0           return;
32             }
33              
34 1 50         if (nargs == 2) {
35 0 0         if (ctxt->value->type != XPATH_NODESET) {
36 0           ctxt->error = XPATH_INVALID_TYPE;
37 0           return;
38             }
39              
40 0           obj2 = valuePop(ctxt);
41             }
42              
43              
44             /* first assure the XML::LibXML error handler is deactivated
45             otherwise strange things might happen
46             */
47              
48 1 50         if (ctxt->value->type == XPATH_NODESET) {
49             int i;
50             xmlXPathObjectPtr newobj, ret;
51              
52 0           obj = valuePop(ctxt);
53 0           ret = xmlXPathNewNodeSet(NULL);
54              
55 0 0         if (obj->nodesetval) {
56 0 0         for (i = 0; i < obj->nodesetval->nodeNr; i++) {
57 0           valuePush(ctxt,
58 0           xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
59 0           xmlXPathStringFunction(ctxt, 1);
60 0 0         if (nargs == 2) {
61 0           valuePush(ctxt, xmlXPathObjectCopy(obj2));
62             } else {
63 0           valuePush(ctxt,
64 0           xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
65             }
66 0           perlDocumentFunction(ctxt, 2);
67 0           newobj = valuePop(ctxt);
68 0           ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
69             newobj->nodesetval);
70 0           xmlXPathFreeObject(newobj);
71             }
72             }
73              
74 0           xmlXPathFreeObject(obj);
75 0 0         if (obj2 != NULL)
76 0           xmlXPathFreeObject(obj2);
77 0           valuePush(ctxt, ret);
78              
79             /* reset the error old error handler before leaving
80             */
81 0           return;
82             }
83             /*
84             * Make sure it's converted to a string
85             */
86 1           xmlXPathStringFunction(ctxt, 1);
87 1 50         if (ctxt->value->type != XPATH_STRING) {
88 0           ctxt->error = XPATH_INVALID_TYPE;
89 0 0         if (obj2 != NULL)
90 0           xmlXPathFreeObject(obj2);
91              
92             /* reset the error old error handler before leaving
93             */
94              
95 0           return;
96             }
97 1           obj = valuePop(ctxt);
98 1 50         if (obj->stringval == NULL) {
99 0           valuePush(ctxt, xmlXPathNewNodeSet(NULL));
100             } else {
101 1 50         if ((obj2 != NULL) && (obj2->nodesetval != NULL) &&
    0          
    0          
102 0           (obj2->nodesetval->nodeNr > 0)) {
103             xmlNodePtr target;
104              
105 0           target = obj2->nodesetval->nodeTab[0];
106 0 0         if (target->type == XML_ATTRIBUTE_NODE) {
107 0           target = ((xmlAttrPtr) target)->parent;
108             }
109 0           base = xmlNodeGetBase(target->doc, target);
110             } else {
111 1           base = xmlNodeGetBase(ctxt->context->node->doc, ctxt->context->node);
112             }
113 1           URI = xmlBuildURI(obj->stringval, base);
114 1 50         if (base != NULL)
115 1           xmlFree(base);
116 1 50         if (URI == NULL) {
117 0           valuePush(ctxt, xmlXPathNewNodeSet(NULL));
118             } else {
119 1 50         if (xmlStrEqual(ctxt->context->node->doc->URL, URI)) {
120 0           valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr)ctxt->context->node->doc));
121             }
122             else {
123             xmlDocPtr doc;
124 1           doc = xmlParseFile((const char *)URI);
125 1 50         if (doc == NULL)
126 0           valuePush(ctxt, xmlXPathNewNodeSet(NULL));
127             else {
128             /* TODO: use XPointer of HTML location for fragment ID */
129             /* pbm #xxx can lead to location sets, not nodesets :-) */
130 1           valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc));
131             }
132             }
133 1           xmlFree(URI);
134             }
135             }
136 1           xmlXPathFreeObject(obj);
137 1 50         if (obj2 != NULL)
138 0           xmlXPathFreeObject(obj2);
139              
140             /* reset the error old error handler before leaving
141             */
142             }
143              
144              
145             /**
146             * Most of the code is stolen from testXPath.
147             * The almost only thing I added, is the storeing of the data, so
148             * we can access the data easily - or say more easiely than through
149             * libxml2.
150             **/
151              
152             xmlXPathObjectPtr
153 143           domXPathFind( xmlNodePtr refNode, xmlChar * path, int to_bool ) {
154 143           xmlXPathObjectPtr res = NULL;
155             xmlXPathCompExprPtr comp;
156 143           comp = xmlXPathCompile( path );
157 143 100         if ( comp == NULL ) {
158 20           return NULL;
159             }
160 123           res = domXPathCompFind(refNode,comp,to_bool);
161 123           xmlXPathFreeCompExpr(comp);
162 123           return res;
163             }
164              
165             xmlXPathObjectPtr
166 129           domXPathCompFind( xmlNodePtr refNode, xmlXPathCompExprPtr comp, int to_bool ) {
167 129           xmlXPathObjectPtr res = NULL;
168              
169 129 50         if ( refNode != NULL && comp != NULL ) {
    50          
170             xmlXPathContextPtr ctxt;
171              
172 129           xmlDocPtr tdoc = NULL;
173 129           xmlNodePtr froot = refNode;
174              
175 129 50         if ( comp == NULL ) {
176 0           return NULL;
177             }
178              
179 129 50         if ( refNode->doc == NULL ) {
180             /* if one XPaths a node from a fragment, libxml2 will
181             refuse the lookup. this is not very useful for XML
182             scripters. thus we need to create a temporary document
183             to make libxml2 do it's job correctly.
184             */
185 0           tdoc = xmlNewDoc( NULL );
186              
187             /* find refnode's root node */
188 0 0         while ( froot != NULL ) {
189 0 0         if ( froot->parent == NULL ) {
190 0           break;
191             }
192 0           froot = froot->parent;
193             }
194 0           xmlAddChild((xmlNodePtr)tdoc, froot);
195 0           xmlSetTreeDoc(froot, tdoc); /* probably no need to clean psvi */
196 0           froot->doc = tdoc;
197             /* refNode->doc = tdoc; */
198             }
199              
200             /* prepare the xpath context */
201 129           ctxt = xmlXPathNewContext( refNode->doc );
202 129           ctxt->node = refNode;
203             /* get the namespace information */
204 129 100         if (refNode->type == XML_DOCUMENT_NODE) {
205 85           ctxt->namespaces = xmlGetNsList( refNode->doc,
206 85           xmlDocGetRootElement( refNode->doc ) );
207             }
208             else {
209 44           ctxt->namespaces = xmlGetNsList(refNode->doc, refNode);
210             }
211 129           ctxt->nsNr = 0;
212 129 100         if (ctxt->namespaces != NULL) {
213 94 100         while (ctxt->namespaces[ctxt->nsNr] != NULL)
214 53           ctxt->nsNr++;
215             }
216              
217 129           xmlXPathRegisterFunc(ctxt,
218             (const xmlChar *) "document",
219             perlDocumentFunction);
220 129 100         if (to_bool) {
221             #if LIBXML_VERSION >= 20627
222 8           int val = xmlXPathCompiledEvalToBoolean(comp, ctxt);
223 8           res = xmlXPathNewBoolean(val);
224             #else
225             res = xmlXPathCompiledEval(comp, ctxt);
226             if (res!=NULL) {
227             int val = xmlXPathCastToBoolean(res);
228             xmlXPathFreeObject(res);
229             res = xmlXPathNewBoolean(val);
230             }
231             #endif
232             } else {
233 121           res = xmlXPathCompiledEval(comp, ctxt);
234             }
235 129 100         if (ctxt->namespaces != NULL) {
236 41           xmlFree( ctxt->namespaces );
237             }
238              
239 129           xmlXPathFreeContext(ctxt);
240              
241 129 50         if ( tdoc != NULL ) {
242             /* after looking through a fragment, we need to drop the
243             fake document again */
244 0           xmlSetTreeDoc(froot, NULL); /* probably no need to clean psvi */
245 0           froot->doc = NULL;
246 0           froot->parent = NULL;
247 0           tdoc->children = NULL;
248 0           tdoc->last = NULL;
249             /* next line is not required anymore */
250             /* refNode->doc = NULL; */
251              
252 0           xmlFreeDoc( tdoc );
253             }
254             }
255 129           return res;
256             }
257              
258             /* this function is not actually used: */
259             xmlNodeSetPtr
260 92           domXPathSelect( xmlNodePtr refNode, xmlChar * path ) {
261 92           xmlNodeSetPtr rv = NULL;
262 92           xmlXPathObjectPtr res = NULL;
263              
264 92           res = domXPathFind( refNode, path, 0 );
265              
266 92 100         if (res != NULL) {
267             /* here we have to transfer the result from the internal
268             structure to the return value */
269             /* get the result from the query */
270             /* we have to unbind the nodelist, so free object can
271             not kill it */
272 84           rv = res->nodesetval;
273 84           res->nodesetval = 0 ;
274             }
275              
276 92           xmlXPathFreeObject(res);
277              
278 92           return rv;
279             }
280              
281             /* this function is not actually used: */
282             xmlNodeSetPtr
283 3           domXPathCompSelect( xmlNodePtr refNode, xmlXPathCompExprPtr comp ) {
284 3           xmlNodeSetPtr rv = NULL;
285 3           xmlXPathObjectPtr res = NULL;
286              
287 3           res = domXPathCompFind( refNode, comp, 0 );
288              
289 3 50         if (res != NULL) {
290             /* here we have to transfer the result from the internal
291             structure to the return value */
292             /* get the result from the query */
293             /* we have to unbind the nodelist, so free object can
294             not kill it */
295 3           rv = res->nodesetval;
296 3           res->nodesetval = 0 ;
297             }
298              
299 3           xmlXPathFreeObject(res);
300              
301 3           return rv;
302             }
303              
304             /**
305             * Most of the code is stolen from testXPath.
306             * The almost only thing I added, is the storeing of the data, so
307             * we can access the data easily - or say more easiely than through
308             * libxml2.
309             **/
310              
311             xmlXPathObjectPtr
312 122           domXPathFindCtxt( xmlXPathContextPtr ctxt, xmlChar * path, int to_bool ) {
313 122           xmlXPathObjectPtr res = NULL;
314 122 50         if ( ctxt->node != NULL && path != NULL ) {
    50          
315             xmlXPathCompExprPtr comp;
316 122           comp = xmlXPathCompile( path );
317 122 50         if ( comp == NULL ) {
318 0           return NULL;
319             }
320 122           res = domXPathCompFindCtxt(ctxt,comp,to_bool);
321 121           xmlXPathFreeCompExpr(comp);
322             }
323 121           return res;
324             }
325              
326             xmlXPathObjectPtr
327 129           domXPathCompFindCtxt( xmlXPathContextPtr ctxt, xmlXPathCompExprPtr comp, int to_bool ) {
328 129           xmlXPathObjectPtr res = NULL;
329 129 50         if ( ctxt != NULL && ctxt->node != NULL && comp != NULL ) {
    50          
    50          
330 129           xmlDocPtr tdoc = NULL;
331 129           xmlNodePtr froot = ctxt->node;
332              
333 129 100         if ( ctxt->node->doc == NULL ) {
334             /* if one XPaths a node from a fragment, libxml2 will
335             refuse the lookup. this is not very useful for XML
336             scripters. thus we need to create a temporary document
337             to make libxml2 do it's job correctly.
338             */
339              
340 3           tdoc = xmlNewDoc( NULL );
341              
342             /* find refnode's root node */
343 4 50         while ( froot != NULL ) {
344 4 100         if ( froot->parent == NULL ) {
345 3           break;
346             }
347 1           froot = froot->parent;
348             }
349 3           xmlAddChild((xmlNodePtr)tdoc, froot);
350 3           xmlSetTreeDoc(froot,tdoc); /* probably no need to clean psvi */
351 3           froot->doc = tdoc;
352             /* ctxt->node->doc = tdoc; */
353             }
354 129 100         if (to_bool) {
355             #if LIBXML_VERSION >= 20627
356 3           int val = xmlXPathCompiledEvalToBoolean(comp, ctxt);
357 3           res = xmlXPathNewBoolean(val);
358             #else
359             res = xmlXPathCompiledEval(comp, ctxt);
360             if (res!=NULL) {
361             int val = xmlXPathCastToBoolean(res);
362             xmlXPathFreeObject(res);
363             res = xmlXPathNewBoolean(val);
364             }
365             #endif
366             } else {
367 126           res = xmlXPathCompiledEval(comp, ctxt);
368             }
369 128 100         if ( tdoc != NULL ) {
370             /* after looking through a fragment, we need to drop the
371             fake document again */
372 3           xmlSetTreeDoc(froot,NULL); /* probably no need to clean psvi */
373 3           froot->doc = NULL;
374 3           froot->parent = NULL;
375 3           tdoc->children = NULL;
376 3           tdoc->last = NULL;
377 3 50         if (ctxt->node) {
378 3           ctxt->node->doc = NULL;
379             }
380 3           xmlFreeDoc( tdoc );
381             }
382             }
383 128           return res;
384             }
385              
386             xmlNodeSetPtr
387 0           domXPathSelectCtxt( xmlXPathContextPtr ctxt, xmlChar * path ) {
388 0           xmlNodeSetPtr rv = NULL;
389 0           xmlXPathObjectPtr res = NULL;
390              
391 0           res = domXPathFindCtxt( ctxt, path, 0 );
392              
393 0 0         if (res != NULL) {
394             /* here we have to transfer the result from the internal
395             structure to the return value */
396             /* get the result from the query */
397             /* we have to unbind the nodelist, so free object can
398             not kill it */
399 0           rv = res->nodesetval;
400 0           res->nodesetval = 0 ;
401             }
402              
403 0           xmlXPathFreeObject(res);
404              
405 0           return rv;
406             }