1 /* xmlj_xpath.c -
2    Copyright (C) 2004 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 #include "gnu_xml_libxmlj_dom_GnomeDocument.h"
39 #include "gnu_xml_libxmlj_dom_GnomeElement.h"
40 #include "gnu_xml_libxmlj_dom_GnomeXPathExpression.h"
41 #include "gnu_xml_libxmlj_dom_GnomeXPathNodeList.h"
42 #include "gnu_xml_libxmlj_dom_GnomeXPathResult.h"
43 #include "xmlj_node.h"
44 #include "xmlj_util.h"
45 #include <libxml/xpath.h>
46 
47 /* Local function prototypes */
48 
49 xmlXPathContextPtr
50 xmljCreateXPathContextPtr (xmlNodePtr node);
51 
52 jobject
53 xmljGetXPathResult (JNIEnv *env, xmlXPathObjectPtr obj);
54 
55 jobject
56 xmljGetXPathNodeList (JNIEnv *env, xmlXPathObjectPtr obj);
57 
58 xmlXPathObjectPtr
59 xmljGetXPathObjectID (JNIEnv *env, jobject obj);
60 
61 /**
62  * Creates an XPath context for the given node.
63  */
64 xmlXPathContextPtr
xmljCreateXPathContextPtr(xmlNodePtr node)65 xmljCreateXPathContextPtr (xmlNodePtr node)
66 {
67   xmlXPathContextPtr ctx;
68 
69   ctx = xmlXPathNewContext (node->doc);
70   ctx->node = node;
71   return ctx;
72 }
73 
74 /**
75  * Converts an xmlXPathObjectPtr to a Java XPathResult.
76  */
77 jobject
xmljGetXPathResult(JNIEnv * env,xmlXPathObjectPtr obj)78 xmljGetXPathResult (JNIEnv *env, xmlXPathObjectPtr obj)
79 {
80   jclass cls;
81   jmethodID method;
82   jobject ret;
83   jobject val;
84 
85   if (obj == NULL)
86     {
87       return NULL;
88     }
89   cls = (*env)->FindClass (env, "gnu/xml/libxmlj/dom/GnomeXPathResult");
90   if (cls == NULL)
91     {
92       return NULL;
93     }
94   method = (*env)->GetMethodID (env, cls, "<init>", "(Ljava/lang/Object;)V");
95   if (method == NULL)
96     {
97       return NULL;
98     }
99   val = xmljAsField (env, obj);
100   ret = (*env)->NewObject (env, cls, method, val);
101 
102   return ret;
103 }
104 
105 /**
106  * Converts an xmlXPathObjectPtr to a Java XPathNodeList.
107  */
108 jobject
xmljGetXPathNodeList(JNIEnv * env,xmlXPathObjectPtr obj)109 xmljGetXPathNodeList (JNIEnv *env, xmlXPathObjectPtr obj)
110 {
111   jclass cls;
112   jmethodID method;
113   jobject ret;
114   jobject val;
115 
116   if (obj == NULL)
117     {
118       return NULL;
119     }
120   cls = (*env)->FindClass (env, "gnu/xml/libxmlj/dom/GnomeXPathNodeList");
121   if (cls == NULL)
122     {
123       return NULL;
124     }
125   method = (*env)->GetMethodID (env, cls, "<init>", "(Ljava/lang/Object;)V");
126   if (method == NULL)
127     {
128       return NULL;
129     }
130   val = xmljAsField (env, obj);
131   ret = (*env)->NewObject (env, cls, method, val);
132 
133   return ret;
134 }
135 
136 xmlXPathObjectPtr
xmljGetXPathObjectID(JNIEnv * env,jobject obj)137 xmljGetXPathObjectID (JNIEnv *env, jobject obj)
138 {
139   jclass cls;
140   jfieldID field;
141   jobject val;
142   xmlXPathObjectPtr ret;
143 
144   cls = (*env)->GetObjectClass (env, obj);
145   if (cls == NULL)
146     {
147       return NULL;
148     }
149   field = (*env)->GetFieldID (env, cls, "obj", "Ljava/lang/Object;");
150   if (field == NULL)
151     {
152       return NULL;
153     }
154   val = (*env)->GetObjectField (env, obj, field);
155   ret = (xmlXPathObjectPtr) xmljAsPointer (env, val);
156 
157   return ret;
158 }
159 
160 JNIEXPORT jobject JNICALL
Java_gnu_xml_libxmlj_dom_GnomeDocument_evaluate(JNIEnv * env,jobject self,jstring expression,jobject contextNode,jobject resolver,jshort type,jobject result)161 Java_gnu_xml_libxmlj_dom_GnomeDocument_evaluate (JNIEnv *env,
162                                                  jobject self
163 						 __attribute__((__unused__)),
164                                                  jstring expression,
165                                                  jobject contextNode,
166                                                  jobject resolver,
167                                                  jshort type,
168                                                  jobject result)
169 {
170   const xmlChar *str;
171   xmlNodePtr node;
172   xmlXPathContextPtr ctx;
173   xmlXPathObjectPtr eval = NULL;
174 
175   str = xmljGetStringChars (env, expression);
176   node = xmljGetNodeID (env, contextNode);
177   if (node == NULL)
178     {
179       return NULL;
180     }
181   ctx = xmljCreateXPathContextPtr (node);
182   if (ctx != NULL)
183     {
184       eval = xmlXPathEval (str, ctx);
185       xmlXPathFreeContext (ctx);
186     }
187   xmlFree ((xmlChar *) str);
188   return xmljGetXPathResult (env, eval);
189 }
190 
191 JNIEXPORT jobject JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathExpression_init(JNIEnv * env,jobject self,jstring expression)192 Java_gnu_xml_libxmlj_dom_GnomeXPathExpression_init (JNIEnv *env,
193                                                     jobject self
194 						    __attribute__((__unused__)),
195                                                     jstring expression)
196 {
197   const xmlChar *str;
198   xmlXPathCompExprPtr ptr;
199 
200   str = xmljGetStringChars (env, expression);
201   ptr = xmlXPathCompile (str);
202   xmlFree ((xmlChar *) str);
203   return xmljAsField (env, ptr);
204 }
205 
206 JNIEXPORT void JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathExpression_free(JNIEnv * env,jobject self,jobject ptr)207 Java_gnu_xml_libxmlj_dom_GnomeXPathExpression_free (JNIEnv *env,
208                                                     jobject self
209 						    __attribute__((__unused__)),
210                                                     jobject ptr)
211 {
212   xmlXPathCompExprPtr expr;
213 
214   expr = (xmlXPathCompExprPtr) xmljAsPointer (env, ptr);
215   xmlXPathFreeCompExpr (expr);
216 }
217 
218 JNIEXPORT jobject JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathExpression_doEvaluate(JNIEnv * env,jobject self,jobject ptr,jobject contextNode,jshort type,jobject result)219 Java_gnu_xml_libxmlj_dom_GnomeXPathExpression_doEvaluate (JNIEnv *env,
220                                                           jobject self
221 							  __attribute__((__unused__)),
222                                                           jobject ptr,
223                                                           jobject contextNode,
224                                                           jshort type,
225                                                           jobject result)
226 {
227   xmlXPathCompExprPtr expr;
228   xmlNodePtr node;
229   xmlXPathContextPtr ctx;
230   xmlXPathObjectPtr eval = NULL;
231 
232   expr = (xmlXPathCompExprPtr) xmljAsPointer (env, ptr);
233   node = xmljGetNodeID (env, contextNode);
234   if (node == NULL)
235     {
236       return NULL;
237     }
238   ctx = xmljCreateXPathContextPtr (node);
239   if (ctx != NULL)
240     {
241       eval = xmlXPathCompiledEval (expr, ctx);
242       xmlXPathFreeContext (ctx);
243     }
244   return xmljGetXPathResult (env, eval);
245 }
246 
247 JNIEXPORT void JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathResult_free(JNIEnv * env,jobject self,jobject obj)248 Java_gnu_xml_libxmlj_dom_GnomeXPathResult_free (JNIEnv *env,
249                                                 jobject self
250 						__attribute__((__unused__)),
251                                                 jobject obj)
252 {
253   xmlXPathFreeObject ((xmlXPathObjectPtr) xmljAsPointer (env, obj));
254 }
255 
256 JNIEXPORT jshort JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getResultType(JNIEnv * env,jobject self)257 Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getResultType (JNIEnv *env,
258                                                          jobject self)
259 {
260   xmlXPathObjectPtr obj;
261 
262   obj = xmljGetXPathObjectID (env, self);
263   switch (obj->type)
264     {
265     case XPATH_UNDEFINED:
266       return 0; /* ANY_TYPE */
267     case XPATH_NUMBER:
268       return 1; /* NUMBER_TYPE */
269     case XPATH_STRING:
270       return 2; /* STRING_TYPE */
271     case XPATH_BOOLEAN:
272       return 3; /* BOOLEAN_TYPE */
273     case XPATH_NODESET:
274       return 6; /* UNORDERED_NODE_SNAPSHOT_TYPE */
275     case XPATH_POINT:
276     case XPATH_RANGE:
277     case XPATH_LOCATIONSET:
278     case XPATH_USERS:
279     case XPATH_XSLT_TREE:
280       /* TODO */
281     default:
282       return -1; /* TODO */
283     }
284 }
285 
286 JNIEXPORT jdouble JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getNumberValue(JNIEnv * env,jobject self)287 Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getNumberValue (JNIEnv *env,
288                                                           jobject self)
289 {
290   xmlXPathObjectPtr obj;
291 
292   obj = xmljGetXPathObjectID (env, self);
293   if (obj == NULL)
294     {
295       return 0.0;
296     }
297   return obj->floatval;
298 }
299 
300 JNIEXPORT jstring JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getStringValue(JNIEnv * env,jobject self)301 Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getStringValue (JNIEnv *env,
302                                                           jobject self)
303 {
304   xmlXPathObjectPtr obj;
305 
306   obj = xmljGetXPathObjectID (env, self);
307   if (obj == NULL)
308     {
309       return NULL;
310     }
311   return xmljNewString (env, obj->stringval);
312 }
313 
314 JNIEXPORT jboolean JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getBooleanValue(JNIEnv * env,jobject self)315 Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getBooleanValue (JNIEnv *env,
316                                                            jobject self)
317 {
318   xmlXPathObjectPtr obj;
319 
320   obj = xmljGetXPathObjectID (env, self);
321   return obj->boolval;
322 }
323 
324 JNIEXPORT jobject JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getSingleNodeValue(JNIEnv * env,jobject self)325 Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getSingleNodeValue (JNIEnv *env,
326                                                               jobject self)
327 {
328   xmlXPathObjectPtr obj;
329 
330   obj = xmljGetXPathObjectID (env, self);
331   if (obj == NULL)
332     {
333       return NULL;
334     }
335   if (obj->nodesetval == NULL)
336     {
337       return NULL;
338     }
339   if (obj->nodesetval->nodeNr > 0)
340     {
341       return xmljGetNodeInstance (env, obj->nodesetval->nodeTab[0]);
342     }
343   else
344     {
345       return NULL;
346     }
347 }
348 
349 JNIEXPORT jboolean JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getInvalidIteratorState(JNIEnv * env,jobject self)350 Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getInvalidIteratorState (JNIEnv *env,
351                                                                    jobject self)
352 {
353   xmlXPathObjectPtr obj;
354 
355   obj = xmljGetXPathObjectID (env, self);
356   return 0; /* TODO */
357 }
358 
359 JNIEXPORT jint JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getSnapshotLength(JNIEnv * env,jobject self)360 Java_gnu_xml_libxmlj_dom_GnomeXPathResult_getSnapshotLength (JNIEnv *env,
361                                                              jobject self)
362 {
363   xmlXPathObjectPtr obj;
364 
365   obj = xmljGetXPathObjectID (env, self);
366   if (obj == NULL)
367     {
368       return -1;
369     }
370   if (obj->nodesetval == NULL)
371     {
372       return -1;
373     }
374   return obj->nodesetval->nodeNr;
375 }
376 
377 JNIEXPORT jobject JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathResult_iterateNext(JNIEnv * env,jobject self)378 Java_gnu_xml_libxmlj_dom_GnomeXPathResult_iterateNext (JNIEnv *env,
379                                                        jobject self)
380 {
381   xmlXPathObjectPtr obj;
382 
383   obj = xmljGetXPathObjectID (env, self);
384   return NULL; /* TODO */
385 }
386 
387 JNIEXPORT jobject JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathResult_snapshotItem(JNIEnv * env,jobject self,jint index)388 Java_gnu_xml_libxmlj_dom_GnomeXPathResult_snapshotItem (JNIEnv *env,
389                                                         jobject self,
390                                                         jint index)
391 {
392   xmlXPathObjectPtr obj;
393 
394   obj = xmljGetXPathObjectID (env, self);
395   if (obj == NULL)
396     {
397       return NULL;
398     }
399   if (obj->nodesetval == NULL)
400     {
401       return NULL;
402     }
403   if (obj->nodesetval->nodeNr > 0)
404     {
405       return xmljGetNodeInstance (env, obj->nodesetval->nodeTab[index]);
406     }
407   else
408     {
409       return NULL;
410     }
411 }
412 
413 /* -- GnomeXPathNodeList -- */
414 
415 JNIEXPORT jobject JNICALL
Java_gnu_xml_libxmlj_dom_GnomeDocument_getElementsByTagName(JNIEnv * env,jobject self,jstring name)416 Java_gnu_xml_libxmlj_dom_GnomeDocument_getElementsByTagName (JNIEnv *env,
417                                                              jobject self,
418                                                              jstring name)
419 {
420   return Java_gnu_xml_libxmlj_dom_GnomeElement_getElementsByTagName (env,
421                                                                      self,
422                                                                      name);
423 }
424 
425 JNIEXPORT jobject JNICALL
Java_gnu_xml_libxmlj_dom_GnomeElement_getElementsByTagName(JNIEnv * env,jobject self,jstring name)426 Java_gnu_xml_libxmlj_dom_GnomeElement_getElementsByTagName (JNIEnv *env,
427                                                              jobject self,
428                                                              jstring name)
429 {
430   const xmlChar *s_name;
431   const xmlChar *format;
432   xmlChar expr[256];
433   xmlNodePtr node;
434   xmlXPathContextPtr ctx;
435   xmlXPathObjectPtr eval = NULL;
436 
437   node = xmljGetNodeID (env, self);
438   if (node == NULL)
439     {
440       return NULL;
441     }
442   s_name = xmljGetStringChars (env, name);
443   if (xmlStrEqual (s_name, BAD_CAST "*"))
444     {
445       format = xmlCharStrdup ("descendant-or-self::*[node-type()=1]");
446       if (xmlStrPrintf (expr, 256, format) == -1)
447         {
448           return NULL;
449         }
450     }
451   else
452     {
453       format = xmlCharStrdup ("descendant-or-self::*[name()='%s']");
454       if (xmlStrPrintf (expr, 256, format, s_name) == -1)
455         {
456           return NULL;
457         }
458     }
459   xmlFree ((xmlChar *) s_name);
460   ctx = xmljCreateXPathContextPtr (node);
461   if (ctx != NULL)
462     {
463       eval = xmlXPathEval (expr, ctx);
464       xmlXPathFreeContext (ctx);
465     }
466   return xmljGetXPathNodeList (env, eval);
467 }
468 
469 JNIEXPORT jobject JNICALL
Java_gnu_xml_libxmlj_dom_GnomeDocument_getElementsByTagNameNS(JNIEnv * env,jobject self,jstring uri,jstring localName)470 Java_gnu_xml_libxmlj_dom_GnomeDocument_getElementsByTagNameNS (JNIEnv *env,
471                                                                jobject self,
472                                                                jstring uri,
473                                                                jstring localName)
474 {
475   return Java_gnu_xml_libxmlj_dom_GnomeElement_getElementsByTagNameNS (env,
476                                                                        self,
477                                                                        uri,
478                                                                        localName);
479 }
480 
481 JNIEXPORT jobject JNICALL
Java_gnu_xml_libxmlj_dom_GnomeElement_getElementsByTagNameNS(JNIEnv * env,jobject self,jstring uri,jstring localName)482 Java_gnu_xml_libxmlj_dom_GnomeElement_getElementsByTagNameNS (JNIEnv *env,
483                                                                jobject self,
484                                                                jstring uri,
485                                                                jstring localName)
486 {
487   const xmlChar *s_uri;
488   const xmlChar *s_localName;
489   const xmlChar *format;
490   xmlChar expr[256];
491   xmlNodePtr node;
492   xmlXPathContextPtr ctx;
493   xmlXPathObjectPtr eval = NULL;
494 
495   node = xmljGetNodeID (env, self);
496   if (node == NULL)
497     {
498       return NULL;
499     }
500   s_uri = xmljGetStringChars (env, uri);
501   s_localName = xmljGetStringChars (env, localName);
502   if (uri == NULL)
503     {
504       /* namespace URI is empty */
505       if (xmlStrEqual (s_localName, BAD_CAST "*"))
506         {
507           format = xmlCharStrdup ("descendant-or-self::*[namespace-uri()='' and node-type()=1]");
508           if (xmlStrPrintf (expr, 256, format) == -1)
509             {
510               return NULL;
511             }
512         }
513       else
514         {
515           format = xmlCharStrdup ("descendant-or-self::*[namespace-uri()='' and local-name()='%s']");
516           if (xmlStrPrintf (expr, 256, format, s_localName) == -1)
517             {
518               return NULL;
519             }
520         }
521     }
522   else if (xmlStrEqual (s_uri, BAD_CAST "*"))
523     {
524       /* matches all namespaces */
525       if (xmlStrEqual (s_localName, BAD_CAST "*"))
526         {
527           format = xmlCharStrdup ("descendant-or-self::*[node-type()=1]");
528           if (xmlStrPrintf (expr, 256, format) == -1)
529             {
530               return NULL;
531             }
532         }
533       else
534         {
535           format = xmlCharStrdup ("descendant-or-self::*[local-name()='%s']");
536           if (xmlStrPrintf (expr, 256, format, s_localName) == -1)
537             {
538               return NULL;
539             }
540         }
541     }
542   else
543     {
544       if (xmlStrEqual (s_localName, BAD_CAST "*"))
545         {
546           format = xmlCharStrdup ("descendant-or-self::*[namespace-uri()='%s' and node-type()=1]");
547           if (xmlStrPrintf (expr, 256, format, s_uri) == -1)
548             {
549               return NULL;
550             }
551         }
552       else
553         {
554           format = xmlCharStrdup ("descendant-or-self::*[namespace-uri()='%s' and local-name()='%s']");
555           if (xmlStrPrintf (expr, 256, format, s_uri, s_localName) == -1)
556             {
557               return NULL;
558             }
559         }
560     }
561   xmlFree ((xmlChar *) s_uri);
562   xmlFree ((xmlChar *) s_localName);
563   ctx = xmljCreateXPathContextPtr (node);
564   if (ctx != NULL)
565     {
566       eval = xmlXPathEval (expr, ctx);
567       xmlXPathFreeContext (ctx);
568     }
569   return xmljGetXPathNodeList (env, eval);
570 }
571 
572 JNIEXPORT void JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathNodeList_free(JNIEnv * env,jobject self,jobject obj)573 Java_gnu_xml_libxmlj_dom_GnomeXPathNodeList_free (JNIEnv *env,
574                                                   jobject self
575 						  __attribute__((__unused__)),
576                                                   jobject obj)
577 {
578   xmlXPathFreeObject ((xmlXPathObjectPtr) xmljAsPointer (env, obj));
579 }
580 
581 JNIEXPORT jint JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathNodeList_getLength(JNIEnv * env,jobject self)582 Java_gnu_xml_libxmlj_dom_GnomeXPathNodeList_getLength (JNIEnv *env,
583                                                        jobject self)
584 {
585   xmlXPathObjectPtr obj;
586 
587   obj = xmljGetXPathObjectID (env, self);
588   if (obj == NULL)
589     {
590       return 0;
591     }
592   if (obj->nodesetval == NULL)
593     {
594       return 0;
595     }
596   return obj->nodesetval->nodeNr;
597 }
598 
599 JNIEXPORT jobject JNICALL
Java_gnu_xml_libxmlj_dom_GnomeXPathNodeList_item(JNIEnv * env,jobject self,jint index)600 Java_gnu_xml_libxmlj_dom_GnomeXPathNodeList_item (JNIEnv *env,
601                                                   jobject self,
602                                                   jint index)
603 {
604   xmlXPathObjectPtr obj;
605 
606   obj = xmljGetXPathObjectID (env, self);
607   if (obj == NULL)
608     {
609       return NULL;
610     }
611   if (obj->nodesetval == NULL)
612     {
613       return NULL;
614     }
615   if (obj->nodesetval->nodeNr > 0)
616     {
617       return xmljGetNodeInstance (env, obj->nodesetval->nodeTab[index]);
618     }
619   else
620     {
621       return NULL;
622     }
623 }
624 
625