Perl XML::LibXML использование
У меня возникли проблемы с использованием XML::LibXML, и я хотел бы знать, есть ли способ сделать то, что я хочу, или мой XML должен быть изменен.
на данный момент мой XML выглядит так:
<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>
как вы можете видеть, под "действиями" могут быть различные типы действий (1 или несколько действий каждого вида, с разными вещами под каждым действием)
Я хочу просмотреть каждое действие и выполнить определенные вещи в зависимости от действия.
Моя проблема: поскольку существует несколько действий одного и того же типа, скрипт не работает должным образом и перезаписывает предыдущее действие того же рода, или цикл для определенных действий повторяет все действия одного и того же вида
пример 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";
}
}
результат 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:
-------------
как видите, этот результат неверен, так как в каждом "типе действия" (который хорошо обнаружен) он повторяется для каждого действия того же рода.
это связано с:
foreach my $action_details ($doc->findnodes('/fftg/actions/'.$action_name)) {
как я могу сделать то, чего я хочу достичь? (если возможно без изменения XML)
что я хочу это:
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:
-------------
благодарю вас
В дополнение к этому, я полагаю, что я мог бы изменить свой XML и использовать что-то подобное вместо этого, чтобы легко это исправить (но я не знаю, какой из них является лучшим вариантом из трех), но я хотел бы избежать этих двух ниже потому что XSD будет сложно производить впоследствии (я хочу конкретные параметры для каждого типа действия):
<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>
или же
<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>
еще раз спасибо с уважением,
1 ответ
Сначала вы вызываете findnodes на $doc
, что означает, что ваше выражение XPath оценивается по отношению к корневому узлу документа. Во-вторых, выражение XPath, которое вы используете, начинается с '/', так что снова укореняется в узле верхнего уровня. Так что при звонке
$doc->findnodes('/fftg/actions/rename')
это значит "дай мне каждый <rename/>
элемент, который является потомком <actions/>
элемент, который является потомком <fftg/>
элемент, который является корневым узлом документа ", и, в результате, вы получаете каждый <rename/>
узел, который находится в документе.
Более того, петель слишком много. Первый является избыточным, так как может быть только один корневой элемент. Два цикла должны работать (один на <action/>
дети, и еще один на своих детей)
for my $action ($doc->findnodes('/fftg/actions/*')) {
print "executing ", $action->nodeName(), "\n";
for my $detail ($action->findnodes('./*')) {
print $detail->nodeName(), ": ", $detail->textContent(), "\n";
}
}