Hello Perl hackers,

I have an application that I originally wrote using XML::DOM. However, due limitations in XML::XSLT and XML::DOM::XPath (which use XML::DOM objects) I have decided to convert the application to use XML::LibXML and XML::LibXSLT. Since most of the methods are the same, the changes were not too large.

In my application, I need to subclass the XML::LibXML::Element class. My class provides wrapper methods around the DOM methods, which I use to simplify access to data members in my objects (data members in my objects are implemented as subelements in an XML::LibXML::Element). There are a number of reasons for why I am doing this, but I won't get into them here.

My question is, is it ok to do this? I didn't have any problems subclassing XML::DOM::Element, but when I switched over to XML::LibXML, I ran into a strange problem. My application is quite complex, so I can't include code samples, but I have isolated the problem in a simple example (see "readmore" section below).

In my application I bless an XML::LibXML::Element object into my class, which we'll call "Foo". Then I insert it into a document. My problem is that, when I use the parentNode() method to get a, reference to the a Foo object from one of its subelements, I get a reference to an XML::LibXML::Element object, not my application's Foo object. At first I thought that the XML::LibXML package was re-blessing the reference into the XML::LibXML::Element class somewhere, but looking at the references, they are not the same objects (i.e. the references have different values). I think I could work around this if I could just find another way to get from a subelemnt to its parent element, without losing the reference to the original parent element. (note: I also tried using $obj->findnodes('..'), but with no success.)

Thank you and regards.
-brian

CommonObject.pm - base class for most of the classes in my application. Contains methods for accessing the data members of my objects, which are implemented as subelements of an XML::LibXML::Element objects blessed into my class.

package CommonObject; use strict; use XML::LibXML; use vars qw{ @ISA }; @ISA= qw{ XML::LibXML::Element }; sub createTextField { my ($self, $fieldname, $fieldvalue) = @_; my ($newelem, $textnode); if (defined($fieldname)) { $newelem = XML::LibXML::Element->new($fieldname); } else { return undef; } # The Perl XML::LibXML implementation requires that a text node's +data be # set to a defined value, so we set it to an empty string if $fiel +dvalue # is undefined. This will happen if an initial text field value i +s not # specified. # $fieldvalue = '' unless (defined($fieldvalue)); if ($newelem) { $textnode = XML::LibXML::Text->new($fieldvalue); } else { return undef; } if (defined($textnode)) { $newelem->appendChild($textnode); $self->appendChild($newelem); } else { return undef; } return $newelem; } sub setTextFieldValue { my $self = shift; my $fieldname = shift; my $newvalue = shift; if (defined($fieldname)) { my $nodelist = $self->findnodes("./$fieldname"); my $node = $nodelist->item(0) if ($nodelist->size() > 0); return undef unless defined($node); my $textnode = $node->getFirstChild(); if ($textnode->isa('XML::LibXML::Text')) { my $oldvalue = $textnode->getData(); if (defined($oldvalue)) { $oldvalue =~ s/^\s+//; # Cut leading whitespace. $oldvalue =~ s/\s+$//; # Cut trailing whitespace. } else { $oldvalue = ''; } if (defined($newvalue)) { $textnode->setData($newvalue); } else { $textnode->setData(''); } return $oldvalue; } else { return undef; } } return undef; } sub getTextFieldValue { my $self = shift; my $fieldname = shift; if (defined($fieldname)) { my $node; foreach my $child ($self->childNodes()) { if ($child->isa('XML::LibXML::Element')) { my $name = $child->localname(); if ($name eq $fieldname) { $node = $child; last; } } } return undef unless defined($node); my $textnode = $node->getFirstChild(); #printf(qq{Found Text node: $textnode with data "%s"\n}, # $textnode->getData()); if (defined($textnode) && $textnode->isa('XML::LibXML::Text')) + { my $value = $textnode->getData(); if (defined($value)) { $value =~ s/^\s+//; # Cut leading whitespace. $value =~ s/\s+$//; # Cut trailing whitespace. } else { $value = ''; } return $value; } else { return ''; } } return undef; } 1;

Foo.pm - simplified example of one of the classes in my application.

package Foo; use strict; use XML::LibXML; use CommonObject; use vars qw{ @ISA }; @ISA = qw{ CommonObject }; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = XML::LibXML::Element->new('Foo'); #my $doc = XML::LibXML::Document->new(); #$doc->setDocumentElement($self); bless($self, $class); $self->createTextField('Name'); return $self; } sub setName { my $self = shift; my $name = shift; return $self->setTextFieldValue('Name', $name); } sub getName { my $self = shift; return $self->getTextFieldValue('Name'); } 1;

testfoo - sample test script illustrating the problem.

#!/usr/bin/perl -w use strict; use XML::LibXML; use Foo; my $foo = Foo->new(); my $doc = XML::LibXML::Document->new(); print "\$foo is a ", ref($foo), " object reference\n"; my $docelem = XML::LibXML::Element->new('Root'); $doc->setDocumentElement($docelem); $docelem->appendChild($foo); $foo->setName('Bar'); my $name = $foo->getName(); print qq{\$foo->getName() returned "$name"\n\n}; print qq{Notice that my object has type "Foo" here:\n}; my $localname = $foo->localname(); print "My object: $foo ($localname)\n\n"; my $nodes = $doc->findnodes('//Name'); my $s = scalar(@{$nodes}) == 1 ? '' : 's'; print "Found ", scalar(@{$nodes}), " node$s:\n"; foreach my $node (@{$nodes}) { print " ", $node->toString(), "\n"; my $parent = $node->parentNode(); print " From a subelement of my object, I call parentNode().\n" +; print " Now notice that my object is no longer a Foo object:\n\ +n"; my $plm = $parent->localname(); print " My parent: $parent ($plm)\n\n"; print " The reference returned by parantNode() is not the same\ +n"; print " as the original reference:\n\n"; print " ($foo != $parent)\n"; } print "\n", "Document:\n", $doc->toString(), "\n";

In reply to Is it a bad idea to subclass XML::LibXML ? by nenbrian

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.