libxml-ruby 0.3.8 → 0.3.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- /* $Id: ruby_xml_node.c,v 1.3 2006/04/12 12:08:39 roscopeco Exp $ */
1
+ /* $Id: ruby_xml_node.c,v 1.9 2006/11/20 01:22:07 roscopeco Exp $ */
2
2
 
3
3
  /* Please see the LICENSE file for copyright and distribution information */
4
4
 
@@ -10,6 +10,15 @@ VALUE eXMLNodeSetNamespace;
10
10
  VALUE eXMLNodeFailedModify;
11
11
  VALUE eXMLNodeUnknownType;
12
12
 
13
+ static VALUE
14
+ check_string_or_symbol( VALUE val ) {
15
+ if( TYPE(val) != T_STRING && TYPE(val) != T_SYMBOL ) {
16
+ rb_raise(rb_eTypeError, "wrong argument type %s (expected String or Symbol)",
17
+ rb_obj_classname(val) );
18
+ }
19
+ return rb_obj_as_string( val );
20
+ }
21
+
13
22
  /*
14
23
  * call-seq:
15
24
  * node.attribute? => (true|false)
@@ -122,7 +131,7 @@ ruby_xml_node_comment_q(VALUE self) {
122
131
 
123
132
  /*
124
133
  * call-seq:
125
- * node << ("string" | node)
134
+ * node << ("string" | node) => node
126
135
  *
127
136
  * Add the specified string or XML::Node to this node's
128
137
  * content.
@@ -134,17 +143,18 @@ ruby_xml_node_content_add(VALUE self, VALUE obj) {
134
143
 
135
144
  Data_Get_Struct(self, ruby_xml_node, node);
136
145
  if (rb_obj_is_kind_of(obj, cXMLNode)) {
137
- return(ruby_xml_node_child_set(self, obj));
146
+ ruby_xml_node_child_set(self, obj);
147
+ return(self);
138
148
  } else if (TYPE(obj) == T_STRING) {
139
149
  xmlNodeAddContent(node->node, (xmlChar*)StringValuePtr(obj));
140
- return(obj);
150
+ return(self);
141
151
  } else {
142
152
  str = rb_obj_as_string(obj);
143
153
  if (NIL_P(str) || TYPE(str) != T_STRING)
144
154
  rb_raise(rb_eTypeError, "invalid argument: must be string or XML::Node");
145
155
 
146
156
  xmlNodeAddContent(node->node, (xmlChar*)StringValuePtr(str));
147
- return(obj);
157
+ return(self);
148
158
  }
149
159
  }
150
160
 
@@ -206,11 +216,6 @@ ruby_xml_node_content_stripped_get(VALUE self) {
206
216
  return(rb_str_new2((const char*)xmlNodeGetContent(rxn->node)));
207
217
  }
208
218
 
209
- ////////////////////////////////////////////////////
210
- // TODO This whole child thing seems to work in some odd ways.
211
- // Try setting child= to a node with multiple children,
212
- // then get it back through child= .
213
-
214
219
  /*
215
220
  * call-seq:
216
221
  * node.child => node
@@ -252,7 +257,7 @@ ruby_xml_node_child_get(VALUE self) {
252
257
  if (tmp == NULL)
253
258
  return(Qnil);
254
259
  else
255
- return(ruby_xml_node_new2(cXMLNode, node->xd, tmp));
260
+ return(ruby_xml_node_new_ptr(cXMLNode, node->xd, tmp));
256
261
  }
257
262
 
258
263
 
@@ -300,6 +305,7 @@ ruby_xml_node_child_q(VALUE self) {
300
305
  }
301
306
 
302
307
 
308
+ // TODO Fixes below should be applied to sibling, prev, etc ?
303
309
  /*
304
310
  * call-seq:
305
311
  * node.child = node
@@ -309,20 +315,45 @@ ruby_xml_node_child_q(VALUE self) {
309
315
  VALUE
310
316
  ruby_xml_node_child_set(VALUE self, VALUE rnode) {
311
317
  ruby_xml_node *cnode, *pnode;
312
- xmlNodePtr ret;
318
+ xmlNodePtr chld, ret;
319
+ ruby_xml_document *pdoc, *cdoc;
320
+ int ptr;
313
321
 
314
322
  if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
315
323
  rb_raise(rb_eTypeError, "Must pass an XML::Node object");
316
324
 
317
325
  Data_Get_Struct(self, ruby_xml_node, pnode);
318
326
  Data_Get_Struct(rnode, ruby_xml_node, cnode);
319
-
320
- ret = xmlAddChild(pnode->node, cnode->node);
327
+
328
+ chld = cnode->node;
329
+
330
+ // Only copy if both nodes are in documents, which are different.
331
+ if (pnode->xd && pnode->xd != Qnil) {
332
+ Data_Get_Struct(pnode->xd, ruby_xml_document, pdoc);
333
+ if (cnode->xd && cnode->xd != Qnil) {
334
+ Data_Get_Struct(cnode->xd, ruby_xml_document, cdoc);
335
+ if (cdoc->doc != pdoc->doc) {
336
+ chld = xmlDocCopyNode(chld, pdoc->doc, 1);
337
+ chld->_private = 0;
338
+ ptr = 1;
339
+ }
340
+ } else {
341
+ chld = xmlDocCopyNode(chld, pdoc->doc, 1);
342
+ chld->_private = 0;
343
+ ptr = 1;
344
+ }
345
+ } else {
346
+ chld->doc = NULL;
347
+ }
348
+
349
+ ret = xmlAddChild(pnode->node, chld);
321
350
  if (ret == NULL)
322
351
  rb_raise(eXMLNodeFailedModify, "unable to add a child to the document");
352
+
353
+ cnode->node = ret;
354
+ cnode->xd = pnode->xd;
323
355
 
324
- ruby_xml_node_set_ptr(rnode, 1);
325
- return(ruby_xml_node_new2(cXMLNode, pnode->xd, ret));
356
+ return(rnode);
326
357
  }
327
358
 
328
359
  ////////////////////////////////////////////////
@@ -342,6 +373,9 @@ ruby_xml_node_doc(VALUE self) {
342
373
  VALUE docobj;
343
374
 
344
375
  Data_Get_Struct(self, ruby_xml_node, rxn);
376
+
377
+ if (rxn->xd)
378
+ return(rxn->xd);
345
379
 
346
380
  switch (rxn->node->type) {
347
381
  case XML_DOCUMENT_NODE:
@@ -634,18 +668,18 @@ VALUE
634
668
  ruby_xml_node_find_first(int argc, VALUE *argv, VALUE self) {
635
669
  VALUE ns = ruby_xml_node_find(argc, argv, self);
636
670
  ruby_xml_node_set *rxnset;
671
+ VALUE nodeobj;
637
672
 
638
673
  Data_Get_Struct(ns, ruby_xml_node_set, rxnset);
639
674
  if (rxnset->node_set == NULL || rxnset->node_set->nodeNr < 1)
640
675
  return(Qnil);
641
676
 
642
- VALUE nodeobj;
643
677
  switch(rxnset->node_set->nodeTab[0]->type) {
644
678
  case XML_ATTRIBUTE_NODE:
645
679
  nodeobj = ruby_xml_attr_new2(cXMLAttr, rxnset->xd, (xmlAttrPtr)rxnset->node_set->nodeTab[0]);
646
680
  break;
647
681
  default:
648
- nodeobj = ruby_xml_node_new2(cXMLNode, rxnset->xd, rxnset->node_set->nodeTab[0]);
682
+ nodeobj = ruby_xml_node_new_ptr(cXMLNode, rxnset->xd, rxnset->node_set->nodeTab[0]);
649
683
  }
650
684
 
651
685
  return(nodeobj);
@@ -670,12 +704,19 @@ ruby_xml_node_fragment_q(VALUE self) {
670
704
 
671
705
 
672
706
  void ruby_xml_node_free(ruby_xml_node *rxn) {
673
- if (rxn->node != NULL && !rxn->is_ptr) {
674
- xmlUnlinkNode(rxn->node);
675
- xmlFreeNode(rxn->node);
676
- rxn->node = NULL;
707
+ if (rxn->node != NULL && // got a node?
708
+ rxn->node->parent == NULL && // unparented (otherwise, it gets freed with parent)
709
+ rxn->node->doc == NULL) { // No document? (otherwise, freed with doc)
710
+ if ((int)rxn->node->_private <= 1) {
711
+ // is null or last reference,
712
+ xmlFreeNode(rxn->node);
713
+ } else {
714
+ // other pointers remain
715
+ rxn->node->_private--;
716
+ }
677
717
  }
678
718
 
719
+ rxn->node = NULL;
679
720
  free(rxn);
680
721
  }
681
722
 
@@ -718,14 +759,16 @@ ruby_xml_node_html_doc_q(VALUE self) {
718
759
  /*
719
760
  * call-seq:
720
761
  * XML::Node.new(name, content = nil) => node
762
+ * XML::Node.new_element(name, content = nil) => node
721
763
  *
722
- * Create a new node with the specified name, optionally setting
764
+ * Create a new element node with the specified name, optionally setting
723
765
  * the node's content.
724
766
  */
725
767
  VALUE
726
768
  ruby_xml_node_initialize(int argc, VALUE *argv, VALUE class) {
727
769
  ruby_xml_node *rxn;
728
770
  VALUE name, node, str;
771
+ xmlNodePtr newxn;
729
772
 
730
773
  str = Qnil;
731
774
 
@@ -746,11 +789,13 @@ ruby_xml_node_initialize(int argc, VALUE *argv, VALUE class) {
746
789
  * the object. Sneaky, but effective. Probably should use a goto
747
790
  * instead. */
748
791
  case 1:
749
- name = argv[0];
750
- Check_Type(name, T_STRING);
751
- node = ruby_xml_node_new(class, NULL);
792
+ name = check_string_or_symbol( argv[0] );
793
+ newxn = xmlNewNode(NULL, (xmlChar*)StringValuePtr(name));
794
+ node = ruby_xml_node_new(class, newxn);
795
+
752
796
  Data_Get_Struct(node, ruby_xml_node, rxn);
753
- rxn->node = xmlNewNode(NULL, (xmlChar*)StringValuePtr(name));
797
+
798
+ /* TODO How would this happen? Shouldn't we raise on it anyway? */
754
799
  if (rxn->node == NULL)
755
800
  return(Qnil);
756
801
 
@@ -766,7 +811,86 @@ ruby_xml_node_initialize(int argc, VALUE *argv, VALUE class) {
766
811
  return(node);
767
812
  }
768
813
 
814
+ /*
815
+ * call-seq:
816
+ * XML::Node.new_cdata(content = nil) => node
817
+ *
818
+ * Create a new #CDATA node, optionally setting
819
+ * the node's content.
820
+ */
821
+ VALUE
822
+ ruby_xml_node_cdata_initialize(int argc, VALUE *argv, VALUE class) {
823
+ xmlNode *xnode;
824
+ VALUE node, str;
825
+
826
+ str = Qnil;
827
+
828
+ switch(argc) {
829
+ case 1:
830
+ str = argv[0];
831
+ Check_Type(str, T_STRING);
832
+ if (!NIL_P(str)) {
833
+ xnode = xmlNewCDataBlock(NULL, (xmlChar*)StringValuePtr(str), xmlStrlen((xmlChar*)StringValuePtr(str)));
834
+ } else {
835
+ xnode = xmlNewCDataBlock(NULL, NULL , 0);
836
+ }
769
837
 
838
+ if (xnode == NULL)
839
+ return(Qnil);
840
+
841
+ node = ruby_xml_node_new(class, xnode);
842
+
843
+ break;
844
+
845
+ default:
846
+ rb_raise(rb_eArgError, "wrong number of arguments (1)");
847
+ }
848
+
849
+ return(node);
850
+ }
851
+
852
+
853
+ /*
854
+ * call-seq:
855
+ * XML::Node.new_comment(content = nil) => node
856
+ *
857
+ * Create a new comment node, optionally setting
858
+ * the node's content.
859
+ *
860
+ */
861
+ VALUE
862
+ ruby_xml_node_comment_initialize(int argc, VALUE *argv, VALUE class) {
863
+ xmlNode *xnode;
864
+ VALUE node, str;
865
+
866
+ str = Qnil;
867
+
868
+ switch(argc) {
869
+ case 1:
870
+ str = argv[0];
871
+ Check_Type(str, T_STRING);
872
+ // TODO xmlNewComment wrongly? adds \n before and after the comment
873
+ if (!NIL_P(str)) {
874
+ xnode = xmlNewComment((xmlChar*)StringValuePtr(str));
875
+ } else {
876
+ xnode = xmlNewComment(NULL);
877
+ }
878
+
879
+ if (xnode == NULL)
880
+ return(Qnil);
881
+
882
+ node = ruby_xml_node_new(class, xnode);
883
+
884
+ break;
885
+
886
+ default:
887
+ rb_raise(rb_eArgError, "wrong number of arguments (1)");
888
+ }
889
+
890
+ return(node);
891
+ }
892
+
893
+
770
894
  /*
771
895
  * call-seq:
772
896
  * node.lang => "string"
@@ -850,7 +974,7 @@ ruby_xml_node_last_get(VALUE self) {
850
974
  if (node == NULL)
851
975
  return(Qnil);
852
976
  else
853
- return(ruby_xml_node_new2(cXMLNode, rxn->xd, node));
977
+ return(ruby_xml_node_new_ptr(cXMLNode, rxn->xd, node));
854
978
  }
855
979
 
856
980
 
@@ -1213,33 +1337,85 @@ ruby_xml_node_namespace_q(VALUE self) {
1213
1337
  return(Qfalse);
1214
1338
  }
1215
1339
 
1216
-
1340
+ /* TODO new_ptr and new3 are obsolete, should be consolidated */
1217
1341
  VALUE
1218
1342
  ruby_xml_node_new(VALUE class, xmlNodePtr node) {
1219
- ruby_xml_node *rxn;
1343
+ return ruby_xml_node_new_ptr(class, Qnil, node);
1344
+ }
1220
1345
 
1221
- rxn = ALLOC(ruby_xml_node);
1222
- rxn->is_ptr = 0;
1223
- rxn->node = node;
1224
- rxn->xd = Qnil;
1225
- return(Data_Wrap_Struct(class, ruby_xml_node_mark,
1226
- ruby_xml_node_free, rxn));
1346
+
1347
+ VALUE
1348
+ ruby_xml_node_new_ptr(VALUE class, VALUE xd, xmlNodePtr node) {
1349
+ return ruby_xml_node_new3(class, xd, node, 1);
1227
1350
  }
1228
1351
 
1229
1352
 
1353
+ /* TODO ptr arg is obsolete, should be removed */
1354
+
1355
+ /* Here's how this works:
1356
+ *
1357
+ * All nodes are 'pointer' nodes, but no node owns the xmlNode
1358
+ * structure they're associated with. Instead, we maintain a
1359
+ * count of the number of VALUEs out there wrapping a given
1360
+ * node, in the nodes _private member. When we wrap a node,
1361
+ * this is incremented.
1362
+ *
1363
+ * In ruby_xml_node_free , the count is checked and if it's
1364
+ * either NULL or 1 (indicating non-wrapped, or that this is
1365
+ * the last reference) then the node is freed along with the
1366
+ * ruby_xml_node that points to it. Otherwise, just the
1367
+ * ruby struct is freed and the node is retained.
1368
+ *
1369
+ * This fixes a problem with the old setup whereby ruby_xml_nodes
1370
+ * with is_ptr = 1 could remain after the node they were pointing
1371
+ * to had been collected. It also helps to ensure we're
1372
+ * threadsafe (according to the libxml2 threadsafety rules).
1373
+ *
1374
+ * N.B. The XD document pointer is very important - when time
1375
+ * comes to free a node, we *must* not free nodes that belong
1376
+ * to a document, or have a parent - they will be freed either
1377
+ * with the document or with the parent (xmlFreeNode calls
1378
+ * xmlFreeNodeList on the kids). You need to make sure that
1379
+ * you keep the XD up to date with the node->doc.
1380
+ *
1381
+ * TODO there should be a func that does that.
1382
+ *
1383
+ * N.B. You can't do this any more:
1384
+ *
1385
+ * node = ruby_xml_node_new3(class, NULL);
1386
+ * Data_Get_Struct(node, ruby_xml_node, rxn);
1387
+ * rxn->node = someXmlNode;
1388
+ *
1389
+ * You *must* pass in the node when your making the new rxn.
1390
+ * This saves confusion about who owns what node, and lets the
1391
+ * refcounts stay consistent.
1392
+ */
1230
1393
  VALUE
1231
- ruby_xml_node_new2(VALUE class, VALUE xd, xmlNodePtr node) {
1394
+ ruby_xml_node_new3(VALUE class, VALUE xd, xmlNodePtr node, int ptr) {
1232
1395
  ruby_xml_node *rxn;
1233
-
1234
1396
  rxn = ALLOC(ruby_xml_node);
1235
- rxn->is_ptr = 1;
1397
+
1236
1398
  rxn->node = node;
1237
- if (NIL_P(xd))
1399
+ if (node->_private) {
1400
+ node->_private++;
1401
+ } else {
1402
+ node->_private = (void*)1;
1403
+ }
1404
+
1405
+ if (NIL_P(xd)) {
1238
1406
  rxn->xd = Qnil;
1239
- else
1407
+ rxn->node->doc = NULL;
1408
+ } else {
1409
+ /* Have to set node->doc too so we don't doublefree this node */
1410
+ ruby_xml_document *xdoc;
1411
+ Data_Get_Struct(xd, ruby_xml_document, xdoc);
1412
+
1240
1413
  rxn->xd = xd;
1414
+ rxn->node->doc = xdoc->doc;
1415
+ }
1416
+
1241
1417
  return(Data_Wrap_Struct(class, ruby_xml_node_mark,
1242
- ruby_xml_node_free, rxn));
1418
+ ruby_xml_node_free, rxn));
1243
1419
  }
1244
1420
 
1245
1421
 
@@ -1280,10 +1456,11 @@ ruby_xml_node_next_get(VALUE self) {
1280
1456
  break;
1281
1457
  }
1282
1458
 
1283
- if (node == NULL)
1459
+ if (node == NULL) {
1284
1460
  return(Qnil);
1285
- else
1286
- return(ruby_xml_node_new2(cXMLNode, rxn->xd, node));
1461
+ } else {
1462
+ return(ruby_xml_node_new_ptr(cXMLNode, rxn->xd, node));
1463
+ }
1287
1464
  }
1288
1465
 
1289
1466
 
@@ -1331,6 +1508,31 @@ ruby_xml_node_next_q(VALUE self) {
1331
1508
  }
1332
1509
 
1333
1510
 
1511
+ /*
1512
+ * call-seq:
1513
+ * node.next = node
1514
+ *
1515
+ * Insert the specified node as this node's next sibling.
1516
+ */
1517
+ VALUE
1518
+ ruby_xml_node_next_set(VALUE self, VALUE rnode) {
1519
+ ruby_xml_node *cnode, *pnode;
1520
+ xmlNodePtr ret;
1521
+
1522
+ if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
1523
+ rb_raise(rb_eTypeError, "Must pass an XML::Node object");
1524
+
1525
+ Data_Get_Struct(self, ruby_xml_node, pnode);
1526
+ Data_Get_Struct(rnode, ruby_xml_node, cnode);
1527
+
1528
+ ret = xmlAddNextSibling(pnode->node, cnode->node);
1529
+ if (ret == NULL)
1530
+ rb_raise(eXMLNodeFailedModify, "unable to add a sibling to the document");
1531
+
1532
+ return(ruby_xml_node_new_ptr(cXMLNode, pnode->xd, ret));
1533
+ }
1534
+
1535
+
1334
1536
  /*
1335
1537
  * call-seq:
1336
1538
  * node.notation? => (true|false)
@@ -1440,7 +1642,7 @@ ruby_xml_node_parent_get(VALUE self) {
1440
1642
  if (node == NULL)
1441
1643
  return(Qnil);
1442
1644
  else
1443
- return(ruby_xml_node_new2(cXMLNode, rxn->xd, node));
1645
+ return(ruby_xml_node_new_ptr(cXMLNode, rxn->xd, node));
1444
1646
  }
1445
1647
 
1446
1648
 
@@ -1562,18 +1764,18 @@ ruby_xml_node_prev_get(VALUE self) {
1562
1764
  case XML_ATTRIBUTE_NODE:
1563
1765
  {
1564
1766
  xmlAttrPtr attr = (xmlAttrPtr) rxn->node;
1565
- node = (xmlNodePtr) attr->next;
1767
+ node = (xmlNodePtr) attr->prev;
1566
1768
  }
1567
1769
  break;
1568
1770
  default:
1569
- node = rxn->node->next;
1771
+ node = rxn->node->prev;
1570
1772
  break;
1571
1773
  }
1572
1774
 
1573
1775
  if (node == NULL)
1574
1776
  return(Qnil);
1575
1777
  else
1576
- return(ruby_xml_node_new2(cXMLNode, rxn->xd, node));
1778
+ return(ruby_xml_node_new_ptr(cXMLNode, rxn->xd, node));
1577
1779
  }
1578
1780
 
1579
1781
 
@@ -1602,11 +1804,11 @@ ruby_xml_node_prev_q(VALUE self) {
1602
1804
  case XML_ATTRIBUTE_NODE:
1603
1805
  {
1604
1806
  xmlAttrPtr attr = (xmlAttrPtr) rxn->node;
1605
- node = (xmlNodePtr) attr->next;
1807
+ node = (xmlNodePtr) attr->prev;
1606
1808
  }
1607
1809
  break;
1608
1810
  default:
1609
- node = rxn->node->next;
1811
+ node = rxn->node->prev;
1610
1812
  break;
1611
1813
  }
1612
1814
 
@@ -1617,6 +1819,31 @@ ruby_xml_node_prev_q(VALUE self) {
1617
1819
  }
1618
1820
 
1619
1821
 
1822
+ /*
1823
+ * call-seq:
1824
+ * node.prev = node
1825
+ *
1826
+ * Insert the specified node as this node's previous sibling.
1827
+ */
1828
+ VALUE
1829
+ ruby_xml_node_prev_set(VALUE self, VALUE rnode) {
1830
+ ruby_xml_node *cnode, *pnode;
1831
+ xmlNodePtr ret;
1832
+
1833
+ if (rb_obj_is_kind_of(rnode, cXMLNode) == Qfalse)
1834
+ rb_raise(rb_eTypeError, "Must pass an XML::Node object");
1835
+
1836
+ Data_Get_Struct(self, ruby_xml_node, pnode);
1837
+ Data_Get_Struct(rnode, ruby_xml_node, cnode);
1838
+
1839
+ ret = xmlAddPrevSibling(pnode->node, cnode->node);
1840
+ if (ret == NULL)
1841
+ rb_raise(eXMLNodeFailedModify, "unable to add a sibling to the document");
1842
+
1843
+ return(ruby_xml_node_new_ptr(cXMLNode, pnode->xd, ret));
1844
+ }
1845
+
1846
+
1620
1847
  /*
1621
1848
  * call-seq:
1622
1849
  * node.property("name") => "string"
@@ -1630,8 +1857,8 @@ ruby_xml_node_property_get(VALUE self, VALUE prop) {
1630
1857
  xmlChar *p;
1631
1858
  VALUE r;
1632
1859
 
1633
- Check_Type(prop, T_STRING);
1634
-
1860
+ prop = check_string_or_symbol( prop );
1861
+
1635
1862
  Data_Get_Struct(self, ruby_xml_node, rxn);
1636
1863
  p = xmlGetProp(rxn->node, (xmlChar*)StringValuePtr(prop));
1637
1864
 
@@ -1655,12 +1882,10 @@ ruby_xml_node_property_get(VALUE self, VALUE prop) {
1655
1882
  VALUE
1656
1883
  ruby_xml_node_property_set(VALUE self, VALUE key, VALUE val) {
1657
1884
  ruby_xml_node *node;
1658
- ruby_xml_attr *rxa;
1659
1885
  xmlAttrPtr attr;
1660
- VALUE rattr;
1661
1886
 
1662
- Data_Get_Struct(self, ruby_xml_node, node);
1663
- Check_Type(key, T_STRING);
1887
+ key = check_string_or_symbol( key );
1888
+ Data_Get_Struct(self, ruby_xml_node, node);
1664
1889
 
1665
1890
  if( val == Qnil ) {
1666
1891
  attr = xmlSetProp(node->node, (xmlChar*)StringValuePtr(key), NULL);
@@ -1676,10 +1901,7 @@ ruby_xml_node_property_set(VALUE self, VALUE key, VALUE val) {
1676
1901
  if (attr == NULL)
1677
1902
  return(Qnil);
1678
1903
  }
1679
- rattr = ruby_xml_attr_new(cXMLAttr, node->xd, attr);
1680
- Data_Get_Struct(rattr, ruby_xml_attr, rxa);
1681
- rxa->is_ptr = 1;
1682
- return(rattr);
1904
+ return(ruby_xml_attr_new(cXMLAttr, node->xd, attr));
1683
1905
  }
1684
1906
 
1685
1907
 
@@ -1778,11 +2000,14 @@ ruby_xml_node_search_ns(VALUE self, VALUE ns) {
1778
2000
  }
1779
2001
 
1780
2002
 
2003
+ /* TODO Obsolete, remove */
1781
2004
  VALUE
1782
2005
  ruby_xml_node_set_ptr(VALUE node, int is_ptr) {
2006
+ /*
1783
2007
  ruby_xml_node *rxn;
1784
2008
  Data_Get_Struct(node, ruby_xml_node, rxn);
1785
2009
  rxn->is_ptr = is_ptr;
2010
+ */
1786
2011
  return(Qtrue);
1787
2012
  }
1788
2013
 
@@ -1808,8 +2033,7 @@ ruby_xml_node_sibling_set(VALUE self, VALUE rnode) {
1808
2033
  if (ret == NULL)
1809
2034
  rb_raise(eXMLNodeFailedModify, "unable to add a sibling to the document");
1810
2035
 
1811
- cnode->is_ptr = 1;
1812
- return(ruby_xml_node_new2(cXMLNode, pnode->xd, ret));
2036
+ return(ruby_xml_node_new_ptr(cXMLNode, pnode->xd, ret));
1813
2037
  }
1814
2038
 
1815
2039
 
@@ -1999,8 +2223,6 @@ ruby_xml_node_xinclude_start_q(VALUE self) {
1999
2223
  }
2000
2224
 
2001
2225
 
2002
- // TODO my gut tells me this is where our sigseg etc. problems start...
2003
-
2004
2226
  /*
2005
2227
  * call-seq:
2006
2228
  * node.copy => node
@@ -2009,19 +2231,18 @@ ruby_xml_node_xinclude_start_q(VALUE self) {
2009
2231
  */
2010
2232
  VALUE
2011
2233
  ruby_xml_node_copy(VALUE self, VALUE deep) { /* MUFF */
2012
- ruby_xml_node *rxn, *n_rxn;
2013
- VALUE n_node;
2234
+ ruby_xml_node *rxn;
2235
+ xmlNode *copy;
2014
2236
 
2015
2237
  Data_Get_Struct(self, ruby_xml_node, rxn);
2016
-
2017
- n_node = ruby_xml_node_new(cXMLNode, NULL); // class??
2018
- Data_Get_Struct(n_node, ruby_xml_node, n_rxn);
2019
-
2020
- n_rxn->node = xmlCopyNode( rxn->node, ((deep==Qnil)||(deep==Qfalse))?0:1 );
2021
- if (rxn->node == NULL)
2022
- return(Qnil);
2023
-
2024
- return n_node;
2238
+ copy = xmlCopyNode( rxn->node, ((deep==Qnil)||(deep==Qfalse))?0:1 );
2239
+ copy->_private = (void*)0;
2240
+
2241
+ if (copy == NULL) {
2242
+ return Qnil;
2243
+ } else {
2244
+ return(ruby_xml_node_new(cXMLNode, copy));
2245
+ }
2025
2246
  }
2026
2247
 
2027
2248
 
@@ -2053,7 +2274,12 @@ ruby_init_xml_node(void) {
2053
2274
  rb_define_const(cXMLNode, "XLINK_TYPE_SIMPLE", INT2NUM(1));
2054
2275
 
2055
2276
  rb_define_singleton_method(cXMLNode, "new", ruby_xml_node_initialize, -1);
2056
-
2277
+ rb_define_singleton_method(cXMLNode, "new_cdata", ruby_xml_node_cdata_initialize, -1);
2278
+ rb_define_singleton_method(cXMLNode, "new_comment", ruby_xml_node_comment_initialize, -1);
2279
+
2280
+ VALUE singleton = rb_singleton_class(cXMLNode);
2281
+ rb_define_alias(singleton, "new_element", "new");
2282
+
2057
2283
  rb_define_method(cXMLNode, "<<", ruby_xml_node_content_add, 1);
2058
2284
  rb_define_method(cXMLNode, "[]", ruby_xml_node_property_get, 1);
2059
2285
  rb_define_method(cXMLNode, "[]=", ruby_xml_node_property_set, 2);
@@ -2104,6 +2330,7 @@ ruby_init_xml_node(void) {
2104
2330
  rb_define_method(cXMLNode, "namespace=", ruby_xml_node_namespace_set, -1);
2105
2331
  rb_define_method(cXMLNode, "next", ruby_xml_node_next_get, 0);
2106
2332
  rb_define_method(cXMLNode, "next?", ruby_xml_node_next_q, 0);
2333
+ rb_define_method(cXMLNode, "next=", ruby_xml_node_next_set, 1);
2107
2334
  rb_define_method(cXMLNode, "node_type", ruby_xml_node_type, 0);
2108
2335
  rb_define_method(cXMLNode, "node_type_name", ruby_xml_node_type_name, 0);
2109
2336
  rb_define_method(cXMLNode, "notation?", ruby_xml_node_notation_q, 0);
@@ -2118,6 +2345,7 @@ ruby_init_xml_node(void) {
2118
2345
  rb_define_method(cXMLNode, "pointer", ruby_xml_node_pointer, 1);
2119
2346
  rb_define_method(cXMLNode, "prev", ruby_xml_node_prev_get, 0);
2120
2347
  rb_define_method(cXMLNode, "prev?", ruby_xml_node_prev_q, 0);
2348
+ rb_define_method(cXMLNode, "prev=", ruby_xml_node_prev_set, 1);
2121
2349
  rb_define_method(cXMLNode, "property", ruby_xml_node_property_get, 1);
2122
2350
  rb_define_method(cXMLNode, "properties", ruby_xml_node_properties_get, 0);
2123
2351
  rb_define_method(cXMLNode, "properties?", ruby_xml_node_properties_q, 0);