2014-03-25 121 views
0

解析我有XML:复杂的XML与Perl和libxml的

<?xml version="1.0" encoding="UTF-8"?> 
<?xml-stylesheet type="text/xsl" href="MeasDataCollection.xsl"?> 

<measCollecFile xmlns=""> 
    <fileHeader fileFormatVersion="32.435 V7.2.0"> 
    </fileHeader> 

    <measData> 
     <managedElement localDn="bs=8" swVersion="R21A"/> 

     <measInfo measInfoId="CORE,SIP_session_statistics"> 
      <measType p="1">CPUUSAGE</measType> 
      <measType p="2">CPUMEM</measType> 
      <measType p="3">SYSMEM</measType> 

      <measValue measObjLdn="SGC.bsNo=17,networkRole=2"> 
       <r p="1">10</r> 
       <r p="2">20</r> 
       <r p="3">30</r> 
      </measValue> 

      <measValue measObjLdn="SGC.bsNo=18,networkRole=2"> 
       <r p="1">40</r> 
       <r p="2">50</r> 
       <r p="3">60</r> 
      </measValue> 
     </measInfo> 
    </measData> 
</measCollecFile> 

问题:

我想从<r p="1">40</r>元素提取40。唯一给出的是<measType p="1">CPUUSAGE</measType><measValue measObjLdn="SGC.bsNo=18,networkRole=2"> 即我只知道我需要找到bsNo=18CPUUSAGE。数据的顺序始终保持不变。


这里是我到目前为止已经试过:

my $qry="//measInfo[measType/text() = 'CPUUSAGE']/measValue"; 

my @nodes= $conn->findnodes($qry); 

foreach my $vnode (@nodes) { 
    if ($vnode->getAttribute('measObjLdn') =~ /'bsNo=18'/) { 
     foreach my $node ($vnode) { 
      foreach my $p ($node->getChildnodes) { 
       if (ref($p)=~'Element'){ 
        $no=$p->textContent; 
        print $no;**#this prints the value of all the <r> elements** 
       } 
      } 
     } 
    } 
} 

我的挑战是可以有很多元素,如CPUUSAGE,CPUMEM ...我如何能达到在正确的顺序<r>对于给定的measValue属性(/'bsNo=18'/)的顺序元素。

并随后修改40为其他所需值**,因为你对阵'bsNo=18'的属性值,包括单引号

+2

你尝试过这么远吗?这对于单个XPath查询来说很难做到,但解决此问题的方法并不复杂。 – amon

+0

@amon,'/ measCollecFile/measData/measInfo/measValue [@ measObjLdn =“SGC.bsNo = 18,networkRole = 2”]/r [@p = ../../measType[text()="CPUUSAGE“ ]/@ p]' – ikegami

+0

Catch:当只需要执行一次时,会导致对每个“r”执行'../../ measType [text()=“CPUUSAGE”]“。 – ikegami

回答

0

你的Perl代码不能工作。

如果你想找到具有相同p属性作为CPUUSAGE节点r元素,你既可以尝试通过池上或XPath表达式类似如下:

for my $type_node ($conn->findnodes('//measInfo/measType[.="CPUUSAGE"]')) { 
    my $p = $type_node->getAttribute('p'); 
    my $qry = <<"EOF"; 
.. 
/measValue[contains(concat(\@measObjLdn, ','), 'bsNo=18,')] 
/r[\@p='$p'] 
EOF 

    for my $r_node ($type_node->findnodes($qry)) { 
     print $r_node->textContent, "\n"; 
    }  
} 

这首先遍历所有measType节点的内容为CPUUSAGE,获取p属性,然后找到所有对应的r节点。这种方法应该比单个XPath查询更有效。

要查找的位置r节点并修改其内容,请尝试:

for my $type_node ($conn->findnodes('//measInfo/measType[.="CPUUSAGE"]')) { 
    my $pos = $type_node->findvalue('count(preceding-sibling::measType) + 1'); 
    my $qry = <<"EOF"; 
.. 
/measValue[contains(concat(\@measObjLdn, ','), 'bsNo=18,')] 
/r[$pos] 
EOF 

    for my $r_node ($type_node->findnodes($qry)) { 
     $r_node->removeChildNodes; 
     $r_node->appendText('50'); 
    } 
} 

print $conn->toString; 
+0

nwellnhof!这非常有帮助。 – marks

+0

万一元素名称是变量,那么我无法找到节点。像//$measInfo/$measType[.="$CPUUSAGE“]。此外,当我试图做精确匹配而不是包含然后以及它找不到节点。提前致谢。 – marks