While trying to create shallow copies of nodes I have run into some
oddities.  

Firstly I have been unable to access each attribute of a node except
through Xpath (as coded in each_attribute, below).  This is frustrating
and seems to contradict the documentation for Node.properties and
Node.each_attr

More strangely, my each_attribute method only works for nodes returned
from a scan of the document, and not from the original nodes as added to
the document.  The following snippet should illustrate this:

node1 = XML::Node.new('node1')
node1['x'] = 'y'
node1['z'] = 'a'
doc.root << node1
node1.each_attribute do |name, val|
  # Will never reach this point!
end

doc.each do |node|
  if node.name == 'node1'
    node.each_attribute do |name, val|
      # Reaches this point for each attribute
    end
  end
end

There is no obvious difference between the 'node1' object, and the
'node' object yielded by doc.each.  They both print the same and both
yield similar looking doc objects, yet they have puzzlingly different
semantics.

I write in the hope that someone can explain, document and/or correct
this, and if not, to ensure that this strange behaviour is at least
described in this list.


Here is a simple test case to illustrate the issue.

require 'xml/libxml'

def each_attribute(node)
  begin
    attrs = node.find('./@*')
  rescue TypeError
    # Do nothing.  This error is mistakenly? raised when no matching 
    # elements can be found
    return
  end
  
  attrs.each do |elem|
    yield elem.name, elem.value
  end
end

def shallowcopy(old)
  node = XML::Node.new(old.name)
  each_attribute(old) do |name, value|
    node[name] = value
  end
  node
end

doc = XML::Document.new
root = XML::Node.new('root')
node1 = XML::Node.new('node1')
node2 = XML::Node.new('node2')
node1['type'] = 'x'
node2['type'] = 'y'
node1['value'] = 'xval'
node2['value'] = 'yval'
doc.root = root
root << node1
root << node2

puts "NODE1        : #{node1} :NODE1"
puts "COPY OF NODE1: #{shallowcopy(node1)}                       :COPY OF NODE1"

doc.root.each_child do |node|
  if node.name == 'node1'
    puts "NODE1        : #{node1} :NODE1"
    puts "COPY OF NODE1: #{shallowcopy(node)} :COPY OF NODE1"
  end
end

And this is the output generated.  Note that the first copy of node1 has
no attributes, while the second does.

NODE1        : <node1 type="x" value="xval"/> :NODE1
COPY OF NODE1: <node1/>                       :COPY OF NODE1
NODE1        : <node1 type="x" value="xval"/> :NODE1
COPY OF NODE1: <node1 type="x" value="xval"/> :COPY OF NODE1

__
Marc

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
libxml-devel mailing list
libxml-devel@rubyforge.org
http://rubyforge.org/mailman/listinfo/libxml-devel

Reply via email to