-1

I'm starting with Perl, I know that there are some similiar questions answered, but (due to my lack of experiences) none of them was helpful.

I have xml like this:

<workflowVertices>
    <workflowVertex>
    <alias />
    <task>Task_L2</task>
    <vertexId>128</vertexId>
</workflowVertex>
<workflowVertex>
     <alias />
     <task>preTask_L1</task>
         <vertexId>129</vertexId>
   </workflowVertex>
</workflowVertices>

I need to delete all workflowVertex nodes that has node task =~ m/_L1/

What I have now:

my $dom = XML::LibXML->load_xml(location => $filename);

foreach my $name ($dom->findnodes('workflowVertices/workflowVertex/task')) 
{
#say $name->to_literal();
if ($name->to_literal() =~ m/_L1/) {
    say "JobName: " . $name->to_literal() . " to be deleted\n";
    my $node = $name->to_literal();
    my $parent = $name-> parentNode();
    say $parent-> removeChild("task[$node]")
    }
}

But when I execute it it falls on error:

XML::LibXML::Node::removeChild() -- node is not a blessed SV reference at 

xmltransform.pl line 28.

Line 28. in my code is

say $parent-> removeChild("task[$node]")

Would anybody help me?

JanFi86
  • 449
  • 10
  • 29
  • 1
    Voting to close as the problem is caused by a typo. The method is called `removeChild`, not `RemoveChild`. – Quentin Jul 02 '19 at 12:15
  • thank you @Quentin, when corrected error message is> XML::LibXML::Node::removeChild() -- node is not a blessed SV reference at xmltransform.pl line 28. – JanFi86 Jul 02 '19 at 12:18
  • @JanFi86 maybe this helps: https://ubuntuforums.org/showthread.php?t=299381 – Chris Jul 02 '19 at 12:31
  • @JanFi86: So someone fixes the problem that you posted and you respond by editing the question to ask a different question? That's a bit rude, really. Please revert your edit and ask your new question in a new post. – Dave Cross Jul 02 '19 at 12:42
  • @ Dave Cross, I'm sorry, thank you for admonition. I thought that if the problem remains in the same line of the code, It'' be better to stay on the same question. But I should have definitely put there edit remark at least. I'll be more carefull next time, No bad intention. Thank you – JanFi86 Jul 02 '19 at 12:53

2 Answers2

3

Here is the documentation for the removeChild() method:

removeChild

$childnode = $node->removeChild( $childnode );

This will unbind the Child Node from its parent $node. The function returns the unbound node. If oldNode is not a child of the given Node the function will fail.

(There's a typo there - where it says oldNode, I'm pretty sure it means $childNode.)

It's not very clear, perhaps, but you need to pass removeChild() a node object, not just a string. You pass it the literal string "task[preTask_L1]" and I'm really not sure where you got that idea from.

I think you've rather confused yourself by using bad names for your variables. Your $name variable contains a node object, not a name. And your $node variable contains the text from the node (which might be considered its "name").

I think the simplest fix is to change your line of code to:

say $parent->removeChild($name);

But I really recommend fixing those variable names too. your maintenance programmer (who could well be you in six months time) will thank you :-)

Dave Cross
  • 68,119
  • 3
  • 51
  • 97
  • Thank you @Dave Cross, now it worked. Just one more question ... what if I do want delete not just _task_ node but _workflowVertex_, it's parent node? I mean delete parent node based on the child node value ... would you help me with that too? – JanFi86 Jul 02 '19 at 13:34
  • I think I found the solution : `my $parent = $name-> parentNode->parentNode; say $parent->removeChild($name->parentNode);` – JanFi86 Jul 02 '19 at 13:45
3

First of all, please use better variable names. Your horrible names ($name is a task node, $node isn't a node at all, it's not clear to whose parent $parent refers, etc.) makes your code extremely hard to read.


You can use

$vertex_node->parent->removeChild($vertex_node);

or

$vertex_node->unbindNode;

to delete the node. Fixed:

my $dom = XML::LibXML->load_xml( location => $filename );

for my $task_node ($dom->findnodes('/workflowVertices/workflowVertex/task')) {
    my $task_name = $task_node->textContent();
    if ($task_name =~ /_L1/) {
        my $vertex_node = $task_node->parent;
        $vertex_node->unbindNode;
        say "Deleted task $task_name.";
    }
}

Alternative approach:

my $dom = XML::LibXML->load_xml( location => $filename );

for my $vertex_node ($dom->findnodes('/workflowVertices/workflowVertex')) {
    my $task_name = $vertex_node->findvalue('task/text()');
    if ($task_name =~ /_L1/) {
        $vertex_node->unbindNode;
        say "Deleted task $task_name.";
    }
}

If you don't need to print out the task name, this can even be shrunk to the following:

my $dom = XML::LibXML->load_xml( location => $filename );

$_->unbindNode
    for $dom->findnodes('/workflowVertices/workflowVertex[contains(task/text(), "_L1")]');
ikegami
  • 367,544
  • 15
  • 269
  • 518