| 1 | /* |
|---|
| 2 | * Document-class: FastXml::NodeList |
|---|
| 3 | * |
|---|
| 4 | * call-seq: |
|---|
| 5 | * doc = FastXml( docfile ) # from FastXml::Doc |
|---|
| 6 | * list = doc.root.children # pull the FastXml::NodeList comprised of the Element's children |
|---|
| 7 | * puts "The document root element has %d children." % list.length |
|---|
| 8 | * list.each { |e| puts e.name } # iterate over each element and print it's name |
|---|
| 9 | * puts list[3] # print the 4th element in the list |
|---|
| 10 | */ |
|---|
| 11 | // Please see the LICENSE file for copyright, licensing and distribution information |
|---|
| 12 | |
|---|
| 13 | #include "fastxml.h" |
|---|
| 14 | #include "fastxml_node.h" |
|---|
| 15 | #include "fastxml_doc.h" |
|---|
| 16 | #include "fastxml_nodelist.h" |
|---|
| 17 | |
|---|
| 18 | /* {{{ fastxml_nodelist |
|---|
| 19 | */ |
|---|
| 20 | void Init_fastxml_nodelist() |
|---|
| 21 | { |
|---|
| 22 | #ifdef RDOC_SHOULD_BE_SMARTER__THIS_IS_NEVER_RUN |
|---|
| 23 | rb_mFastXml = rb_define_module( "FastXml" ); |
|---|
| 24 | #endif |
|---|
| 25 | rb_cFastXmlNodeList = rb_define_class_under( rb_mFastXml, "NodeList", rb_cObject ); |
|---|
| 26 | |
|---|
| 27 | rb_include_module( rb_cFastXmlNodeList, rb_mEnumerable ); |
|---|
| 28 | rb_define_method( rb_cFastXmlNodeList, "initialize", fastxml_nodelist_initialize, 0 ); |
|---|
| 29 | rb_define_method( rb_cFastXmlNodeList, "length", fastxml_nodelist_length, 0 ); |
|---|
| 30 | rb_define_method( rb_cFastXmlNodeList, "each", fastxml_nodelist_each, 0 ); |
|---|
| 31 | rb_define_method( rb_cFastXmlNodeList, "entry", fastxml_nodelist_entry, 1 ); |
|---|
| 32 | rb_define_method( rb_cFastXmlNodeList, "to_ary", fastxml_nodelist_entry, 0 ); |
|---|
| 33 | } |
|---|
| 34 | |
|---|
| 35 | VALUE fastxml_nodelist_inspect(VALUE self) |
|---|
| 36 | { |
|---|
| 37 | VALUE dv; |
|---|
| 38 | VALUE *argv; |
|---|
| 39 | fxml_data_t *data; |
|---|
| 40 | |
|---|
| 41 | dv = rb_iv_get( self, "@lxml_doc" ); |
|---|
| 42 | Data_Get_Struct( dv, fxml_data_t, data ); |
|---|
| 43 | |
|---|
| 44 | argv = ALLOCA_N( VALUE, 4 ); |
|---|
| 45 | argv[0] = rb_str_new2( "#<%s:0x%x %d>" ); |
|---|
| 46 | argv[1] = CLASS_OF( self ); |
|---|
| 47 | argv[2] = rb_obj_id( self ); |
|---|
| 48 | argv[3] = fastxml_nodelist_length( self ); |
|---|
| 49 | return rb_f_sprintf( 4, argv ); |
|---|
| 50 | } |
|---|
| 51 | |
|---|
| 52 | VALUE fastxml_nodelist_initialize(VALUE self) |
|---|
| 53 | { |
|---|
| 54 | return self; |
|---|
| 55 | } |
|---|
| 56 | |
|---|
| 57 | /* Return the length of the FastXml::NodeList |
|---|
| 58 | * |
|---|
| 59 | * call-seq: |
|---|
| 60 | * puts doc.children.length |
|---|
| 61 | */ |
|---|
| 62 | VALUE fastxml_nodelist_length(VALUE self) |
|---|
| 63 | { |
|---|
| 64 | VALUE dv; |
|---|
| 65 | xmlNodePtr cur; |
|---|
| 66 | fxml_data_t *data; |
|---|
| 67 | |
|---|
| 68 | dv = rb_iv_get( self, "@lxml_doc" ); |
|---|
| 69 | Data_Get_Struct( dv, fxml_data_t, data ); |
|---|
| 70 | |
|---|
| 71 | if (data->list_len == EMPTY_NODELIST) { |
|---|
| 72 | data->list_len = 0; |
|---|
| 73 | |
|---|
| 74 | cur = data->list; |
|---|
| 75 | while (cur != NULL) { |
|---|
| 76 | data->list_len++; |
|---|
| 77 | cur = cur->next; |
|---|
| 78 | } |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | return rb_int2inum( data->list_len ); |
|---|
| 82 | } |
|---|
| 83 | |
|---|
| 84 | VALUE fastxml_nodelist_obj_to_ary(fxml_data_t *root) |
|---|
| 85 | { |
|---|
| 86 | VALUE ret; |
|---|
| 87 | xmlNodePtr cur = root->list; |
|---|
| 88 | |
|---|
| 89 | ret = rb_ary_new(); |
|---|
| 90 | while (cur != NULL) { |
|---|
| 91 | rb_ary_push( ret, fastxml_raw_node_to_obj( cur ) ); |
|---|
| 92 | cur = cur->next; |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | return ret; |
|---|
| 96 | } |
|---|
| 97 | |
|---|
| 98 | VALUE fastxml_nodeset_obj_to_ary(fxml_data_t *root) |
|---|
| 99 | { |
|---|
| 100 | VALUE ret; |
|---|
| 101 | xmlNodePtr cur, sub = NULL; |
|---|
| 102 | int i; |
|---|
| 103 | |
|---|
| 104 | ret = rb_ary_new(); |
|---|
| 105 | if (root->xpath_obj->nodesetval->nodeTab != NULL) { |
|---|
| 106 | cur = *root->xpath_obj->nodesetval->nodeTab; |
|---|
| 107 | for (i = 0; i < root->list_len; i++) { |
|---|
| 108 | if (cur->type != XML_ELEMENT_NODE) |
|---|
| 109 | continue; |
|---|
| 110 | |
|---|
| 111 | rb_ary_push( ret, fastxml_raw_node_to_obj( cur ) ); |
|---|
| 112 | sub = cur->next; |
|---|
| 113 | while (sub != NULL) { |
|---|
| 114 | rb_ary_push( ret, fastxml_raw_node_to_obj( sub ) ); |
|---|
| 115 | sub = sub->next; |
|---|
| 116 | } |
|---|
| 117 | cur++; |
|---|
| 118 | } |
|---|
| 119 | } |
|---|
| 120 | |
|---|
| 121 | |
|---|
| 122 | return ret; |
|---|
| 123 | } |
|---|
| 124 | |
|---|
| 125 | VALUE fastxml_nodelist_gen_list(VALUE self, fxml_data_t *data) |
|---|
| 126 | { |
|---|
| 127 | VALUE lst = rb_iv_get( self, "@list" ); |
|---|
| 128 | |
|---|
| 129 | if (lst == Qnil) { |
|---|
| 130 | if (data->xpath_obj != NULL) { |
|---|
| 131 | lst = fastxml_nodeset_obj_to_ary( data ); |
|---|
| 132 | rb_iv_set( self, "@list", lst ); |
|---|
| 133 | } else { |
|---|
| 134 | lst = fastxml_nodelist_obj_to_ary( data ); |
|---|
| 135 | rb_iv_set( self, "@list", lst ); |
|---|
| 136 | } |
|---|
| 137 | } |
|---|
| 138 | |
|---|
| 139 | return lst; |
|---|
| 140 | } |
|---|
| 141 | |
|---|
| 142 | VALUE fastxml_nodelist_to_ary(VALUE self) |
|---|
| 143 | { |
|---|
| 144 | VALUE dv; |
|---|
| 145 | fxml_data_t *data; |
|---|
| 146 | |
|---|
| 147 | dv = rb_iv_get( self, "@lxml_doc" ); |
|---|
| 148 | Data_Get_Struct( dv, fxml_data_t, data ); |
|---|
| 149 | return fastxml_nodelist_gen_list( self, data ); |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | /* Iterate over the list yielding each FastXml::Node contained |
|---|
| 153 | * |
|---|
| 154 | * call-seq: |
|---|
| 155 | * puts doc.children.each { |e| puts e.name } |
|---|
| 156 | */ |
|---|
| 157 | VALUE fastxml_nodelist_each(VALUE self) |
|---|
| 158 | { |
|---|
| 159 | VALUE lst, dv; |
|---|
| 160 | fxml_data_t *data; |
|---|
| 161 | int i; |
|---|
| 162 | |
|---|
| 163 | dv = rb_iv_get( self, "@lxml_doc" ); |
|---|
| 164 | Data_Get_Struct( dv, fxml_data_t, data ); |
|---|
| 165 | lst = fastxml_nodelist_gen_list( self, data ); |
|---|
| 166 | |
|---|
| 167 | for (i=0; i<RARRAY(lst)->len; i++) { |
|---|
| 168 | rb_yield( RARRAY(lst)->ptr[i] ); |
|---|
| 169 | } |
|---|
| 170 | |
|---|
| 171 | return self; |
|---|
| 172 | } |
|---|
| 173 | |
|---|
| 174 | /* Returns the element (FastXml::Node) from the FastXml::NodeList at idx |
|---|
| 175 | * position. 0-based indexing. Ranges are not supported as of yet |
|---|
| 176 | * (Patches welcome). |
|---|
| 177 | * |
|---|
| 178 | * call-seq: |
|---|
| 179 | * puts doc.children[0] # |
|---|
| 180 | * puts doc.children[-1] # last element in the list |
|---|
| 181 | */ |
|---|
| 182 | VALUE fastxml_nodelist_entry(VALUE self, long idx) |
|---|
| 183 | { |
|---|
| 184 | VALUE lst, dv; |
|---|
| 185 | fxml_data_t *data; |
|---|
| 186 | |
|---|
| 187 | dv = rb_iv_get( self, "@lxml_doc" ); |
|---|
| 188 | Data_Get_Struct( dv, fxml_data_t, data ); |
|---|
| 189 | lst = fastxml_nodelist_gen_list( self, data ); |
|---|
| 190 | if (idx > 0) // this comes in offset by 1 |
|---|
| 191 | idx = idx-1; |
|---|
| 192 | // TODO: find out why this is provided offset by 1 and not 0-based |
|---|
| 193 | |
|---|
| 194 | return rb_ary_entry( lst, idx ); |
|---|
| 195 | } |
|---|
| 196 | |
|---|
| 197 | /* }}} fastxml_nodelist |
|---|
| 198 | */ |
|---|