#include "rbxs_qname.h" #include "rbxs_dom.h" #include "rbxs_domnode.h" #include "rbxs_domnodeset.h" #include "rbxs_domattribute.h" #include "rbxs_domattributeset.h" //*********************************************************************************** // GC //*********************************************************************************** void rbxs_domnode_free(rbxs_domnode *prbxs_domnode) { if (prbxs_domnode != NULL) { free(prbxs_domnode); } } void rbxs_domnode_mark(rbxs_domnode *prbxs_domnode) { if (prbxs_domnode == NULL) return; if (!NIL_P(prbxs_domnode->doc)) rb_gc_mark(prbxs_domnode->doc); } //*********************************************************************************** // Methods //*********************************************************************************** VALUE rbxs_domnode_dump(VALUE self) { rbxs_domnode *prbxs_domnode; xmlBufferPtr result; VALUE ret; Data_Get_Struct(self, rbxs_domnode, prbxs_domnode); result = xmlBufferCreate(); xmlNodeDump(result, prbxs_domnode->node->doc, prbxs_domnode->node, 0, 1); ret = rb_str_new2(result->content); xmlBufferFree(result); return(ret); } static int nslist_each(VALUE key, VALUE value, xmlXPathContextPtr arg) { if (xmlXPathRegisterNs(arg,STR2CSTR(key),STR2CSTR(value)) != 0) { xmlXPathFreeContext(arg); rb_raise(rb_eRuntimeError, "Couldn't add namespace"); } return ST_CONTINUE; } VALUE rbxs_domnode_find(int argc, VALUE *argv, VALUE self) { rbxs_domnode *prbxs_domnode; xmlXPathContextPtr ctxt; xmlXPathObjectPtr obj; VALUE set; if (argc > 2 || argc < 1) rb_raise(rb_eArgError, "wrong number of arguments (need 1 or 2)"); Check_Type(argv[0], T_STRING); Data_Get_Struct(self, rbxs_domnode, prbxs_domnode); ctxt = xmlXPathNewContext(prbxs_domnode->node->doc); if(ctxt == NULL) rb_raise(rb_eRuntimeError, "Couldn't create XPath context"); ctxt->node = prbxs_domnode->node; if (argc == 2) { Check_Type(argv[1], T_HASH); rb_hash_foreach(argv[1], nslist_each, (st_data_t)ctxt); } obj = xmlXPathEvalExpression(STR2CSTR(argv[0]), ctxt); if(obj == NULL) { xmlXPathFreeContext(ctxt); rb_raise(rb_eRuntimeError, "Error in xpath"); } set = rbxs_domnodeset_new(cSimpleDomNodeSet,prbxs_domnode->doc,obj); xmlXPathFreeContext(ctxt); return set; } VALUE rbxs_domnode_children(VALUE self) { VALUE *vargv, obj; vargv = ALLOC_N(VALUE, 1); vargv[0] = rb_str_new2("*"); obj = rbxs_domnode_find(1,vargv,self); free(vargv); return(obj); } VALUE rbxs_domnode_children_q(VALUE self) { rbxs_domnode *prbxs_domnode; Data_Get_Struct(self, rbxs_domnode, prbxs_domnode); if (prbxs_domnode->node->children) return(Qtrue); else return(Qfalse); } VALUE rbxs_domnode_name(VALUE self) { return(rbxs_qname_new(cSimpleQName,self,RBXS_PARSER_TYPE_DOM)); } VALUE rbxs_domnode_parent(VALUE self) { rbxs_domnode *prbxs_domnode; Data_Get_Struct(self, rbxs_domnode, prbxs_domnode); if (prbxs_domnode->node != xmlDocGetRootElement(prbxs_domnode->node->doc)) return(rbxs_domnode_new(cSimpleDomNode, self, prbxs_domnode->node->parent)); else return(Qnil); } VALUE rbxs_domnode_text_set(VALUE self, VALUE text) { rbxs_domnode *prbxs_domnode; Data_Get_Struct(self, rbxs_domnode, prbxs_domnode); xmlNodeSetContent(prbxs_domnode->node, STR2CSTR(rb_obj_as_string(text))); return(text); } VALUE rbxs_domnode_text_get(VALUE self) { rbxs_domnode *prbxs_domnode; Data_Get_Struct(self, rbxs_domnode, prbxs_domnode); if (prbxs_domnode->node->children != NULL) if (prbxs_domnode->node->children->content != NULL) return(rb_str_new2(prbxs_domnode->node->children->content)); return(rb_str_new2("")); } VALUE rbxs_domnode_to_i(int argc, VALUE *argv, VALUE self) { VALUE b; int base; rb_scan_args(argc, argv, "01", &b); if (argc == 0) base = 10; else base = NUM2INT(b); if (base < 0) rb_raise(rb_eArgError, "illegal radix %d", base); return(rb_str_to_inum(rbxs_domnode_text_get(self),base,Qfalse)); } VALUE rbxs_domnode_to_f(VALUE self) { return rb_float_new(rb_str_to_dbl(rbxs_domnode_text_get(self), Qfalse)); } VALUE rbxs_domnode_text_add(VALUE self, VALUE text) { rbxs_domnode *prbxs_domnode; Check_Type(text, T_STRING); Data_Get_Struct(self, rbxs_domnode, prbxs_domnode); xmlNodeAddContent(prbxs_domnode->node, STR2CSTR(text)); return(text); } VALUE rbxs_domnode_attributes(VALUE self) { return rbxs_domattributeset_new(cSimpleDomAttributeSet,self); } static void createCheckArguments(int argc, VALUE *argv, VALUE *content, VALUE *attributes) { Check_Type(argv[0], T_STRING); switch (argc) { case 3: if ((TYPE(argv[2]) == T_HASH) && (TYPE(argv[1]) != T_HASH)) { *content = rb_obj_as_string(argv[1]); *attributes = argv[2]; } else if ((TYPE(argv[1]) == T_HASH) && (TYPE(argv[2]) != T_HASH)) { *content = rb_obj_as_string(argv[2]); *attributes = argv[1]; } else rb_raise(rb_eArgError, "argument 2 or 3 has to be a Hash"); break; case 2: if (TYPE(argv[1]) != T_HASH) *content = rb_obj_as_string(argv[1]); else if (TYPE(argv[1]) == T_HASH) *attributes = argv[1]; else rb_raise(rb_eArgError, "argument 2 has to be a String or a Hash"); break; case 1: break; default: rb_raise(rb_eArgError, "wrong number of arguments (need 2 or 3)"); } } static int createAddAttributes_each(VALUE key, VALUE value, xmlNodePtr arg) { xmlAttrPtr attr; Check_Type(key, T_STRING); attr = xmlNewProp(arg, STR2CSTR(key), STR2CSTR(rb_obj_as_string(value))); if (attr == NULL) rb_raise(rb_eRuntimeError, "Couldn't not add attribute"); return ST_CONTINUE; } VALUE rbxs_domnode_append_child(int argc, VALUE *argv, VALUE self) { rbxs_domnode *prbxs_domnode; xmlNodePtr new_domnode; VALUE content; VALUE attributes; content = Qnil; attributes = rb_hash_new(); createCheckArguments(argc,argv,&content,&attributes); Data_Get_Struct(self, rbxs_domnode, prbxs_domnode); new_domnode = xmlNewChild(prbxs_domnode->node, NULL, STR2CSTR(argv[0]), (content == Qnil ? NULL : STR2CSTR(content))); if (new_domnode == NULL) rb_raise(rb_eRuntimeError, "Couldn't add namespace"); rb_hash_foreach(attributes, createAddAttributes_each, (st_data_t)new_domnode); return(rbxs_domnode_new(cSimpleDomNode,prbxs_domnode->doc,new_domnode)); } VALUE rbxs_domnode_insert_sibling_before(int argc, VALUE *argv, VALUE self) { rbxs_domnode *prbxs_domnode; VALUE content; VALUE attributes; content = rb_str_new2(""); attributes = rb_hash_new(); createCheckArguments(argc,argv,&content,&attributes); Data_Get_Struct(self, rbxs_domnode, prbxs_domnode); if (prbxs_domnode->node->parent == NULL) rb_raise(rb_eRuntimeError, "Can't add sibling to root"); return(Qnil); } VALUE rbxs_domnode_insert_sibling_after(int argc, VALUE *argv, VALUE self) { rbxs_domnode *prbxs_domnode; VALUE content; VALUE attributes; content = rb_str_new2(""); attributes = rb_hash_new(); createCheckArguments(argc,argv,&content,&attributes); Data_Get_Struct(self, rbxs_domnode, prbxs_domnode); return(Qnil); } //*********************************************************************************** // Constructors //*********************************************************************************** VALUE rbxs_domnode_new(VALUE class, VALUE doc, xmlNodePtr node) { rbxs_domnode *prbxs_domnode; prbxs_domnode = (rbxs_domnode *)malloc(sizeof(rbxs_domnode)); if (prbxs_domnode == NULL ) rb_raise(rb_eNoMemError, "No memory left for XML::Simple::Node struct"); prbxs_domnode->doc = doc; prbxs_domnode->node = node; return(Data_Wrap_Struct(class, rbxs_domnode_mark, rbxs_domnode_free, prbxs_domnode)); } //*********************************************************************************** // Initialize class Node //*********************************************************************************** VALUE cSimpleDomNode; void init_rbxs_domnode(void) { cSimpleDomNode = rb_define_class_under( cSimpleDom, "Node", rb_cObject ); rb_define_method(cSimpleDomNode, "dump", rbxs_domnode_dump, 0); rb_define_method(cSimpleDomNode, "find", rbxs_domnode_find, -1); rb_define_method(cSimpleDomNode, "to_s", rbxs_domnode_text_get, 0); rb_define_method(cSimpleDomNode, "to_i", rbxs_domnode_to_i, -1); rb_define_method(cSimpleDomNode, "to_f", rbxs_domnode_to_f, 0); rb_define_method(cSimpleDomNode, "name", rbxs_domnode_name, 0); rb_define_method(cSimpleDomNode, "text", rbxs_domnode_text_get, 0); rb_define_method(cSimpleDomNode, "text=", rbxs_domnode_text_set, 1); rb_define_method(cSimpleDomNode, "children", rbxs_domnode_children, 0); rb_define_method(cSimpleDomNode, "children?", rbxs_domnode_children_q, 0); rb_define_method(cSimpleDomNode, "parent", rbxs_domnode_parent, 0); rb_define_method(cSimpleDomNode, "attributes", rbxs_domnode_attributes, 0); rb_define_method(cSimpleDomNode, "append_child", rbxs_domnode_append_child, -1); rb_define_method(cSimpleDomNode, "insert_sibling_before", rbxs_domnode_insert_sibling_before, -1); rb_define_method(cSimpleDomNode, "insert_sibling_after", rbxs_domnode_insert_sibling_after, -1); }