Using Simplexml's Xpath to filter nodes based

2019-08-24 10:07发布

问题:

I'm working on a way to filter certain nodes based upon their value in PHP. I'm trying to return the count of the status nodes that equal 'Funded.' The part I'm not sure about is in using the array (the result of a previous filter ($xml_bio_record[0]) in the new filter ($xml_bio_children)).
This code does not return a count for $count_c. How would I filter on status="Funded"? Thanks for any leads.

Here is the XML:

<?xml version="1.0" encoding="utf-8"?>
<data>
<record id="1A">
    <congrant>
        <ident>a</ident>
        <status>Not Funded</status>
    </congrant>
    <congrant>
        <ident>b</ident>
        <status>Funded</status>
    </congrant>
    <congrant>
        <ident>c</ident>
        <status/>
    </congrant>
</record>
<record id="1B">
    <congrant>
        <ident>a</ident>
        <status>Not Funded</status>
    </congrant>
    <congrant>
        <ident>b</ident>
        <status>Funded</status>
    </congrant>
    <congrant>
        <ident>c</ident>
        <status/>
    </congrant>
</record>
<record id="1C">
    <congrant>
        <ident>aaa</ident>
        <status>Funded</status>
    </congrant>
    <congrant>
        <ident>bbb</ident>
        <status>Funded</status>
    </congrant>
    <congrant>
        <ident>c</ident>
        <status>Funded</status>
    </congrant>
</record>
</data>

Here is the PHP:

$url_bio = "test.xml";


$xml_bio = simplexml_load_file($url_bio);

$xml_bio_record=$xml_bio->xpath('/data/record');
$count_a = count($xml_bio_record);
echo '<br>$count_a is...'.$count_a.'<br>';//
foreach($xml_bio_record as $xa){
    echo "Found {$xa->status} <br>";
}

$xml_bio_record=$xml_bio->xpath('//record[@id="1A"]');
$count_b = count($xml_bio_record);
echo '<br>$count_b is...'.$count_b.'<br>';//
foreach($xml_bio_record as $xb){
    echo "Found {$xb->status} <br>";
}



$xml_bio_children=$xml_bio_record[0]->xpath('/congrant[status="Funded"]');

$count_c = count($xml_bio_children);
echo '<br>$count_c is...'.$count_c.'<br>';//
foreach($xml_bio_children as $xc){
    echo "Found {$xc->status} <br>";
}

======= As an addendum to this, if I wished to set a variable equal to $xb->xpath('./congrant[status="Funded"]'), such as: $xml_congrant_congrant_children=$xb->xpath('./congrant[status="Funded"]') and then use an index to loop through the funded results in a pagination scenario, how could that be accomplished? e.g.

for ($i = $offset; $i < ($offset + $per_page); $i++)
 { 
$strCongrant_ident = $xml_congrant_congrant_children[$i]['ident'];
} 

I've used this loop idea before in a pagination setting, but getting the filter to apply to the variable here is not working. Thanks for any leads.

回答1:

Here is the pure xpath that you can use to get the count of elements with Funded status.

count(//record[@id="1A"]//status[.='Funded'])

Screenshot:



回答2:

As supputuri's answer suggests, you can combine the two XPath expressions into a single search:

//record[@id="1A"]/congrant[status="Funded"]

If you want the first list anyway for other purposes, you could loop over it and do the status check in PHP:

$xml_bio_record=$xml_bio->xpath('//record[@id="1A"]');
$funded_count = 0;
foreach($xml_bio_record as $xb){
    foreach ($xb->congrant as $congrant) {
        if ( (string)$congrant->status == 'Funded' ) {
            $funded_count++;
        }
    }
}

Or you could mix loops and XPath, using . to make the XPath search relative to a particular element:

$xml_bio_record=$xml_bio->xpath('//record[@id="1A"]');
$total_funded_count = 0;
foreach($xml_bio_record as $xb){
    $xb_funded_count = count($xb->xpath('./congrant[status="Funded"]'));
    $total_funded_count += $xb_funded_count;
}