ruby-xpath 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|