root/ext/fastxml_node.c

Revision 286299c5d300ecff2991cf7f9cab8ad33e221a0c, 7.8 KB (checked in by Mark Guzman <segfault@…>, 6 months ago)

made some initial changes to build versus ruby 1.9

  • Property mode set to 100644
Line 
1/*
2 * Document-class: FastXml::Node
3 * Provide a wrapper around the libxml node structures.
4 * Objects of this type are generally retrieved from FastXml::Doc
5 * calls.
6 *
7 * Example:
8 *  puts doc.children.first.content # prints an element's inner text
9 *  doc.children.first.content = "new inner text" # assigns that inner text
10 *  doc.children.first.children # gather a list of node's immediately beneith the target node
11 */
12// Please see the LICENSE file for copyright, licensing and distribution information
13
14#include "fastxml.h"
15#include "fastxml_node.h"
16#include "fastxml_doc.h"
17#include "fastxml_nodelist.h"
18
19/* {{{ fastxml_node
20 */
21void Init_fastxml_node()
22{
23        #ifdef RDOC_SHOULD_BE_SMARTER__THIS_IS_NEVER_RUN
24    rb_mFastXml = rb_define_module( "FastXml" );
25        #endif
26        rb_cFastXmlNode = rb_define_class_under( rb_mFastXml, "Node", rb_cObject );
27       
28        rb_define_method( rb_cFastXmlNode, "initialize", fastxml_node_initialize, 0 );
29    rb_define_method( rb_cFastXmlNode, "search", fastxml_node_search, 1 );
30    rb_define_method( rb_cFastXmlNode, "to_s", fastxml_node_to_s, 0 );
31    rb_define_method( rb_cFastXmlNode, "name", fastxml_node_name, 0 );
32    rb_define_method( rb_cFastXmlNode, "content", fastxml_node_value, 0 );
33    rb_define_method( rb_cFastXmlNode, "content=", fastxml_node_value_set, 1 );
34    rb_define_method( rb_cFastXmlNode, "inner_xml", fastxml_node_innerxml, 0 );
35        rb_define_method( rb_cFastXmlNode, "xpath", fastxml_node_xpath, 0 );
36        rb_define_method( rb_cFastXmlNode, "attr", fastxml_node_attr, 0 );
37        rb_define_method( rb_cFastXmlNode, "children", fastxml_node_children, 0 );
38        rb_define_method( rb_cFastXmlNode, "next", fastxml_node_next, 0 );     
39        rb_define_method( rb_cFastXmlNode, "prev", fastxml_node_prev, 0 );     
40        rb_define_method( rb_cFastXmlNode, "parent", fastxml_node_parent, 0 ); 
41    rb_define_method( rb_cFastXmlNode, "inspect", fastxml_node_inspect, 0 );
42}
43
44/* Returns a friendly summary of the node
45 *
46 */
47VALUE fastxml_node_inspect(VALUE self)
48{
49    VALUE dv;
50    VALUE *argv;
51    fxml_data_t *data;
52
53    dv = rb_iv_get( self, "@lxml_doc" );   
54    Data_Get_Struct( dv, fxml_data_t, data );
55
56    argv = ALLOCA_N( VALUE, 4 );
57    argv[0] = rb_str_new2( "#<%s:0x%x %s>" );
58    argv[1] = CLASS_OF( self );
59    argv[2] = rb_obj_id( self );
60    argv[3] = rb_str_new2( (char*) data->node->name );
61    return rb_f_sprintf( 4, argv );
62}
63
64/* Creates an empty FastXml::Node
65 *
66 */
67VALUE fastxml_node_initialize(VALUE self)
68{
69    return self;
70}
71
72/* Returns the raw xml for a node
73 *
74 */
75VALUE fastxml_node_innerxml(VALUE self)
76{
77        VALUE dv, ret;
78    fxml_data_t *data;
79        xmlBufferPtr buf = xmlBufferCreate();
80
81    dv = rb_iv_get( self, "@lxml_doc" );   
82    Data_Get_Struct( dv, fxml_data_t, data );
83       
84        xmlNodeDump( buf, data->doc, data->node, 0, 0 );
85        ret = rb_str_new2( (char*)xmlBufferContent( buf ) );
86        xmlBufferFree( buf );   
87       
88    return ret;
89}
90
91/* Returns the next (FastXml::Node) sibling if one exists, nil otherwise.
92 *
93 */
94VALUE fastxml_node_next(VALUE self)
95{
96        VALUE dv, next;
97    fxml_data_t *data;
98
99    dv = rb_iv_get( self, "@lxml_doc" );   
100    Data_Get_Struct( dv, fxml_data_t, data );
101
102        if (data->node == NULL || (data->node != NULL && data->node->next == NULL))
103                return Qnil;
104               
105        next = rb_iv_get( self, "@next" );
106        if (next == Qnil) {
107                next = fastxml_raw_node_to_obj( data->node->next );
108                rb_iv_set( self, "@next", next );
109        }
110       
111        return next;
112}
113
114/* Returns the previous (FastXml::Node) sibling if one exists, nil otherwise.
115 *
116 */
117VALUE fastxml_node_prev(VALUE self)
118{
119        VALUE dv, prev;
120    fxml_data_t *data;
121
122    dv = rb_iv_get( self, "@lxml_doc" );   
123    Data_Get_Struct( dv, fxml_data_t, data );
124
125        if (data->node == NULL || (data->node != NULL && data->node->prev == NULL))
126                return Qnil;
127               
128        prev = rb_iv_get( self, "@prev" );
129        if (prev == Qnil) {
130                prev = fastxml_raw_node_to_obj( data->node->prev );
131                rb_iv_set( self, "@prev", prev );
132        }               
133       
134        return prev;
135}
136
137/* Returns the parent (FastXml::Node) node if one exists, nil otherwise.
138 *
139 */
140VALUE fastxml_node_parent(VALUE self)
141{
142        VALUE dv;
143    fxml_data_t *data;
144
145    dv = rb_iv_get( self, "@lxml_doc" );   
146    Data_Get_Struct( dv, fxml_data_t, data );
147
148        if (data->node == NULL || (data->node != NULL && data->node->parent == NULL))
149                return Qnil;
150       
151        return fastxml_raw_node_to_obj( data->node->parent );
152}
153
154/* Returns a list of child nodes if children exist, nil otherwise.
155 *
156 * Example:
157 *  node.children.each { |n| puts n.inspect }
158 *  puts node.children.first.name
159 *  puts node.children.last.content
160 */
161VALUE fastxml_node_children(VALUE self)
162{
163        VALUE dv;
164    fxml_data_t *data;
165
166    dv = rb_iv_get( self, "@lxml_doc" );   
167    Data_Get_Struct( dv, fxml_data_t, data );
168
169        if (data->node == NULL || (data->node != NULL && data->node->children == NULL))
170                return Qnil;
171       
172        return fastxml_nodelist_to_obj( data->node->children, -1 );
173}
174
175
176/* Returns the name of the node.
177 *  Given "<taco/>" => "taco"
178 *
179 */
180VALUE fastxml_node_name(VALUE self)
181{
182    VALUE ret, dv;
183    fxml_data_t *data;
184
185    dv = rb_iv_get( self, "@lxml_doc" );   
186    Data_Get_Struct( dv, fxml_data_t, data ); 
187
188    if (data->node == NULL || (data->node != NULL && data->node->name == NULL))
189        return Qnil;
190
191    ret = rb_str_new2( (const char*)data->node->name );
192
193    return ret;
194}
195
196/* Returns a FastXml::AttrList containing all of the attributes
197 * associated with the target node
198 *
199 * Example:
200 *   node.attr[:test] = "attrtest"
201 *   puts node.attr[:test]  => "attrtest"
202 *
203 */
204VALUE fastxml_node_attr(VALUE self)
205{
206        VALUE self_dv, ret;
207        fxml_data_t *data;
208
209        ret = rb_iv_get( self, "@attrs" );
210        if (ret == Qnil) {
211                self_dv = rb_iv_get( self, "@lxml_doc" );
212                Data_Get_Struct( self_dv, fxml_data_t, data );
213                ret = rb_class_new_instance( 0, 0, rb_cFastXmlAttrList ); 
214
215                rb_iv_set( ret, "@lxml_doc", self_dv );
216        rb_iv_set( self, "@attrs", ret );
217        }
218
219        return ret;
220}
221
222/* Returns the xpath location of the target node.
223 */
224VALUE fastxml_node_xpath(VALUE self)
225{
226        VALUE ret, dv;
227        fxml_data_t *data;
228        xmlChar *raw_ret;
229       
230        dv = rb_iv_get( self, "@lxml_doc" );
231        Data_Get_Struct( dv, fxml_data_t, data );
232       
233        raw_ret = xmlGetNodePath( data->node );
234        if (raw_ret == NULL)
235                return Qnil;
236       
237        ret = rb_str_new2( (const char*)raw_ret );
238        xmlFree( raw_ret );
239       
240        return ret;
241}
242
243/* Sets the contents/value/inner text of the node.
244 */
245VALUE fastxml_node_value_set(VALUE self, VALUE new_val)
246{
247    VALUE dv, val_s;
248    fxml_data_t *data;
249    xmlChar *ents, *spec;
250
251
252    val_s = rb_obj_as_string( new_val );
253    dv = rb_iv_get( self, "@lxml_doc" );   
254    Data_Get_Struct( dv, fxml_data_t, data ); 
255
256    ents = xmlEncodeEntitiesReentrant( data->doc, (const xmlChar*)StringValuePtr(val_s) );
257    spec = xmlEncodeSpecialChars( data->doc, ents );
258
259    xmlNodeSetContent( data->node, spec );
260    xmlFree( ents );
261
262    return new_val;
263}
264
265/* Returns the contents/value/inner text of the node.
266 */
267VALUE fastxml_node_value(VALUE self)
268{
269    VALUE ret, dv;
270    fxml_data_t *data;
271        xmlChar *cont;
272
273    dv = rb_iv_get( self, "@lxml_doc" );   
274    Data_Get_Struct( dv, fxml_data_t, data ); 
275       
276        cont = xmlNodeGetContent( data->node );
277
278    if (cont == NULL)
279        return Qnil;
280
281    ret = rb_str_new2( (const char*)cont );
282
283    return ret;
284}
285
286/* Returns the string representation of the node
287 *
288 */
289VALUE fastxml_node_to_s(VALUE self)
290{
291    VALUE ret, dv;
292    fxml_data_t *data;
293    xmlBufferPtr buf;
294
295    dv = rb_iv_get( self, "@lxml_doc" );
296    Data_Get_Struct( dv, fxml_data_t, data );
297
298    buf = xmlBufferCreate();
299    ret = Qnil;
300
301    if (xmlNodeDump(buf, data->doc, data->node, 0, 0) != -1) 
302        ret = rb_str_new( (const char*)buf->content, buf->use );
303
304    xmlBufferFree( buf );
305    return ret;
306}
307
308/* Evaluates an xpath query and returns a list of nodes
309 * that match.
310 *
311 * call-seq:
312 *   node.search( "//subnodes" ).each { |n| puts n.inspect }
313 */
314VALUE fastxml_node_search(VALUE self, VALUE raw_xpath, VALUE blk)
315{
316    return fastxml_xpath_search( self, raw_xpath, blk );
317}
318
319
320/* }}} fastxml_node
321 */
Note: See TracBrowser for help on using the browser.