ext/xml/ruby_xml_node.c in libxml-ruby-0.3.8.4 vs ext/xml/ruby_xml_node.c in libxml-ruby-0.5.0

- old
+ new

@@ -1,6 +1,6 @@ -/* $Id: ruby_xml_node.c,v 1.9.2.3 2006/11/27 10:32:01 roscopeco Exp $ */ +/* $Id: ruby_xml_node.c 138 2007-08-29 18:00:35Z danj $ */ /* Please see the LICENSE file for copyright and distribution information */ #include "libxml.h" #include "ruby_xml_node.h" @@ -140,10 +140,14 @@ ruby_xml_node_content_add(VALUE self, VALUE obj) { ruby_xml_node *node; VALUE str; Data_Get_Struct(self, ruby_xml_node, node); + /* XXX This should only be legal for a CDATA type node, I think, + * resulting in a merge of content, as if a string were passed + * danj 070827 + */ if (rb_obj_is_kind_of(obj, cXMLNode)) { ruby_xml_node_child_set(self, obj); return(self); } else if (TYPE(obj) == T_STRING) { xmlNodeAddContent(node->node, (xmlChar*)StringValuePtr(obj)); @@ -189,10 +193,11 @@ ruby_xml_node_content_set(VALUE self, VALUE content) { ruby_xml_node *node; Check_Type(content, T_STRING); Data_Get_Struct(self, ruby_xml_node, node); + // XXX docs indicate need for escaping entites, need to be done? danj xmlNodeSetContent(node->node, (xmlChar*)StringValuePtr(content)); return(Qtrue); } @@ -255,11 +260,11 @@ } if (tmp == NULL) return(Qnil); else - return(ruby_xml_node_new_ptr(cXMLNode, node->xd, tmp)); + return(ruby_xml_node2_wrap(cXMLNode, tmp)); } /* * call-seq: @@ -314,26 +319,27 @@ */ VALUE ruby_xml_node_child_set(VALUE self, VALUE rnode) { ruby_xml_node *cnode, *pnode; xmlNodePtr chld, ret; - ruby_xml_document *pdoc, *cdoc; + ruby_xml_document_t *pdoc, *cdoc; int ptr; if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse) rb_raise(rb_eTypeError, "Must pass an XML::Node object"); Data_Get_Struct(self, ruby_xml_node, pnode); Data_Get_Struct(rnode, ruby_xml_node, cnode); chld = cnode->node; - + +#ifdef IGNORE // Only copy if both nodes are in documents, which are different. if (pnode->xd && pnode->xd != Qnil) { - Data_Get_Struct(pnode->xd, ruby_xml_document, pdoc); + Data_Get_Struct(pnode->xd, ruby_xml_document_t, pdoc); if (cnode->xd && cnode->xd != Qnil) { - Data_Get_Struct(cnode->xd, ruby_xml_document, cdoc); + Data_Get_Struct(cnode->xd, ruby_xml_document_t, cdoc); if (cdoc->doc != pdoc->doc) { chld = xmlDocCopyNode(chld, pdoc->doc, 1); chld->_private = 0; ptr = 1; } @@ -343,42 +349,34 @@ ptr = 1; } } else { chld->doc = NULL; } +#endif ret = xmlAddChild(pnode->node, chld); if (ret == NULL) rb_raise(eXMLNodeFailedModify, "unable to add a child to the document"); - cnode->node = ret; - cnode->xd = pnode->xd; - - return(rnode); + return ruby_xml_node2_wrap(cXMLNode,ret); } -//////////////////////////////////////////////// -// TODO new Documents seem to be created quite readily... - /* * call-seq: * node.doc => document * * Obtain the XML::Document this node belongs to. */ VALUE ruby_xml_node_doc(VALUE self) { - ruby_xml_document *rxd; + ruby_xml_document_t *rxd; ruby_xml_node *rxn; - xmlDocPtr doc; + xmlDocPtr doc=NULL; VALUE docobj; Data_Get_Struct(self, ruby_xml_node, rxn); - if (rxn->xd) - return(rxn->xd); - switch (rxn->node->type) { case XML_DOCUMENT_NODE: #ifdef LIBXML_DOCB_ENABLED case XML_DOCB_DOCUMENT_NODE: #endif @@ -400,14 +398,14 @@ } if (doc == NULL) return(Qnil); - docobj = ruby_xml_document_new(cXMLDocument, doc); - Data_Get_Struct(docobj, ruby_xml_document, rxd); - rxd->is_ptr = 1; - return(docobj); + if ( doc->_private == NULL ) + rb_raise(rb_eRuntimeError,"existing document object has no ruby-instance"); + + return (VALUE)doc->_private; } /* * call-seq: @@ -674,14 +672,14 @@ if (rxnset->node_set == NULL || rxnset->node_set->nodeNr < 1) return(Qnil); switch(rxnset->node_set->nodeTab[0]->type) { case XML_ATTRIBUTE_NODE: - nodeobj = ruby_xml_attr_new2(cXMLAttr, rxnset->xd, (xmlAttrPtr)rxnset->node_set->nodeTab[0]); + nodeobj = ruby_xml_attr_wrap(cXMLAttr, (xmlAttrPtr)rxnset->node_set->nodeTab[0]); break; default: - nodeobj = ruby_xml_node_new_ptr(cXMLNode, rxnset->xd, rxnset->node_set->nodeTab[0]); + nodeobj = ruby_xml_node2_wrap(cXMLNode, rxnset->node_set->nodeTab[0]); } return(nodeobj); } @@ -700,29 +698,10 @@ return(Qtrue); else return(Qfalse); } - -void ruby_xml_node_free(ruby_xml_node *rxn) { - if (rxn->node != NULL && // got a node? - rxn->node->parent == NULL && // unparented (otherwise, it gets freed with parent) - rxn->node->doc == NULL) { // No document? (otherwise, freed with doc) - if (rxn->node->_private <= (void*)1) { - // is null or last reference, - xmlFreeNode(rxn->node); - } else { - // other pointers remain - rxn->node->_private--; - } - } - - rxn->node = NULL; - free(rxn); -} - - /* * call-seq: * node.hash => fixnum * * Returns the hash-code for this node. This is the hash of the XML @@ -753,80 +732,22 @@ return(Qtrue); else return(Qfalse); } - /* * call-seq: - * XML::Node.new(name, content = nil) => node - * XML::Node.new_element(name, content = nil) => node - * - * Create a new element node with the specified name, optionally setting - * the node's content. - */ -VALUE -ruby_xml_node_initialize(int argc, VALUE *argv, VALUE class) { - ruby_xml_node *rxn; - VALUE name, node, str; - xmlNodePtr newxn; - - str = Qnil; - - switch(argc) { - case 2: - switch (TYPE(str)) { - case T_STRING: - str = argv[1]; - break; - default: - str = rb_obj_as_string(argv[1]); - if (NIL_P(str)) - Check_Type(str, T_STRING); - break; - } - - /* Intentionally fall through to case 1: as a way of setting up - * the object. Sneaky, but effective. Probably should use a goto - * instead. */ - case 1: - name = check_string_or_symbol( argv[0] ); - newxn = xmlNewNode(NULL, (xmlChar*)StringValuePtr(name)); - node = ruby_xml_node_new(class, newxn); - - Data_Get_Struct(node, ruby_xml_node, rxn); - - /* TODO How would this happen? Shouldn't we raise on it anyway? */ - if (rxn->node == NULL) - return(Qnil); - - if (!NIL_P(str)) - ruby_xml_node_content_set(node, str); - - break; - - default: - rb_raise(rb_eArgError, "wrong number of arguments (1 or 2)"); - } - - return(node); -} - -/* - * call-seq: * XML::Node.new_cdata(content = nil) => node * * Create a new #CDATA node, optionally setting * the node's content. */ VALUE -ruby_xml_node_cdata_initialize(int argc, VALUE *argv, VALUE class) { - xmlNode *xnode; - VALUE node, str; +ruby_xml_node_new_cdata(int argc, VALUE *argv, VALUE class) { + xmlNodePtr xnode; + VALUE node, str=Qnil; - str = Qnil; - switch(argc) { case 1: str = argv[0]; Check_Type(str, T_STRING); if (!NIL_P(str)) { @@ -836,19 +757,18 @@ } if (xnode == NULL) return(Qnil); - node = ruby_xml_node_new(class, xnode); + return ruby_xml_node2_wrap(class,xnode); - break; - default: rb_raise(rb_eArgError, "wrong number of arguments (1)"); } - return(node); + // not reached + return(Qnil); } /* * call-seq: @@ -857,16 +777,14 @@ * Create a new comment node, optionally setting * the node's content. * */ VALUE -ruby_xml_node_comment_initialize(int argc, VALUE *argv, VALUE class) { - xmlNode *xnode; - VALUE node, str; +ruby_xml_node_new_comment(int argc, VALUE *argv, VALUE class) { + xmlNodePtr xnode; + VALUE node, str=Qnil; - str = Qnil; - switch(argc) { case 1: str = argv[0]; Check_Type(str, T_STRING); // TODO xmlNewComment wrongly? adds \n before and after the comment @@ -877,19 +795,18 @@ } if (xnode == NULL) return(Qnil); - node = ruby_xml_node_new(class, xnode); + return ruby_xml_node2_wrap(class,xnode); - break; - default: rb_raise(rb_eArgError, "wrong number of arguments (1)"); } - return(node); + // not reached + return(Qnil); } /* * call-seq: @@ -972,11 +889,11 @@ } if (node == NULL) return(Qnil); else - return(ruby_xml_node_new_ptr(cXMLNode, rxn->xd, node)); + return(ruby_xml_node2_wrap(cXMLNode, node)); } /* * call-seq: @@ -1054,16 +971,14 @@ * Determine whether this node is an xlink node. */ VALUE ruby_xml_node_xlink_q(VALUE self) { ruby_xml_node *node; - ruby_xml_document *doc; xlinkType xlt; Data_Get_Struct(self, ruby_xml_node, node); - Data_Get_Struct(node->xd, ruby_xml_document, doc); - xlt = xlinkIsLink(doc->doc, node->node); + xlt = xlinkIsLink(node->node->doc, node->node); if (xlt == XLINK_TYPE_NONE) return(Qfalse); else return(Qtrue); @@ -1079,16 +994,15 @@ * nil. */ VALUE ruby_xml_node_xlink_type(VALUE self) { ruby_xml_node *node; - ruby_xml_document *doc; + ruby_xml_document_t *doc; xlinkType xlt; Data_Get_Struct(self, ruby_xml_node, node); - Data_Get_Struct(node->xd, ruby_xml_document, doc); - xlt = xlinkIsLink(doc->doc, node->node); + xlt = xlinkIsLink(node->node->doc, node->node); if (xlt == XLINK_TYPE_NONE) return(Qnil); else return(INT2NUM(xlt)); @@ -1104,16 +1018,15 @@ * nil. */ VALUE ruby_xml_node_xlink_type_name(VALUE self) { ruby_xml_node *node; - ruby_xml_document *doc; + ruby_xml_document_t *doc; xlinkType xlt; Data_Get_Struct(self, ruby_xml_node, node); - Data_Get_Struct(node->xd, ruby_xml_document, doc); - xlt = xlinkIsLink(doc->doc, node->node); + xlt = xlinkIsLink(node->node->doc, node->node); switch(xlt) { case XLINK_TYPE_NONE: return(Qnil); case XLINK_TYPE_SIMPLE: @@ -1125,18 +1038,10 @@ default: rb_fatal("Unknowng xlink type, %d", xlt); } } - -static void -ruby_xml_node_mark(ruby_xml_node *rxn) { - if (rxn == NULL) return; - if (!NIL_P(rxn->xd)) rb_gc_mark(rxn->xd); -} - - /* * call-seq: * node.name => "string" * * Obtain this node's name. @@ -1222,11 +1127,11 @@ if (nsList == NULL) return(Qnil); arr = rb_ary_new(); for (cur = nsList; *cur != NULL; cur++) { - ns = ruby_xml_ns_new2(cXMLNS, node->xd, *cur); + ns = ruby_xml_ns_new2(cXMLNS, ruby_xml_document_wrap(cXMLDocument,node->node->doc), *cur); if (ns == Qnil) continue; else rb_ary_push(arr, ns); } @@ -1248,11 +1153,13 @@ Data_Get_Struct(self, ruby_xml_node, node); if (node->node->ns == NULL) return(Qnil); else - return(ruby_xml_ns_new2(cXMLNS, node->xd, node->node->ns)); + return ruby_xml_ns_new2(cXMLNS, + ruby_xml_document_wrap(cXMLDocument,node->node->doc), + node->node->ns); } // TODO namespace_set can take varargs (in fact, must if used // with strings), but I cannot see how you can call // that version, apart from with 'send' @@ -1306,11 +1213,11 @@ ns = xmlNewNs(rxn->node, (xmlChar*)href, (xmlChar*)StringValuePtr(rprefix)); if (ns == NULL) rb_raise(eXMLNodeSetNamespace, "unable to set the namespace"); else - return(ruby_xml_ns_new2(cXMLNS, rxn->xd, ns)); + return ruby_xml_ns_new2(cXMLNS, ruby_xml_document_wrap(cXMLDocument,rxn->node->doc), ns); break; default: rb_raise(rb_eArgError, "wrong number of arguments (1 or 2)"); } @@ -1335,92 +1242,159 @@ return(Qtrue); else return(Qfalse); } -/* TODO new_ptr and new3 are obsolete, should be consolidated */ -VALUE -ruby_xml_node_new(VALUE class, xmlNodePtr node) { - return ruby_xml_node_new_ptr(class, Qnil, node); +/* + * memory2 implementation: xmlNode->_private holds a reference + * to the wrapping ruby object VALUE when there is one. + * traversal for marking is upward, and top levels are marked + * through and lower level mark entry. + * + * All ruby retrieval for an xml + * node will result in the same ruby instance. When all handles to them + * go out of scope, then free gets called and _private is set to NULL. + * If the xmlNode has no parent or document, then call xmlFree. + */ +void +ruby_xml_node2_free(ruby_xml_node *rxn) { + + if (rxn->node == NULL ) return; + + if (rxn->node->parent == NULL && rxn->node->doc == NULL ) { +#ifdef NODE_DEBUG + fprintf(stderr,"free rxn=0x%x xn=0x%x o=0x%x\n",(long)rxn,(long)rxn->node,(long)rxn->node->_private); +#endif + rxn->node->_private=NULL; + xmlFreeNode(rxn->node); + } + + rxn->node=NULL; + // fprintf(stderr,"%0x ",(long)rxn); + free(rxn); } +void +ruby_xml_node2_mark(ruby_xml_node *rxn) { + xmlNodePtr node; + if (rxn->node == NULL ) return; -VALUE -ruby_xml_node_new_ptr(VALUE class, VALUE xd, xmlNodePtr node) { - return ruby_xml_node_new3(class, xd, node, 1); + if (rxn->node->_private == NULL ) { + rb_warning("XmlNode is not bound! (%s:%d)", + __FILE__,__LINE__); + return; + } + + if (rxn->node->doc != NULL ) { + if (rxn->node->doc->_private == NULL ) + rb_warning("XmlNode Doc is not bound! (%s:%d)", + __FILE__,__LINE__); + else { + rb_gc_mark((VALUE)rxn->node->doc->_private); +#ifdef NODE_DEBUG + fprintf(stderr,"mark rxn=0x%x xn=0x%x o=0x%x\n",(long)rxn,(long)rxn->node,(long)rxn->node->_private); +#endif + } + } else if (rxn->node->parent != NULL ) { + if (rxn->node->parent->_private == NULL ) + rb_warning("XmlNode Parent is not bound! (%s:%d)", + __FILE__,__LINE__); + node=rxn->node; + while (node->parent != NULL ) + node=node->parent; + if (node->_private != NULL) { + rb_gc_mark((VALUE)node->_private); +#ifdef NODE_DEBUG + fprintf(stderr,"mark rxn=0x%x xn=0x%x o=0x%x\n",(long)0,(long)node,(long)node->_private); +#endif + } + } } +VALUE +ruby_xml_node2_wrap(VALUE class, xmlNodePtr xnode) +{ + VALUE obj; + ruby_xml_node *rxn; -/* TODO ptr arg is obsolete, should be removed */ + // This node is already wrapped + if (xnode->_private != NULL) + return (VALUE)xnode->_private; -/* Here's how this works: - * - * All nodes are 'pointer' nodes, but no node owns the xmlNode - * structure they're associated with. Instead, we maintain a - * count of the number of VALUEs out there wrapping a given - * node, in the nodes _private member. When we wrap a node, - * this is incremented. - * - * In ruby_xml_node_free , the count is checked and if it's - * either NULL or 1 (indicating non-wrapped, or that this is - * the last reference) then the node is freed along with the - * ruby_xml_node that points to it. Otherwise, just the - * ruby struct is freed and the node is retained. - * - * This fixes a problem with the old setup whereby ruby_xml_nodes - * with is_ptr = 1 could remain after the node they were pointing - * to had been collected. It also helps to ensure we're - * threadsafe (according to the libxml2 threadsafety rules). - * - * N.B. The XD document pointer is very important - when time - * comes to free a node, we *must* not free nodes that belong - * to a document, or have a parent - they will be freed either - * with the document or with the parent (xmlFreeNode calls - * xmlFreeNodeList on the kids). You need to make sure that - * you keep the XD up to date with the node->doc. - * - * TODO there should be a func that does that. - * - * N.B. You can't do this any more: - * - * node = ruby_xml_node_new3(class, NULL); - * Data_Get_Struct(node, ruby_xml_node, rxn); - * rxn->node = someXmlNode; - * - * You *must* pass in the node when your making the new rxn. - * This saves confusion about who owns what node, and lets the - * refcounts stay consistent. - */ + obj=Data_Make_Struct(class,ruby_xml_node,ruby_xml_node2_mark, + ruby_xml_node2_free,rxn); + + rxn->node=xnode; + xnode->_private=(void*)obj; +#ifdef NODE_DEBUG + fprintf(stderr,"wrap rxn=0x%x xn=0x%x o=0x%x\n",(long)rxn,(long)xnode,(long)obj); +#endif + return obj; +} + VALUE -ruby_xml_node_new3(VALUE class, VALUE xd, xmlNodePtr node, int ptr) { +ruby_xml_node2_new_native(VALUE class, VALUE ns, VALUE name) +{ + VALUE obj; + xmlNodePtr xnode; + xmlNsPtr xns=NULL; ruby_xml_node *rxn; - rxn = ALLOC(ruby_xml_node); - rxn->node = node; - if (node->_private) { - node->_private++; - } else { - node->_private = (void*)1; + if ( ! NIL_P(ns) ) { + Data_Get_Struct(ns,xmlNs,xns); } - - if (NIL_P(xd)) { - rxn->xd = Qnil; - rxn->node->doc = NULL; - } else { - /* Have to set node->doc too so we don't doublefree this node */ - ruby_xml_document *xdoc; - Data_Get_Struct(xd, ruby_xml_document, xdoc); - - rxn->xd = xd; - rxn->node->doc = xdoc->doc; - } + xnode=xmlNewNode(xns,(xmlChar*)StringValuePtr(name)); + xnode->_private=NULL; - return(Data_Wrap_Struct(class, ruby_xml_node_mark, - ruby_xml_node_free, rxn)); + obj= + ruby_xml_node2_wrap(class,xnode); + + rb_obj_call_init(obj,0,NULL); + return obj; } +VALUE +ruby_xml_node2_new_string(VALUE class, VALUE ns, VALUE name, VALUE val) +{ + VALUE obj; + char* value; + obj=ruby_xml_node2_new_native(class,ns,name); + if ( ! NIL_P(val) ) { + if ( TYPE(val) != T_STRING ) + val=rb_obj_as_string(val); + ruby_xml_node_content_set(obj,val); + } + return obj; +} +/* + * call-seq: + * XML::Node.new(name, content = nil) => node + * XML::Node.new_element(name, content = nil) => node + * + * Create a new element node with the specified name, optionally setting + * the node's content. + * backward compatibility for <.5 new + */ +VALUE +ruby_xml_node2_new_string_bc(int argc, VALUE *argv, VALUE class) +{ + VALUE content=Qnil,name=Qnil,rxnode; + switch(argc) { + case 2: + content=argv[1]; + if ( TYPE(content) != T_STRING) + content=rb_obj_as_string(content); + + case 1: + name=check_string_or_symbol( argv[0] ); + return ruby_xml_node2_new_string(class,Qnil,name,content); + default: + rb_raise(rb_eArgError, "wrong number of arguments (1 or 2) given %d",argc); + } +} + /* * call-seq: * node.next => node * * Obtain the next sibling node, if any. @@ -1457,11 +1431,11 @@ } if (node == NULL) { return(Qnil); } else { - return(ruby_xml_node_new_ptr(cXMLNode, rxn->xd, node)); + return(ruby_xml_node2_wrap(cXMLNode, node)); } } /* @@ -1527,11 +1501,11 @@ ret = xmlAddNextSibling(pnode->node, cnode->node); if (ret == NULL) rb_raise(eXMLNodeFailedModify, "unable to add a sibling to the document"); - return(ruby_xml_node_new_ptr(cXMLNode, pnode->xd, ret)); + return(ruby_xml_node2_wrap(cXMLNode, ret)); } /* * call-seq: @@ -1578,11 +1552,11 @@ ruby_xml_node *rxn; Data_Get_Struct(self, ruby_xml_node, rxn); if (rxn->node->nsDef == NULL) return(Qnil); else - return(ruby_xml_ns_new2(cXMLNS, rxn->xd, rxn->node->nsDef)); + return(ruby_xml_ns_new2(cXMLNS, ruby_xml_document_wrap(cXMLDocument,rxn->node->doc), rxn->node->nsDef)); } /* * call-seq: @@ -1640,11 +1614,11 @@ } if (node == NULL) return(Qnil); else - return(ruby_xml_node_new_ptr(cXMLNode, rxn->xd, node)); + return(ruby_xml_node2_wrap(cXMLNode, node)); } /* * call-seq: @@ -1773,11 +1747,11 @@ } if (node == NULL) return(Qnil); else - return(ruby_xml_node_new_ptr(cXMLNode, rxn->xd, node)); + return(ruby_xml_node2_wrap(cXMLNode, node)); } /* * call-seq: @@ -1838,11 +1812,11 @@ ret = xmlAddPrevSibling(pnode->node, cnode->node); if (ret == NULL) rb_raise(eXMLNodeFailedModify, "unable to add a sibling to the document"); - return(ruby_xml_node_new_ptr(cXMLNode, pnode->xd, ret)); + return(ruby_xml_node2_wrap(cXMLNode, ret)); } /* * call-seq: @@ -1899,22 +1873,19 @@ if (attr == NULL) { attr = xmlNewProp(node->node, (xmlChar*)StringValuePtr(key), (xmlChar*)StringValuePtr(val)); if (attr == NULL) return(Qnil); } - return(ruby_xml_attr_new(cXMLAttr, node->xd, attr)); + return(ruby_xml_attr_new(cXMLAttr, attr)); } /* * call-seq: - * node.properties => attributes or nil + * node.properties => attributes * - * Returns the first +XML::Attr+ for this node. Use the - * +name+ and +value+ methods to obtain the attribute's - * data, and the +prev+ and +next+ methods to - * navigate the property list. + * Returns the +XML::Attr+ for this node. */ VALUE ruby_xml_node_properties_get(VALUE self) { ruby_xml_node *node; xmlAttrPtr attr; @@ -1922,14 +1893,14 @@ Data_Get_Struct(self, ruby_xml_node, node); if (node->node->type == XML_ELEMENT_NODE) { attr = node->node->properties; - if (attr == NULL) { - return(Qnil); + if (attr == NULL) { + return(Qnil); } else { - return(ruby_xml_attr_new2(cXMLAttr, node->xd, attr)); + return(ruby_xml_attr_wrap(cXMLAttr, attr)); } } else { return(Qnil); } } @@ -1974,18 +1945,16 @@ * * Search for a namespace by href. */ VALUE ruby_xml_node_search_href(VALUE self, VALUE href) { - ruby_xml_document *doc; ruby_xml_node *node; Check_Type(href, T_STRING); Data_Get_Struct(self, ruby_xml_node, node); - Data_Get_Struct(node->xd, ruby_xml_document, doc); - return(ruby_xml_ns_new2(cXMLNS, node->xd, - xmlSearchNsByHref(doc->doc, node->node, + return(ruby_xml_ns_new2(cXMLNS, ruby_xml_document_wrap(cXMLDocument,node->node->doc), + xmlSearchNsByHref(node->node->doc, node->node, (xmlChar*)StringValuePtr(href)))); } /* @@ -1994,56 +1963,48 @@ * * Search for a namespace by namespace. */ VALUE ruby_xml_node_search_ns(VALUE self, VALUE ns) { - ruby_xml_document *doc; ruby_xml_node *node; Check_Type(ns, T_STRING); Data_Get_Struct(self, ruby_xml_node, node); - Data_Get_Struct(node->xd, ruby_xml_document, doc); - return(ruby_xml_ns_new2(cXMLNS, node->xd, - xmlSearchNs(doc->doc, node->node, - (xmlChar*)StringValuePtr(ns)))); + return(ruby_xml_ns_new2(cXMLNS, + ruby_xml_document_wrap(cXMLDocument,node->node->doc), + xmlSearchNs(node->node->doc, node->node, + (xmlChar*)StringValuePtr(ns)))); } -/* TODO Obsolete, remove */ -VALUE -ruby_xml_node_set_ptr(VALUE node, int is_ptr) { - /* - ruby_xml_node *rxn; - Data_Get_Struct(node, ruby_xml_node, rxn); - rxn->is_ptr = is_ptr; - */ - return(Qtrue); -} - - /* * call-seq: * node.sibling(node) => node * * Add the specified node as a sibling of this node. */ VALUE ruby_xml_node_sibling_set(VALUE self, VALUE rnode) { ruby_xml_node *cnode, *pnode; xmlNodePtr ret; + VALUE obj; if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse) rb_raise(rb_eTypeError, "Must pass an XML::Node object"); Data_Get_Struct(self, ruby_xml_node, pnode); Data_Get_Struct(rnode, ruby_xml_node, cnode); ret = xmlAddSibling(pnode->node, cnode->node); if (ret == NULL) rb_raise(eXMLNodeFailedModify, "unable to add a sibling to the document"); + if (ret->_private==NULL) + obj=ruby_xml_node2_wrap(cXMLNode,ret); + else + obj=(VALUE)ret->_private; - return(ruby_xml_node_new_ptr(cXMLNode, pnode->xd, ret)); + return obj; } /* * call-seq: @@ -2239,34 +2200,39 @@ */ VALUE ruby_xml_node_copy(VALUE self, VALUE deep) { ruby_xml_node *rxn; xmlNode *copy; - + VALUE obj; + Data_Get_Struct(self, ruby_xml_node, rxn); copy = xmlCopyNode( rxn->node, ((deep==Qnil)||(deep==Qfalse))?0:1 ); - copy->_private = (void*)0; - - if (copy == NULL) { + + if (copy == NULL) return Qnil; - } else { - return(ruby_xml_node_new(cXMLNode, copy)); - } + + obj=ruby_xml_node2_wrap(cXMLNode,copy); + copy->_private = (void*) obj; + return obj; } // Rdoc needs to know #ifdef RDOC_NEVER_DEFINED mXML = rb_define_module("XML"); #endif void ruby_init_xml_node(void) { + VALUE singleton; + cXMLNode = rb_define_class_under(mXML, "Node", rb_cObject); eXMLNodeSetNamespace = rb_define_class_under(cXMLNode, "SetNamespace", eXMLError); eXMLNodeFailedModify = rb_define_class_under(cXMLNode, "FailedModify", eXMLError); eXMLNodeUnknownType = rb_define_class_under(cXMLNode, "UnknownType", eXMLError); + + singleton = rb_singleton_class(cXMLNode); rb_define_const(cXMLNode, "SPACE_DEFAULT", INT2NUM(0)); rb_define_const(cXMLNode, "SPACE_PRESERVE", INT2NUM(1)); rb_define_const(cXMLNode, "SPACE_NOT_INHERIT", INT2NUM(-1)); rb_define_const(cXMLNode, "XLINK_ACTUATE_AUTO", INT2NUM(1)); @@ -2279,14 +2245,14 @@ rb_define_const(cXMLNode, "XLINK_TYPE_EXTENDED", INT2NUM(2)); rb_define_const(cXMLNode, "XLINK_TYPE_EXTENDED_SET", INT2NUM(3)); rb_define_const(cXMLNode, "XLINK_TYPE_NONE", INT2NUM(0)); rb_define_const(cXMLNode, "XLINK_TYPE_SIMPLE", INT2NUM(1)); - rb_define_singleton_method(cXMLNode, "new", ruby_xml_node_initialize, -1); - rb_define_singleton_method(cXMLNode, "new_cdata", ruby_xml_node_cdata_initialize, -1); - rb_define_singleton_method(cXMLNode, "new_comment", ruby_xml_node_comment_initialize, -1); + rb_define_singleton_method(cXMLNode, "new2", ruby_xml_node2_new_native, 2); + rb_define_singleton_method(cXMLNode, "new", ruby_xml_node2_new_string_bc, -1); + rb_define_singleton_method(cXMLNode, "new_cdata", ruby_xml_node_new_cdata, -1); + rb_define_singleton_method(cXMLNode, "new_comment", ruby_xml_node_new_comment, -1); - VALUE singleton = rb_singleton_class(cXMLNode); rb_define_alias(singleton, "new_element", "new"); rb_define_method(cXMLNode, "<<", ruby_xml_node_content_add, 1); rb_define_method(cXMLNode, "[]", ruby_xml_node_property_get, 1); rb_define_method(cXMLNode, "[]=", ruby_xml_node_property_set, 2);