2017-05-24 102 views
2

我在使用XML :: LibXML时遇到了一些麻烦,我想知道是否有办法做我想做的事,或者如果我的XML应该改变。Perl XML :: LibXML用法

的那一刻,我的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> 

再次感谢 问候,

+0

阅读这一切之前...中的其他问题,你有那里面有属性''元素。值得一提的是,这里也可能会改变一切。 – simbabque

回答

4

首先,你叫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"; 
    } 
}