Perl XML :: LibXML的用法

Perl XML::LibXML usage

我在使用XML :: LibXML时遇到了一些麻烦,我想知道是否有一种方法可以做我想做的事,或者是否应该更改我的XML。

此刻,我的XML如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<fftg>
   

            <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>

           
                    <mandatory>1</mandatory>
                    <other_things_here />
            </archive>

            <rename>
                    <mandatory>1</mandatory>
                    <other_things_here />
            </rename>

    </actions>

</fftg>

如您所见,在"动作"下可以有不同类型的动作(一种或多种动作,每种动作下有不同的事物)

我想浏览每个动作并根据动作执行特定的操作。

我的问题是:由于存在多个相同类型的动作,因此脚本无法正常工作,并覆盖了相同类型的先前动作,或者特定动作的循环在相同类型的每个动作上重新循环

示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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 ..\
"
;

            # Browse action details
            foreach my $action_details ($doc->findnodes('/fftg/actions/'.$action_name)) {
                    for my $detail ($action_details->findnodes('./*')) {
                            print $detail->nodeName(),":", $detail->textContent(),"\
"
;
                    }
            }
            print"-------------\
"
;
    }
}

结果1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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:
-------------

如您所见,此结果是错误的,因为在每个"动作类型"(很好,已检测到)中,它都会在相同类型的每个动作上重新循环。

这是由于:

1
foreach my $action_details ($doc->findnodes('/fftg/actions/'.$action_name)) {

我该怎么做才能实现自己想要的目标? (如果可能的话,不更改XML)

我想要的是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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之后将很难生成(我想要每种操作类型都有特定的选项):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<fftg>

       
                <type>rename</type>
                <mandatory>0</mandatory>
                <other_things_here />
        </action>

       
                <type>transfer</type>
                <mandatory>0</mandatory>
                <protocol>SFTP</protocol>
                <other_things_here />
       

       
                <type>transfer</type>
                <mandatory>0</mandatory>
                <protocol>FTP</protocol>
                <other_things_here />
       

       
                <type>archive</type>
                <mandatory>0</mandatory>
                <other_things_here />
       

       
                <type>rename</type>
                <mandatory>0</mandatory>
                <other_things_here />
       



</actions>

</fftg>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<fftg>

       
                <mandatory>0</mandatory>
                <other_things_here />
        </action>

       
                <mandatory>0</mandatory>
                <protocol>SFTP</protocol>
                <other_things_here />
       

       
                <mandatory>0</mandatory>
                <protocol>FTP</protocol>
                <other_things_here />
       

       
                <mandatory>0</mandatory>
                <other_things_here />
       

       
                <mandatory>0</mandatory>
                <other_things_here />
       



</actions>

</fftg>

再次感谢
问候,


首先,您在$doc上调用findnodes,这意味着您的XPath表达式是根据文档根节点求值的。其次,您使用的XPath表达式以\\'/ \\'开头,从而再次植根于顶级节点。这样,当您致电:

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

它的意思是"给我作为元素的子元素的<rename/>元素,作为文档根节点的<fftg/>元素的子元素",结果,您得到了每个在文档中找到的节点。

此外,循环太多。第一个是多余的,因为可能只有一个根元素。应该有两个循环(一个在子代上,另一个在子代上):

1
2
3
4
5
6
7
8
for my $action ($doc->findnodes('/fftg/actions/*')) {
    print"executing", $action->nodeName(),"\
"
;
    for my $detail ($action->findnodes('./*')) {
        print $detail->nodeName(),":", $detail->textContent(),"\
"
;
    }
}