Thread

Posted on Tue May 20 01:15:12 2008 by digitalramble
getting setData to work
OK, I'm having a bit of a problem getting setData to work. I can *clearly* use it -- it works fine if I copy the example given at http://www.perlmonks.org/?node_id=490846
In particular the example near the bottom of that page where it changes the page value to 394. That all works, so I'm sure my setup etc, is okay. However, when I try to tweak this for my purposes, I run into a stone wall, and it just keeps telling me
Can't locate object method "setData" via package "XML::LibXML::Element"
(and yes, I googled that up...zilch).

Now, in the example, the xpath expression locates one single node. In my application, I'm interested in finding all nodes with a particular attribute and changing those texts around a little bit. I have established that the xpath expression does indeed pull up all the correct nodes from the xml file (via printing out the contents) and I know that the change function works. But adding in the last setData to change the text goes belly up.

Here's my code snippet.

eval { $doc = $parser->parse_file($file); }; warn $@ if $@; my $nodes=$doc->findnodes('//*[@lang="greek"]'); foreach my $node ($nodes->get_nodelist) { my $content=$node->textContent; print "$content\n"; my $changedtext = changeold2new($content); print "$changedtext\n"; $node->setData($betacode); }

It just seems like the node "type" for setData is different than the node "type" for textContent but at this point, I just seem to be going in circles looking through the documentation at cpan to figure out what goes with what or how to convert or...WHAT. Help! I'm sure it's something stupidly obvious, just because :-P.

Thanks, --Cindy
Direct Responses: 8100 | Write a response
Posted on Wed Jun 18 23:53:49 2008 by guttersnipe in response to 7908
Re: getting setData to work
Cindy,

I was having this same issue when I was also trying to run the setData() method against the XML::LibXML::Element object. As you can see from the XML::LibXML::Element and XML::LibXML::Text documentation, the setData() method only exists in the latter.

There is, however, a wrapper method for the Element class called appendTextNode( $string ) that appends the argument $string to the end of the existing text for that element. Why there is no replaceTextNode() method escapes me. But, in the meantime, it seems that in order to replace instead of append, you need to be working with a Text object--not a Element object. This is accomplished by amending your xpath expression.

my @nodes=$doc->findnodes("//*[@lang='greek']");

After the above line executes, each element of the @nodes array will consist of an XML::LibXML::Element object. You want each of these elements to consist of an XML::LibXML::Text object. Change the line to:

my @nodes=$doc->findnodes("//*[@lang='greek']/text()");

...and wala! You can now iterate through the array of XML::LibXML::Text objects and--therefore--preform the setText() method on those objects.

Cheers!
Direct Responses: 8102 | Write a response
Posted on Thu Jun 19 09:27:45 2008 by kevang in response to 8100
Re: getting setData to work
| Why there is no replaceTextNode() method escapes me.

Simple: Because an element may have more than one text node as a child. Consider

<p>This is <em>very</em> important.</p>


The p element has two next nodes, with the data "This is " and " important".
Direct Responses: 8104 | Write a response
Posted on Thu Jun 19 16:08:29 2008 by guttersnipe in response to 8102
Re: getting setData to work
@kavang
> Simple: Because an element may have more than one text node as a child.

Couldn't there be a replaceTextNode() wrapper method that recursively replaces all text nodes within an element? It just seems like a logical counterpart to appendTextNode()...
Write a response