ruby-xpath 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +1 -0
- data/COPYING +340 -0
- data/ChangeLog +12 -0
- data/README +41 -0
- data/ext/xpath/extconf.h +4 -0
- data/ext/xpath/extconf.rb +51 -0
- data/ext/xpath/rb_utils.c +30 -0
- data/ext/xpath/rb_utils.h +34 -0
- data/ext/xpath/xpath.c +535 -0
- data/ext/xpath/xpath.h +56 -0
- data/setup.rb +1585 -0
- metadata +63 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (C) 2005 Gregoire Lejeune <gregoire.lejeune@free.fr>
|
3
|
+
*
|
4
|
+
* This program is free software; you can redistribute it and/or modify
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
6
|
+
* the Free Software Foundation; either version 2 of the License, or
|
7
|
+
* (at your option) any later version.
|
8
|
+
*
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
* GNU General Public License for more details.
|
13
|
+
*
|
14
|
+
* You should have received a copy of the GNU General Public License
|
15
|
+
* along with this program; if not, write to the Free Software
|
16
|
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
*/
|
18
|
+
#include "rb_utils.h"
|
19
|
+
|
20
|
+
char * getRubyObjectName( VALUE rb_Object ) {
|
21
|
+
VALUE klass = rb_funcall( rb_Object, rb_intern( "class" ), 0 );
|
22
|
+
return( STR2CSTR( rb_funcall( klass, rb_intern( "to_s" ), 0 ) ) );
|
23
|
+
}
|
24
|
+
|
25
|
+
int isFile( const char *filename ) {
|
26
|
+
struct stat stbuf;
|
27
|
+
|
28
|
+
if (stat(filename, &stbuf)) return 0;
|
29
|
+
return ((stbuf.st_mode & S_IFMT) == S_IFREG) ? 1 : 0;
|
30
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (C) 2005 Gregoire Lejeune <gregoire.lejeune@free.fr>
|
3
|
+
*
|
4
|
+
* This program is free software; you can redistribute it and/or modify
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
6
|
+
* the Free Software Foundation; either version 2 of the License, or
|
7
|
+
* (at your option) any later version.
|
8
|
+
*
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
* GNU General Public License for more details.
|
13
|
+
*
|
14
|
+
* You should have received a copy of the GNU General Public License
|
15
|
+
* along with this program; if not, write to the Free Software
|
16
|
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
*/
|
18
|
+
|
19
|
+
/* Please see the LICENSE file for copyright and distribution information */
|
20
|
+
|
21
|
+
#ifndef __RUBY_RB_UTILS_H__
|
22
|
+
#define __RUBY_RB_UTILS_H__
|
23
|
+
|
24
|
+
#include <ruby.h>
|
25
|
+
#include <rubyio.h>
|
26
|
+
|
27
|
+
#include <stdio.h>
|
28
|
+
#include <string.h>
|
29
|
+
#include <sys/stat.h>
|
30
|
+
|
31
|
+
char * getRubyObjectName( VALUE );
|
32
|
+
int isFile( const char *filename );
|
33
|
+
|
34
|
+
#endif
|
data/ext/xpath/xpath.c
ADDED
@@ -0,0 +1,535 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright (C) 2004, 2005 Gregoire Lejeune <gregoire.lejeune@free.fr>
|
3
|
+
*
|
4
|
+
* This program is free software; you can redistribute it and/or modify
|
5
|
+
* it under the terms of the GNU General Public License as published by
|
6
|
+
* the Free Software Foundation; either version 2 of the License, or
|
7
|
+
* (at your option) any later version.
|
8
|
+
*
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
* GNU General Public License for more details.
|
13
|
+
*
|
14
|
+
* You should have received a copy of the GNU General Public License
|
15
|
+
* along with this program; if not, write to the Free Software
|
16
|
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
|
+
*/
|
18
|
+
|
19
|
+
#include "xpath.h"
|
20
|
+
|
21
|
+
static VALUE each_pair( VALUE obj ) {
|
22
|
+
return rb_funcall( obj, rb_intern("each"), 0, 0 );
|
23
|
+
}
|
24
|
+
|
25
|
+
static VALUE process_pair( VALUE pair, VALUE rbparams ) {
|
26
|
+
VALUE key, value;
|
27
|
+
static int count = 0;
|
28
|
+
|
29
|
+
Check_Type(pair, T_ARRAY);
|
30
|
+
|
31
|
+
key = RARRAY(pair)->ptr[0];
|
32
|
+
value = RARRAY(pair)->ptr[1];
|
33
|
+
|
34
|
+
Check_Type(key, T_STRING);
|
35
|
+
Check_Type(value, T_STRING);
|
36
|
+
|
37
|
+
rb_ary_store( rbparams, count, key );
|
38
|
+
rb_ary_store( rbparams, count + 1, value );
|
39
|
+
|
40
|
+
count += 2;
|
41
|
+
return Qnil;
|
42
|
+
}
|
43
|
+
|
44
|
+
/* ------------------------------------------------------------------------------- */
|
45
|
+
|
46
|
+
/**
|
47
|
+
* register_namespaces:
|
48
|
+
* @xpathCtx: the pointer to an XPath context.
|
49
|
+
* @nsList: the list of known namespaces in
|
50
|
+
* {<prefix1>=><href1>, <prefix2>=>href2>, ...} format.
|
51
|
+
*
|
52
|
+
* Registers namespaces from @nsList in @xpathCtx.
|
53
|
+
*
|
54
|
+
* Returns 0 on success and a negative value otherwise.
|
55
|
+
*/
|
56
|
+
int register_namespaces( xmlXPathContextPtr xpathCtx, VALUE nsList ) {
|
57
|
+
xmlChar* prefix;
|
58
|
+
xmlChar* href;
|
59
|
+
int iNbNs;
|
60
|
+
int iCpt;
|
61
|
+
|
62
|
+
VALUE lxNS = rb_ary_new( );
|
63
|
+
(void)rb_iterate( each_pair, nsList, process_pair, lxNS );
|
64
|
+
iNbNs = FIX2INT( rb_funcall( nsList, rb_intern("size"), 0, 0 ) );
|
65
|
+
|
66
|
+
for( iCpt = 0; iCpt <= iNbNs; iCpt += 2 ) {
|
67
|
+
prefix = (xmlChar*)STR2CSTR( rb_ary_entry( lxNS, iCpt ) );
|
68
|
+
href = (xmlChar*)STR2CSTR( rb_ary_entry( lxNS, iCpt+1 ) );
|
69
|
+
|
70
|
+
if( xmlXPathRegisterNs( xpathCtx, prefix, href ) != 0 ) {
|
71
|
+
return( -1 );
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
return( 0 );
|
76
|
+
}
|
77
|
+
|
78
|
+
int get_xpath_nodes( xmlNodeSetPtr nodes, RbTxpath *pRbTxpath ) {
|
79
|
+
int RCod;
|
80
|
+
int iCpt;
|
81
|
+
int jCpt;
|
82
|
+
struct _xmlAttr *attr;
|
83
|
+
VALUE rbNode;
|
84
|
+
VALUE rbListAttr;
|
85
|
+
|
86
|
+
pRbTxpath->rbResult = rb_ary_new( );
|
87
|
+
|
88
|
+
RCod = pRbTxpath->iNbNodes = (nodes) ? nodes->nodeNr : 0;
|
89
|
+
pRbTxpath->iCurrentNode = 0;
|
90
|
+
|
91
|
+
for( iCpt = 0; iCpt < RCod; iCpt++ ) {
|
92
|
+
rbNode = rb_hash_new( );
|
93
|
+
|
94
|
+
rb_hash_aset( rbNode, rb_str_new2( "type" ), INT2NUM( (int)nodes->nodeTab[iCpt]->type ) );
|
95
|
+
rb_hash_aset( rbNode, rb_str_new2( "path" ), rb_str_new2( (char*)xmlGetNodePath(nodes->nodeTab[iCpt]) ) );
|
96
|
+
rb_hash_aset( rbNode, rb_str_new2( "name" ), rb_str_new2( (char*)nodes->nodeTab[iCpt]->name ) );
|
97
|
+
|
98
|
+
if( nodes->nodeTab[iCpt]->ns != NULL ) {
|
99
|
+
rb_hash_aset( rbNode, rb_str_new2( "NS href" ), rb_str_new2( (char*)nodes->nodeTab[iCpt]->ns->href ) );
|
100
|
+
rb_hash_aset( rbNode, rb_str_new2( "NS prefix" ), rb_str_new2( (char*)nodes->nodeTab[iCpt]->ns->prefix ) );
|
101
|
+
}
|
102
|
+
|
103
|
+
switch( nodes->nodeTab[iCpt]->type ) {
|
104
|
+
case XML_ELEMENT_NODE:
|
105
|
+
rbListAttr = rb_hash_new( );
|
106
|
+
|
107
|
+
jCpt = 0;
|
108
|
+
if( nodes->nodeTab[iCpt]->children != NULL && nodes->nodeTab[iCpt]->children->content != NULL ) {
|
109
|
+
rb_hash_aset( rbNode, rb_str_new2( "content" ), rb_str_new2( (char*)nodes->nodeTab[iCpt]->children->content ) );
|
110
|
+
}
|
111
|
+
|
112
|
+
attr = nodes->nodeTab[iCpt]->properties;
|
113
|
+
while( attr != NULL ) {
|
114
|
+
rb_hash_aset( rbListAttr, rb_str_new2( (char*)attr->name ), rb_str_new2( (char*)attr->children->content ) );
|
115
|
+
|
116
|
+
jCpt++;
|
117
|
+
attr = attr->next;
|
118
|
+
}
|
119
|
+
|
120
|
+
if( jCpt > 0 ) {
|
121
|
+
rb_hash_aset( rbNode, rb_str_new2( "attrs" ), rbListAttr );
|
122
|
+
}
|
123
|
+
break;
|
124
|
+
|
125
|
+
case XML_ATTRIBUTE_NODE:
|
126
|
+
if( nodes->nodeTab[iCpt]->children != NULL ) {
|
127
|
+
rb_hash_aset( rbNode, rb_str_new2( "content" ), rb_str_new2( (char*)nodes->nodeTab[iCpt]->children->content ) );
|
128
|
+
}
|
129
|
+
break;
|
130
|
+
|
131
|
+
default:
|
132
|
+
break;
|
133
|
+
}
|
134
|
+
|
135
|
+
rb_ary_push( pRbTxpath->rbResult, rbNode );
|
136
|
+
}
|
137
|
+
|
138
|
+
return( RCod );
|
139
|
+
}
|
140
|
+
|
141
|
+
/**
|
142
|
+
* execute_xpath_expression:
|
143
|
+
*
|
144
|
+
* Parses input XML file, evaluates XPath expression and return results.
|
145
|
+
*
|
146
|
+
* Returns 0 on success and a negative value otherwise.
|
147
|
+
*/
|
148
|
+
int parse( const char* xml, int iXmlType, const xmlChar* xpathExpr, RbTxpath *pRbTxpath ) {
|
149
|
+
xmlErrorPtr ptXMLError;
|
150
|
+
xmlDocPtr doc = NULL;
|
151
|
+
xmlXPathContextPtr xpathCtx;
|
152
|
+
xmlXPathObjectPtr xpathObj;
|
153
|
+
int RCod = -1;
|
154
|
+
|
155
|
+
/* Init libxml */
|
156
|
+
xmlInitParser();
|
157
|
+
LIBXML_TEST_VERSION
|
158
|
+
|
159
|
+
/** Act: Parse XML */
|
160
|
+
xmlResetLastError( );
|
161
|
+
ptXMLError = NULL;
|
162
|
+
if( iXmlType == RUBY_XPATH_XMLSRC_TYPE_STR ) {
|
163
|
+
doc = xmlParseMemory( xml, strlen( xml ) );
|
164
|
+
} else if( iXmlType == RUBY_XPATH_XMLSRC_TYPE_FILE ) {
|
165
|
+
doc = xmlParseFile( xml );
|
166
|
+
}
|
167
|
+
|
168
|
+
ptXMLError = xmlGetLastError();
|
169
|
+
if( doc == NULL || ptXMLError != NULL ) {
|
170
|
+
rb_fatal( "XML::XPATH: XML parsing error : %s\n", ptXMLError->message );
|
171
|
+
return( RCod );
|
172
|
+
}
|
173
|
+
|
174
|
+
/* Create xpath evaluation context */
|
175
|
+
xpathCtx = xmlXPathNewContext(doc);
|
176
|
+
if(xpathCtx == NULL) {
|
177
|
+
ptXMLError = xmlGetLastError();
|
178
|
+
rb_fatal( "Error: unable to create new XPath context : %s\n", ptXMLError->message);
|
179
|
+
xmlFreeDoc(doc);
|
180
|
+
return( RCod );
|
181
|
+
}
|
182
|
+
|
183
|
+
/* Register namespaces from list (if any) */
|
184
|
+
if( pRbTxpath->hxNS != Qnil ) {
|
185
|
+
if( register_namespaces(xpathCtx, pRbTxpath->hxNS) < 0 ) {
|
186
|
+
ptXMLError = xmlGetLastError();
|
187
|
+
rb_fatal( "Error: failed to register namespaces list : %s\n", ptXMLError->message );
|
188
|
+
xmlXPathFreeContext(xpathCtx);
|
189
|
+
xmlFreeDoc(doc);
|
190
|
+
return( RCod );
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
/* Evaluate xpath expression */
|
195
|
+
xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
|
196
|
+
if(xpathObj == NULL) {
|
197
|
+
ptXMLError = xmlGetLastError();
|
198
|
+
rb_fatal("Error: unable to evaluate xpath expression \"%s\" : %s\n", xpathExpr, ptXMLError->message );
|
199
|
+
xmlXPathFreeContext(xpathCtx);
|
200
|
+
xmlFreeDoc(doc);
|
201
|
+
return( RCod );
|
202
|
+
}
|
203
|
+
|
204
|
+
/* Print results */
|
205
|
+
RCod = get_xpath_nodes( xpathObj->nodesetval, pRbTxpath );
|
206
|
+
|
207
|
+
/* Cleanup */
|
208
|
+
xmlXPathFreeObject(xpathObj);
|
209
|
+
xmlXPathFreeContext(xpathCtx);
|
210
|
+
xmlFreeDoc(doc);
|
211
|
+
|
212
|
+
/* Shutdown libxml */
|
213
|
+
xmlCleanupParser();
|
214
|
+
|
215
|
+
/*
|
216
|
+
* this is to debug memory for regression tests
|
217
|
+
*/
|
218
|
+
xmlMemoryDump();
|
219
|
+
return( RCod );
|
220
|
+
}
|
221
|
+
|
222
|
+
VALUE get_node_element( VALUE self, const char *xField ) {
|
223
|
+
RbTxpath *pRbTxpath;
|
224
|
+
Data_Get_Struct( self, RbTxpath, pRbTxpath );
|
225
|
+
VALUE xValue = Qnil;
|
226
|
+
|
227
|
+
if( pRbTxpath->iNbNodes > 0 ) {
|
228
|
+
VALUE rbNode = rb_ary_entry( pRbTxpath->rbResult, pRbTxpath->iCurrentNode );
|
229
|
+
xValue = rb_hash_aref( rbNode, rb_str_new2( xField ) );
|
230
|
+
}
|
231
|
+
|
232
|
+
return( xValue );
|
233
|
+
}
|
234
|
+
|
235
|
+
/**
|
236
|
+
* vOut = object_to_string( VALUE object );
|
237
|
+
*/
|
238
|
+
VALUE object_to_string( VALUE object ) {
|
239
|
+
VALUE vOut = Qnil;
|
240
|
+
|
241
|
+
switch( TYPE( object ) ) {
|
242
|
+
case T_STRING:
|
243
|
+
{
|
244
|
+
if( isFile( STR2CSTR( object ) ) == 0 ) {
|
245
|
+
vOut = object;
|
246
|
+
} else {
|
247
|
+
long iBufferLength;
|
248
|
+
long iCpt;
|
249
|
+
char *xBuffer;
|
250
|
+
|
251
|
+
FILE* fStream = fopen( STR2CSTR( object ), "r" );
|
252
|
+
if( fStream == NULL ) {
|
253
|
+
return( Qnil );
|
254
|
+
}
|
255
|
+
|
256
|
+
fseek( fStream, 0L, 2 );
|
257
|
+
iBufferLength = ftell( fStream );
|
258
|
+
xBuffer = (char *)malloc( (int)iBufferLength + 1 );
|
259
|
+
if( !xBuffer )
|
260
|
+
rb_raise( rb_eNoMemError, "Memory allocation error" );
|
261
|
+
|
262
|
+
xBuffer[iBufferLength] = 0;
|
263
|
+
fseek( fStream, 0L, 0 );
|
264
|
+
iCpt = fread( xBuffer, 1, (int)iBufferLength, fStream );
|
265
|
+
|
266
|
+
if( iCpt != iBufferLength ) {
|
267
|
+
free( (char *)xBuffer );
|
268
|
+
rb_raise( rb_eSystemCallError, "Read file error" );
|
269
|
+
}
|
270
|
+
|
271
|
+
vOut = rb_str_new2( xBuffer );
|
272
|
+
|
273
|
+
fclose( fStream );
|
274
|
+
}
|
275
|
+
}
|
276
|
+
break;
|
277
|
+
|
278
|
+
case T_DATA:
|
279
|
+
case T_OBJECT:
|
280
|
+
{
|
281
|
+
if( strcmp( getRubyObjectName( object ), "XML::Simple::Dom" ) == 0 ) {
|
282
|
+
vOut = rb_funcall( object, rb_intern( "to_s" ), 0 );
|
283
|
+
} else {
|
284
|
+
rb_raise( rb_eSystemCallError, "Can't read XML from object %s", getRubyObjectName( object ) );
|
285
|
+
}
|
286
|
+
}
|
287
|
+
break;
|
288
|
+
|
289
|
+
default:
|
290
|
+
rb_raise( rb_eArgError, "XML object #0x%x not supported", TYPE( object ) );
|
291
|
+
}
|
292
|
+
|
293
|
+
return( vOut );
|
294
|
+
}
|
295
|
+
|
296
|
+
/* ------------------------------------------------------------------------------- */
|
297
|
+
|
298
|
+
/** xmlData = o.xml */
|
299
|
+
VALUE ruby_xpath_xml_str_get( VALUE self ) {
|
300
|
+
RbTxpath *pRbTxpath;
|
301
|
+
Data_Get_Struct( self, RbTxpath, pRbTxpath );
|
302
|
+
|
303
|
+
if( pRbTxpath->iXmlType == RUBY_XPATH_XMLSRC_TYPE_NULL )
|
304
|
+
return( Qnil );
|
305
|
+
else
|
306
|
+
return( (VALUE)pRbTxpath->xXmlData );
|
307
|
+
}
|
308
|
+
|
309
|
+
/** o.xml = "<...>" */
|
310
|
+
VALUE ruby_xpath_xml_str_set( VALUE self, VALUE xml_doc_str ) {
|
311
|
+
RbTxpath *pRbTxpath;
|
312
|
+
|
313
|
+
Data_Get_Struct( self, RbTxpath, pRbTxpath );
|
314
|
+
|
315
|
+
pRbTxpath->iXmlType = RUBY_XPATH_XMLSRC_TYPE_STR;
|
316
|
+
pRbTxpath->xXmlData = object_to_string( xml_doc_str );
|
317
|
+
|
318
|
+
return( xml_doc_str );
|
319
|
+
}
|
320
|
+
|
321
|
+
/** o.xmlfile="file.xml" */
|
322
|
+
VALUE ruby_xpath_xml_file_set( VALUE self, VALUE xml_doc_file ) {
|
323
|
+
rb_warn( "XML::XSLT#xmlfile=<file> is deprecated. Please use XML::XSLT#xml=<file> !" );
|
324
|
+
return( ruby_xpath_xml_str_set( self, xml_doc_file ) );
|
325
|
+
}
|
326
|
+
|
327
|
+
/** o.ns={ ... } */
|
328
|
+
VALUE ruby_xpath_xml_ns_set( VALUE self, VALUE ns_hash ) {
|
329
|
+
RbTxpath *pRbTxpath;
|
330
|
+
Check_Type( ns_hash, T_HASH );
|
331
|
+
|
332
|
+
Data_Get_Struct( self, RbTxpath, pRbTxpath );
|
333
|
+
pRbTxpath->hxNS = ns_hash;
|
334
|
+
|
335
|
+
return( Qnil );
|
336
|
+
}
|
337
|
+
|
338
|
+
/* ------------------------------------------------------------------------------- */
|
339
|
+
|
340
|
+
/** o.execute( XPathExp ) */
|
341
|
+
VALUE ruby_xpath_xml_execute( VALUE self, VALUE xpathExp ) {
|
342
|
+
int RCod = -1;
|
343
|
+
RbTxpath *pRbTxpath;
|
344
|
+
Check_Type( xpathExp, T_STRING );
|
345
|
+
|
346
|
+
Data_Get_Struct( self, RbTxpath, pRbTxpath );
|
347
|
+
|
348
|
+
RCod = parse( STR2CSTR( pRbTxpath->xXmlData ), pRbTxpath->iXmlType, BAD_CAST STR2CSTR( xpathExp ), pRbTxpath );
|
349
|
+
|
350
|
+
return( INT2NUM( RCod ) );
|
351
|
+
}
|
352
|
+
|
353
|
+
/* a = o.to_a */
|
354
|
+
VALUE ruby_xpath_xml_to_a( VALUE self ) {
|
355
|
+
RbTxpath *pRbTxpath;
|
356
|
+
Data_Get_Struct( self, RbTxpath, pRbTxpath );
|
357
|
+
|
358
|
+
return( pRbTxpath->rbResult );
|
359
|
+
}
|
360
|
+
|
361
|
+
/* ------------------------------------------------------------------------------- */
|
362
|
+
|
363
|
+
VALUE ruby_xpath_xml_each( VALUE self ) {
|
364
|
+
RbTxpath *pRbTxpath;
|
365
|
+
Data_Get_Struct( self, RbTxpath, pRbTxpath );
|
366
|
+
int iCpt;
|
367
|
+
|
368
|
+
if (rb_block_given_p()) {
|
369
|
+
for( iCpt = 0; iCpt < pRbTxpath->iNbNodes; iCpt++ ) {
|
370
|
+
VALUE rbNode = rb_ary_entry( pRbTxpath->rbResult, iCpt );
|
371
|
+
rb_yield( rbNode );
|
372
|
+
}
|
373
|
+
}
|
374
|
+
return( Qnil );
|
375
|
+
}
|
376
|
+
|
377
|
+
VALUE ruby_xpath_xml_first( VALUE self ) {
|
378
|
+
RbTxpath *pRbTxpath;
|
379
|
+
Data_Get_Struct( self, RbTxpath, pRbTxpath );
|
380
|
+
int RCod = 0;
|
381
|
+
|
382
|
+
if( pRbTxpath->iNbNodes > 0 ) {
|
383
|
+
pRbTxpath->iCurrentNode = 0;
|
384
|
+
RCod = 1;
|
385
|
+
}
|
386
|
+
|
387
|
+
return( INT2NUM( RCod ) );
|
388
|
+
}
|
389
|
+
|
390
|
+
VALUE ruby_xpath_xml_last( VALUE self ) {
|
391
|
+
RbTxpath *pRbTxpath;
|
392
|
+
Data_Get_Struct( self, RbTxpath, pRbTxpath );
|
393
|
+
int RCod = 0;
|
394
|
+
|
395
|
+
if( pRbTxpath->iNbNodes > 0 ) {
|
396
|
+
pRbTxpath->iCurrentNode = pRbTxpath->iNbNodes - 1;
|
397
|
+
RCod = pRbTxpath->iNbNodes;
|
398
|
+
}
|
399
|
+
|
400
|
+
return( INT2NUM( RCod ) );
|
401
|
+
}
|
402
|
+
|
403
|
+
VALUE ruby_xpath_xml_next( VALUE self ) {
|
404
|
+
RbTxpath *pRbTxpath;
|
405
|
+
Data_Get_Struct( self, RbTxpath, pRbTxpath );
|
406
|
+
int RCod = 0;
|
407
|
+
|
408
|
+
if( pRbTxpath->iCurrentNode + 1 < pRbTxpath->iNbNodes ) {
|
409
|
+
pRbTxpath->iCurrentNode += 1;
|
410
|
+
RCod = pRbTxpath->iCurrentNode + 1;
|
411
|
+
}
|
412
|
+
|
413
|
+
return( INT2NUM( RCod ) );
|
414
|
+
}
|
415
|
+
|
416
|
+
VALUE ruby_xpath_xml_prev( VALUE self ) {
|
417
|
+
RbTxpath *pRbTxpath;
|
418
|
+
Data_Get_Struct( self, RbTxpath, pRbTxpath );
|
419
|
+
int RCod = 0;
|
420
|
+
|
421
|
+
if( pRbTxpath->iCurrentNode - 1 >= 0 ) {
|
422
|
+
pRbTxpath->iCurrentNode -= 1;
|
423
|
+
RCod = pRbTxpath->iCurrentNode + 1;
|
424
|
+
}
|
425
|
+
|
426
|
+
return( INT2NUM( RCod ) );
|
427
|
+
}
|
428
|
+
|
429
|
+
/* ------------------------------------------------------------------------------- */
|
430
|
+
|
431
|
+
VALUE ruby_xpath_xml_name( VALUE self ) {
|
432
|
+
return( get_node_element( self, "name" ) );
|
433
|
+
}
|
434
|
+
|
435
|
+
VALUE ruby_xpath_xml_attrs( VALUE self ) {
|
436
|
+
return( get_node_element( self, "attrs" ) );
|
437
|
+
}
|
438
|
+
|
439
|
+
VALUE ruby_xpath_xml_type( VALUE self ) {
|
440
|
+
return( get_node_element( self, "type" ) );
|
441
|
+
}
|
442
|
+
|
443
|
+
VALUE ruby_xpath_xml_content( VALUE self ) {
|
444
|
+
return( get_node_element( self, "content" ) );
|
445
|
+
}
|
446
|
+
|
447
|
+
VALUE ruby_xpath_xml_path( VALUE self ) {
|
448
|
+
return( get_node_element( self, "path" ) );
|
449
|
+
}
|
450
|
+
|
451
|
+
|
452
|
+
/* ------------------------------------------------------------------------------- */
|
453
|
+
|
454
|
+
void ruby_xpath_free( RbTxpath *pRbTxpath ) {
|
455
|
+
if (pRbTxpath != NULL)
|
456
|
+
free(pRbTxpath);
|
457
|
+
}
|
458
|
+
|
459
|
+
void ruby_xpath_mark( RbTxpath *pRbTxpath ) {
|
460
|
+
if( pRbTxpath == NULL ) return;
|
461
|
+
if( !NIL_P(pRbTxpath->xXmlData) ) rb_gc_mark( pRbTxpath->xXmlData );
|
462
|
+
if( !NIL_P(pRbTxpath->hxNS) ) rb_gc_mark( pRbTxpath->hxNS );
|
463
|
+
if( !NIL_P(pRbTxpath->rbResult) ) rb_gc_mark( pRbTxpath->rbResult );
|
464
|
+
}
|
465
|
+
|
466
|
+
/** o = XML::XPATH.new() */
|
467
|
+
VALUE ruby_xpath_new( VALUE class ) {
|
468
|
+
RbTxpath *pRbTxpath;
|
469
|
+
|
470
|
+
pRbTxpath = (RbTxpath *)malloc(sizeof(RbTxpath));
|
471
|
+
if( pRbTxpath == NULL )
|
472
|
+
rb_raise(rb_eNoMemError, "No memory left for XPATH struct");
|
473
|
+
|
474
|
+
pRbTxpath->iXmlType = RUBY_XPATH_XMLSRC_TYPE_NULL;
|
475
|
+
pRbTxpath->xXmlData = Qnil;
|
476
|
+
pRbTxpath->hxNS = Qnil;
|
477
|
+
pRbTxpath->rbResult = Qnil;
|
478
|
+
pRbTxpath->iCurrentNode = 0;
|
479
|
+
pRbTxpath->iNbNodes = 0;
|
480
|
+
|
481
|
+
return( Data_Wrap_Struct( class, ruby_xpath_mark, ruby_xpath_free, pRbTxpath ) );
|
482
|
+
}
|
483
|
+
|
484
|
+
VALUE mXML;
|
485
|
+
VALUE cXPATH;
|
486
|
+
|
487
|
+
void Init_xpath( void ) {
|
488
|
+
mXML = rb_define_module( "XML" );
|
489
|
+
cXPATH = rb_define_class_under( mXML, "XPATH", rb_cObject );
|
490
|
+
|
491
|
+
rb_define_const( cXPATH, "XML_ELEMENT_NODE", INT2NUM( 1 ) );
|
492
|
+
rb_define_const( cXPATH, "XML_ATTRIBUTE_NODE", INT2NUM( 2 ) );
|
493
|
+
rb_define_const( cXPATH, "XML_TEXT_NODE", INT2NUM( 3 ) );
|
494
|
+
rb_define_const( cXPATH, "XML_CDATA_SECTION_NODE", INT2NUM( 4 ) );
|
495
|
+
rb_define_const( cXPATH, "XML_ENTITY_REF_NODE", INT2NUM( 5 ) );
|
496
|
+
rb_define_const( cXPATH, "XML_ENTITY_NODE", INT2NUM( 6 ) );
|
497
|
+
rb_define_const( cXPATH, "XML_PI_NODE", INT2NUM( 7 ) );
|
498
|
+
rb_define_const( cXPATH, "XML_COMMENT_NODE", INT2NUM( 8 ) );
|
499
|
+
rb_define_const( cXPATH, "XML_DOCUMENT_NODE", INT2NUM( 9 ) );
|
500
|
+
rb_define_const( cXPATH, "XML_DOCUMENT_TYPE_NODE", INT2NUM( 10 ) );
|
501
|
+
rb_define_const( cXPATH, "XML_DOCUMENT_FRAG_NODE", INT2NUM( 11 ) );
|
502
|
+
rb_define_const( cXPATH, "XML_NOTATION_NODE", INT2NUM( 12 ) );
|
503
|
+
rb_define_const( cXPATH, "XML_HTML_DOCUMENT_NODE", INT2NUM( 13 ) );
|
504
|
+
rb_define_const( cXPATH, "XML_DTD_NODE", INT2NUM( 14 ) );
|
505
|
+
rb_define_const( cXPATH, "XML_ELEMENT_DECL", INT2NUM( 15 ) );
|
506
|
+
rb_define_const( cXPATH, "XML_ATTRIBUTE_DECL", INT2NUM( 16 ) );
|
507
|
+
rb_define_const( cXPATH, "XML_ENTITY_DECL", INT2NUM( 17 ) );
|
508
|
+
rb_define_const( cXPATH, "XML_NAMESPACE_DECL", INT2NUM( 18 ) );
|
509
|
+
rb_define_const( cXPATH, "XML_XINCLUDE_START", INT2NUM( 19 ) );
|
510
|
+
rb_define_const( cXPATH, "XML_XINCLUDE_END", INT2NUM( 20 ) );
|
511
|
+
rb_define_const( cXPATH, "XML_DOCB_DOCUMENT_NODE", INT2NUM( 21 ) );
|
512
|
+
rb_define_const( cXPATH, "RUBY_XPATH_VERSION", rb_str_new2( RUBY_XPATH_VERSION ) );
|
513
|
+
|
514
|
+
rb_define_singleton_method( cXPATH, "new", ruby_xpath_new, 0 );
|
515
|
+
|
516
|
+
rb_define_method( cXPATH, "xml", ruby_xpath_xml_str_get, 0 );
|
517
|
+
rb_define_method( cXPATH, "xml=", ruby_xpath_xml_str_set, 1 );
|
518
|
+
rb_define_method( cXPATH, "xmlfile=", ruby_xpath_xml_file_set, 1 ); // DEPRECATED
|
519
|
+
rb_define_method( cXPATH, "ns=", ruby_xpath_xml_ns_set, 1 );
|
520
|
+
|
521
|
+
rb_define_method( cXPATH, "execute", ruby_xpath_xml_execute, 1 );
|
522
|
+
rb_define_method( cXPATH, "to_a", ruby_xpath_xml_to_a, 0 );
|
523
|
+
|
524
|
+
rb_define_method( cXPATH, "each", ruby_xpath_xml_each, 0 );
|
525
|
+
rb_define_method( cXPATH, "first", ruby_xpath_xml_first, 0 );
|
526
|
+
rb_define_method( cXPATH, "last", ruby_xpath_xml_last, 0 );
|
527
|
+
rb_define_method( cXPATH, "next", ruby_xpath_xml_next, 0 );
|
528
|
+
rb_define_method( cXPATH, "prev", ruby_xpath_xml_prev, 0 );
|
529
|
+
|
530
|
+
rb_define_method( cXPATH, "name", ruby_xpath_xml_name, 0 );
|
531
|
+
rb_define_method( cXPATH, "attrs", ruby_xpath_xml_attrs, 0 );
|
532
|
+
rb_define_method( cXPATH, "type", ruby_xpath_xml_type, 0 );
|
533
|
+
rb_define_method( cXPATH, "content", ruby_xpath_xml_content, 0 );
|
534
|
+
rb_define_method( cXPATH, "path", ruby_xpath_xml_path, 0 );
|
535
|
+
}
|