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);