in reply to XML round-trip with comments and prolog

To close out this discussion, here's an example implementation using XML::LibXML of taking the example data, finding a specific node, editing that node, and adding a new node after it, and outputting the final XML to complete the round trip.

#!perl -l use 5.012; # strict, // use warnings; use Data::Dump; use XML::LibXML; my $xml_doc = <<EOXML; <?xml version="1.0" encoding="UTF-8" ?> <!-- important instructions to manual editors --> <root> <group name="somethingElse"> <Item MenuEntryName="Edit" MenuItemName="Copy"/> </group> <group name="contextMenu"> <!-- still commented --> <Item MenuEntryName="Edit" MenuItemName="Cut"/> <Item MenuEntryName="Edit" MenuItemName="Copy"/> <Item MenuEntryName="Edit" MenuItemName="Paste"/> </group> </root> EOXML # process XML my $dom = XML::LibXML->load_xml(string => $xml_doc, no_blanks => 1); # find specific item and its parent my ($desiredItem) = $dom->findnodes('//group[@name="contextMenu"]/Item +[@MenuItemName="Copy"]'); printf "%-23s %s\n", "Found:", $desiredItem->toString(); my $itemParent = $desiredItem->parentNode; printf "%-23s %s\n", "Parent:", $itemParent->toString(1); # prove that I can edit the item $desiredItem->setAttribute( comment => 'edited' ); printf "%-23s %s\n", "Edited:", $desiredItem->toString(); printf "%-23s %s\n", "Parent:", $itemParent->toString(1); # create item and show it's not added to parent yet my $newItem = XML::LibXML::Element->new('Item'); $newItem->setAttribute( MenuEntryName => "Edit"); $newItem->setAttribute( MenuItemName => "Delete"); $newItem->setAttribute( comment => "created"); printf "%-23s %s\n", "Created:", $newItem->toString(); printf "%-23s %s\n", "Parent:", $itemParent->toString(1); # add item $itemParent->insertAfter($newItem, $desiredItem); printf "%-23s %s\n", "Added to Parent:", $itemParent->toString(1); # verify it's there and edit it my ($foundNew) = $dom->findnodes('//group[@name="contextMenu"]/Item[@c +omment="created"]'); printf "%-23s %s\n", "Found:", $foundNew->toString(); $foundNew->setAttribute( comment => 'inserted' ); printf "%-23s %s\n", "Edited:", $foundNew->toString(); printf "%-23s %s\n", "Parent:", $itemParent->toString(1); # finish with the Round Trip output my $str = $dom->toString(1); $str =~ s/(^|\G)( |\t)/ /gm; print "\n\nRound Trip output:\n-----\n$str\n=====\n\n"; __END__ ... snipped intermediate output ... Round Trip output: ----- <?xml version="1.0" encoding="UTF-8"?> <!-- important instructions to manual editors --> <root> <group name="somethingElse"> <Item MenuEntryName="Edit" MenuItemName="Copy"/> </group> <group name="contextMenu"> <!-- still commented --> <Item MenuEntryName="Edit" MenuItemName="Cut"/> <Item MenuEntryName="Edit" MenuItemName="Copy" comment="edited +"/> <Item MenuEntryName="Edit" MenuItemName="Delete" comment="inse +rted"/> <Item MenuEntryName="Edit" MenuItemName="Paste"/> </group> </root> =====

So thanks all for the helpful suggestions.

Replies are listed 'Best First'.
Re^2: XML round-trip with comments and prolog
by choroba (Archbishop) on Jul 30, 2021 at 13:31 UTC
    Note that non-ancient XML::LibXML supports the hash syntax for attributes, so you can replace your setAttribute calls with
    $desiredItem->{comment} = 'edited'; ... @$newItem{qw{ MenuEntryName MenuItemName comment }} = qw{ Edit Delete created }; ... $foundNew->{comment} = 'inserted';

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]