Perl XML :: LibXML用法

时间:2017-05-24 10:28:34

标签: xml perl loops libxml2 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>

正如您所看到的,在&#34; actions&#34;下,可能会有不同类型的操作(每种操作有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:
-------------

正如您所看到的,这个结果是错误的,就像每个&#34;动作类型&#34; (检测结果很好),它会对同类动作进行重新循环。

这是由于:

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并使用类似的东西来轻松修复它(但我不知道哪一个是三者之间的最佳选择),但我&#39;我想避免下面这两个因为之后很难生成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 个答案:

答案 0 :(得分:4)

首先,在$doc上调用findnodes,这意味着您的XPath表达式将根据文档根节点进行评估。其次,您使用的XPath表达式以&#39; /&#39;开头。所以它再次植根于顶级节点。所以,当你打电话时:

$doc->findnodes('/fftg/actions/rename')

它意味着&#34;给我作为<rename/>元素的子元素<actions/>元素的每个<fftg/>元素,它是文档&#34;的根节点的<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"; } } 个孩子上,另一个在他们的孩子身上):

#!/bin/bash

sta=1
end=2
countFileInFolder=2
countFolders=5
filePath='/tmp/txt'
scriptDir=$(dirname $(readlink -f ${BASH_SOURCE}))

# create files for test
for (( k=1; k<=$(($countFolders*$countFileInFolder )); k++ )); do
  > "$filePath/$k.txt"
done

for (( i=1; i<=$countFolders; i++ )); do
    if [[ ! -d "$i" ]]; then mkdir "$i"; fi
  for (( n=$sta; n<=$end; n++ )); do
    if [[ ! -f "$i" ]]; then mv "$filePath/$n.txt" "$scriptDir/$i"; fi
  done
  sta=$(($sta+$countFileInFolder))
  end=$(($end+$countFileInFolder))
done