Reputation: 792
I am having some trouble using XML::LibXML and I'd like to know if there is a way to do what I want to do, or if my XML should be changed.
at the moment, my XML looks like :
<fftg>
<actions>
<rename>
<mandatory>0</mandatory>
<other_things_here />
</rename>
<transfer>
<mandatory>0</mandatory>
<protocol>SFTP</protocol>
<other_things_here />
</transfer>
<transfer>
<mandatory>1</mandatory>
<protocol>FTP</protocol>
<other_things_here />
</transfer>
<archive>
<mandatory>1</mandatory>
<other_things_here />
</archive>
<rename>
<mandatory>1</mandatory>
<other_things_here />
</rename>
</actions>
</fftg>
as you can see, under "actions", there can be different type of actions (1 or multiple actions of each kind, with different things under each action)
I want to browse each action and perform specific things depending on the action.
my problem is : as there are multiple actions of the same kind, the script is not working properly and overwrites the previous action of the same kind, or the loop on a specific actions re-loops on every action of the same kind
example 1 :
foreach my $transfer ($doc->findnodes('/fftg')) {
# Browse Actions
foreach my $action ($doc->findnodes('/fftg/actions/*')) {
my $action_name = $action->nodeName();
my $actiontype = ucfirst($action->nodeName());
print "executing action $action_name ..\n";
# Browse action details
foreach my $action_details ($doc->findnodes('/fftg/actions/'.$action_name)) {
for my $detail ($action_details->findnodes('./*')) {
print $detail->nodeName(), ": ", $detail->textContent(), "\n";
}
}
print "-------------\n";
}
}
result 1 :
executing action rename ..
mandatory: 0
other_things_here:
mandatory: 1
other_things_here:
-------------
executing action transfer ..
mandatory: 0
protocol: SFTP
other_things_here:
mandatory: 1
protocol: FTP
other_things_here:
-------------
executing action transfer ..
mandatory: 0
protocol: SFTP
other_things_here:
mandatory: 1
protocol: FTP
other_things_here:
-------------
executing action archive ..
mandatory: 1
other_things_here:
-------------
executing action rename ..
mandatory: 0
other_things_here:
mandatory: 1
other_things_here:
-------------
as you can see, this result is wrong, as in each "action type" (which is good, detected), it's re-looping on every action of the same kind.
this is due to :
foreach my $action_details ($doc->findnodes('/fftg/actions/'.$action_name)) {
how can I do to make what I want to achieve ? (if possible without changing the XML)
what I want is :
executing action rename ..
mandatory: 0
other_things_here:
-------------
executing action transfer ..
mandatory: 0
protocol: SFTP
other_things_here:
-------------
executing action transfer ..
mandatory: 1
protocol: FTP
other_things_here:
-------------
executing action archive ..
mandatory: 1
other_things_here:
-------------
executing action rename ..
mandatory: 1
other_things_here:
-------------
thank you
on a side note, I suppose I could change my XML and use something like that instead to fix it easily (but I don't know which one is the best option between the three), but I'd like to avoid these two below because the XSD is going to be tough to produce afterwards (I want specific options for each action type) :
<fftg>
<actions>
<action>
<type>rename</type>
<mandatory>0</mandatory>
<other_things_here />
</action>
<action>
<type>transfer</type>
<mandatory>0</mandatory>
<protocol>SFTP</protocol>
<other_things_here />
<action>
<action>
<type>transfer</type>
<mandatory>0</mandatory>
<protocol>FTP</protocol>
<other_things_here />
<action>
<action>
<type>archive</type>
<mandatory>0</mandatory>
<other_things_here />
<action>
<action>
<type>rename</type>
<mandatory>0</mandatory>
<other_things_here />
<action>
</actions>
</fftg>
or
<fftg>
<actions>
<action type="rename">
<mandatory>0</mandatory>
<other_things_here />
</action>
<action type="transfer">
<mandatory>0</mandatory>
<protocol>SFTP</protocol>
<other_things_here />
<action>
<action type="transfer">
<mandatory>0</mandatory>
<protocol>FTP</protocol>
<other_things_here />
<action>
<action type="archive">
<mandatory>0</mandatory>
<other_things_here />
<action>
<action type="rename">
<mandatory>0</mandatory>
<other_things_here />
<action>
</actions>
</fftg>
thanks again regards,
Upvotes: 2
Views: 129
Reputation: 19204
First, you call findnodes on $doc
, which means your XPath expression is evaluated against document root node. Second, the XPath expression you use starts with '/' so that again is rooted at the top-level node. So that, when you call:
$doc->findnodes('/fftg/actions/rename')
it means "give me every <rename/>
element that is child of <actions/>
element that is child of <fftg/>
element that is root node of document", and, as a result, you get every <rename/>
node that is found in document.
Moreover, there are too many loops. The first one is redundant, as there may be only single root element. Two loops should work (one on <action/>
children, and another one on their children):
for my $action ($doc->findnodes('/fftg/actions/*')) {
print "executing ", $action->nodeName(), "\n";
for my $detail ($action->findnodes('./*')) {
print $detail->nodeName(), ": ", $detail->textContent(), "\n";
}
}
Upvotes: 5