timmmy has asked for the wisdom of the Perl Monks concerning the following question:
I am completely new to perl. I have had trouble understanding documentation; I think I don't understand all of the terminology. As such, I am not sure of the best way to phrase my questions. The examples here have been most helpful.
The code below works completely, but it feels like I am missing all of the perl and XML::Twig advantages. I feel like I should not need any foreach loops for this task.
1. How do I directly access the child with a specific gi and with a specific attribute of a specific value? I want to find the 'Instruction' element where 'Type'='Motor'. (There should only be one.)
2. How do I access the children where one of two attributes is a specific value? I want to find the FromID of wires that 'ToID'=$motorID OR the ToID of wires that 'FromID'=$motorID.
3. How do I access the child with ANY gi and with a specific attribute of a specific value? I want to access the 'Text' attribute of the child that 'ID'=$tofromID (discussed above in #2.)
Specifically, I want to link together a motor with all of its inputs and outputs. The output format is completely open. This is what I chose for its presenting ease with Excel.
Output:
<Motors> <Motor ID="2" Name="Motor2_name"> <Motor_Input>Input_0_Text</Motor_Input> <Motor_Output>Output_1_Text</Motor_Output> </Motor> <Motor ID="2" Name="Motor_name"> <Motor_Input>Input_0_Text</Motor_Input> <Motor_Output>Output_1_Text</Motor_Output> </Motor> </Motors>
Code:
use strict; use warnings; use XML::Twig; my $XML='<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Content> <Sheet> <Input ID="0" Text="Input_0_Text"/> <Output ID="1" Text="Output_1_Text"/> <Output ID="3" Text="Irrelevant_Output"/> <Instruction Type="Other"/> <Instruction Type="Motor" ID="2" Name="Motor_name"/> <Wire FromID="0" ToID="2" ToText="Motor_Input"/> <Wire FromID="2" ToID="1" FromText="Motor_Output"/> </Sheet> <Sheet> <Input ID="0" Text="Input_0_Text"/> <Output ID="1" Text="Output_1_Text"/> <Instruction Type="Motor" ID="2" Name="Motor2_name"/> <Wire FromID="0" ToID="2" ToText="Motor_Input"/> <Wire FromID="2" ToID="1" FromText="Motor_Output"/> </Sheet> </Content>'; # build a new file in the output format. my $Output_file_name='testOutput.xml'; my $outRoot=XML::Twig::Elt->new('Motors'); #process input XML data my $twig_roots={'Sheet'=>1}; my $twig_handlers={'Sheet' => \&Motors}; my $twig=new XML::Twig(TwigRoots=>$twig_roots, TwigHandlers=>$twig_han +dlers); $twig->parse($XML); #output results $outRoot->set_pretty_print('indented'); $outRoot->print_to_file($Output_file_name); sub Motors{ my ($twig, $Motor)=@_; my $motor_name=""; my $motorID=-1; # I want to find the ID of the Motor Instruction # This seems like what I want to do # $motorID = $Motor->first_child('Instruction')=>{Type=>'Motor'}->att +('Name'); # Error: "Can't call method "att" on unblessed reference..." # This works but seems to be non-twigish foreach my $instr ($Motor->children('Instruction')){ #iterate throug +h all the instructions on this sheet if($instr->att('Type') eq 'Motor'){ #this instruction is a motor +type; set attributes $motorID=$instr->att('ID'); $motor_name=$instr->att('Name'); $outRoot->insert_new_elt('Motor'=>{Name=>$motor_name, ID=>$motor +ID}); } } # I want to find all wires that have a ToID or FromID that matches th +e motorID foreach my $wire ($Motor->children('Wire')){ #iterate through all wi +res on this sheet # do once for ToID if($wire->att('ToID') == $motorID){ #this is a wire that goes to +the motor my $ToParam = $wire->att('ToText'); my $FromID = $wire->att('FromID'); my $FromText; #nested foreach -> lots of iteration :( foreach my $motor_item ($Motor->children()){ #iterate though all + items on the sheet if (defined ($motor_item->att('ID'))){ #if the item has an ID +attribute if($motor_item->att('ID')==$FromID){ #that matches the wire +to the motor $FromText=$motor_item->att('Text'); #set output attribute } } } my $newRoot = $outRoot->first_child('Motor'=>{Name=>$motor_name} +); #set current motor as root $newRoot->insert_new_elt('last_child', $ToParam, $FromText); #ad +d this wire to output. } # do again for FromID pretty much the same as above. if($wire->att('FromID') == $motorID){ my $FromParam = $wire->att('FromText'); my $ToID = $wire->att('ToID'); my $ToText; foreach my $motor_item ($Motor->children()){ if (defined ($motor_item->att('ID'))){ if($motor_item->att('ID')==$ToID){ $ToText=$motor_item->att('Text'); } } } my $newRoot = $outRoot->first_child('Motor'=>{Name=>$motor_name} +); $newRoot->insert_new_elt('last_child', $FromParam, $ToText); } } }
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: XML::Twig efficiency with attributes
by perlfan (Parson) on Jun 02, 2014 at 18:42 UTC | |
|
Re: XML::Twig efficiency with attributes
by poj (Abbot) on Jun 02, 2014 at 21:44 UTC | |
by timmmy (Initiate) on Jun 03, 2014 at 14:14 UTC |