使用Perl和LIBXML进行复杂的XML解析

时间:2014-03-25 14:11:17

标签: perl libxml2

我有XML:

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

问题:

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


这是我到目前为止所尝试的内容:

bsNo=18

我的挑战是可以有许多元素,如CPUUSAGE,CPUMEM ......以及我如何在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** } } } } } 元素中按顺序为给定的<r>属性({{1)达到正确的顺序}})。

随后将该40修改为其他所需的值**

1 个答案:

答案 0 :(得分:0)

您的Perl代码无效,因为您将属性值与'bsNo=18'匹配,包括单引号。

如果要查找与r节点具有相同p属性的CPUUSAGE元素,可以尝试使用ikegami的单个XPath表达式,如下所示:< / p>

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;