xmlperlxml-libxml

Perl removing node


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?


Solution

  • 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")]');