【问题标题】:Perl XML::LibXML usagePerl XML::LibXML 用法
【发布时间】:2017-10-24 15:25:33
【问题描述】:

我在使用 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:

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>

再次感谢 问候,

【问题讨论】:

  • 在阅读所有这些之前......在另一个问题中,您在&lt;action&gt; 中拥有具有属性的元素。在这里也值得一提,因为它可能会改变一些事情。

标签: xml perl loops libxml2 xml-libxml


【解决方案1】:

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

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

它的意思是“给我每个&lt;rename/&gt;元素,它是&lt;actions/&gt;元素的子元素,它是&lt;fftg/&gt;元素的子元素,它是文档的根节点”,结果,你得到每个&lt;rename/&gt;节点可以在文档中找到。

而且,循环太多了。第一个是多余的,因为可能只有一个根元素。两个循环应该可以工作(一个在&lt;action/&gt; 孩子身上,另一个在他们的孩子身上):

for my $action ($doc->findnodes('/fftg/actions/*')) {
    print "executing ", $action->nodeName(), "\n";
    for my $detail ($action->findnodes('./*')) {
        print $detail->nodeName(), ": ", $detail->textContent(), "\n";
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-09
    • 1970-01-01
    相关资源
    最近更新 更多