Charlie Trig
Charlie Trig

Reputation: 57

SimpleXML and php - get a node that contains text that matches another node

I am trying to display the text content of a Node, if the content of that node matches another node (sibling). Here is the XML:

<MemberId>
    <BillingInfo>
        <Details>
            <Line NUMBER="0">
                <ChargeDate>20140605</ChargeDate>
                <DueDate>20140605</DueDate>
                <TrackingNumber>PR DED</TrackingNumber>
                <Description>Account payroll deduction</Description>
                <RevCode>SJ1550</RevCode>
                <RevDesc>ACCOUNT PAYROLL DEDUCTION</RevDesc>
                <SalesAmount>-11.77</SalesAmount>
                <ServiceCharge>0.00</ServiceCharge>
                <GST>0.00</GST>
                <PST>0.00</PST>
                <Othertaxes>0.00</Othertaxes>
                <Total>-11.77</Total>
                <ChitCode>PR DED</ChitCode>
                <ChitDate>20140605</ChitDate>
            </Line>

            <Line NUMBER="1">
                <ChargeDate>20140605</ChargeDate>
                <DueDate>20140605</DueDate>
                <TrackingNumber>03128862</TrackingNumber>
                <Description>Mountain Mkt Sales</Description>
                <RevCode>SJ1553</RevCode>
                <RevDesc>MOUNTAIN MKT SALES</RevDesc>
                <SalesAmount>8.99</SalesAmount>
                <ServiceCharge>0.00</ServiceCharge>
                <GST>0.00</GST>
                <PST>0.61</PST>
                <Othertaxes>0.00</Othertaxes>
                <Total>9.60</Total>
                <ChitCode>03128862</ChitCode>
                <ChitDate>20140605</ChitDate>
            </Line>
        </Details>
    </BillingInfo>
    <Chits>
    <Chit>
    <Code>03128862</Code>
    <Body><![CDATA[
        Member#: 0ECHER
        Name: *******
        Area:  *********
        Server: JEANNEANE
        Chit#: 03128862
        Date:  June 5 2014
        ------- ------- ------- ------- -------
        1       MINGUA BEEF JER            8.99
        ------- ------- ------- ------- -------
        Sub-Total                          8.99


        TAX                                0.61
        ------- ------- ------- ------- -------
        Chit Total                         9.60



        MEMBER CHARGE                     -9.60
    ]]></Body>
    </Chit>
    </Chits>
</MemberId>

I am successfully displaying each ChitCode and ChitDate, because they are in the Line[@number] Node. I want to display the Body node that contains the text "Chit#: XXXXXX" where xxxxxx matches Line->ChitCode. Here is my php, it displays the Body, but it displays the first Body for all the line items:

<?php 
    foreach($Chitquery as $Chit) 
    {
        foreach($Linequery as $Line)
        {
            echo "<label class='collapse' for='".$Line->ChitCode."-".$Line->ChitDate."'>".$Line->Description."</label>
            <input id='".$Line->ChitCode."-".$Line->ChitDate."' type='checkbox'>
            <div>"; 
            // Creates hide - show link for each Description item
            // Start getting the matching Chit Code from Chit/Body                          

            if ($Chit->Code = $Line->ChitCode)
            {
                echo $Chit->Body."</div>";
            }
            else
            {
                echo " ".$Line->ChitCode."</div>";
            } // End If
        } //End  foreach Linequery
    } // End foreach Chitquery
?>

It's the echo $Chit->Body.""; that I need help with, I want to display the Body that contains the value of $Line->ChitCode.

Oh yeah, and the lines are repeating weird, due to improper placement of 'foreach' statements! screenshot of lists Help! Thanks in advance!

UPDATE: I have changed my php code and now I have the hide-show divs working, with no duplicates, but I get 'array' instead of $ChitBody. I cannot figure out how to find the Body node that contains the $Line->ChitCode in $ChitBody = $member->xpath('Chits/Chit/Body[text()="'.$Line->ChitCode.'"] ');

<?php 
                        foreach($Linequery as $Line) { 
                        $ChitCode = $member->Chits->Chit->Code;
                        $ChitBody = $member->xpath('Chits/Chit/Body[text()="'.$Line->ChitCode.'"] ');
                        echo "<label class='collapse' for='".$Line->ChitCode."-".$Line->ChitDate."'>".$Line->Description."</label>
                         <input id='".$Line->ChitCode."-".$Line->ChitDate."' type='checkbox'>"; // Creates hide - show link for each Description item
                        // Start getting the matching Chit Code from Chit/Body                          
                            if ($ChitCode = $Line->ChitCode) {
                            echo "<div>Code: ".$ChitCode."<br>".$ChitBody."</div>";
                            } else {
                            echo "<div>".$Line->ChitCode."</div>";
                            } // End If
                        } //End  foreachLinequery
                     ?>

enter image description here

Upvotes: 0

Views: 268

Answers (2)

hakre
hakre

Reputation: 198217

You are most likely looking for xpath to query you document.

for example to iterate over the lines - I don't fully understand why you do it the way you do it, but here is how I understand it to go over the lines (text-only output):

$xml = simplexml_load_string($buffer);

foreach ($xml->xpath('//Details/Line') as $line)
{
    printf("#%d: %s\n", $line['NUMBER'], $line->Description);            
}

which gives:

#0: Account payroll deduction
#1: Mountain Mkt Sales

I guess you see how this works in general. So now for getting chit based on $line->ChitCode, which is I think actually the more interesting part for you. It also better illustrates the benefits of xpath:

foreach ($xml->xpath('//Details/Line') as $line)
{
    printf("#%d: [%s] %s\n", $line['NUMBER'], $line->ChitCode, $line->Description);

    $query  = sprintf("//Chits/Chit[Code = '%s']/Body", $line->ChitCode);
    $result = $xml->xpath($query);

    if ($result) {
        $chit = $result[0];
        echo $chit;
    } else {
        echo ' -- no chit found -- ';
    }
    echo "\n";
}

This time the query contains the condition to look for the number (in case you want to make this save, escape the string properly (more info)), it basically creates the following two xpath queries:

//Chits/Chit[Code = 'PR DED']/Body

//Chits/Chit[Code = '03128862']/Body

I again guess you can imagine what those mean. In case such a <Body> element is found, the code above outputs it. And this is how the result looks like:

#0: [PR DED] Account payroll deduction
 -- no chit found -- 
#1: [03128862] Mountain Mkt Sales

        Member#: 0ECHER
        Name: *******
        Area:  *********
        Server: JEANNEANE
        Chit#: 03128862
        Date:  June 5 2014
        ------- ------- ------- ------- -------
        1       MINGUA BEEF JER            8.99
        ------- ------- ------- ------- -------
        Sub-Total                          8.99


        TAX                                0.61
        ------- ------- ------- ------- -------
        Chit Total                         9.60



        MEMBER CHARGE                     -9.60

I hope this gives you enough insight to get started with it. xpath() is just a method on SimpleXMLElement so you can combine this as well with your code which I didn't copy just to have the example smaller (same reason why I use plain text output here, would work equally with HTMl but would bloat the example).


Addition by OP:

THAT WORKED GREAT!!

I adapted your code to this, and it worked perfectly:

foreach ($Linequery as $Line) {
    $LineChitCode = $Line->ChitCode;
    $ChitBody     = sprintf("//Chits/Chit[Code = '%s']/Body", $LineChitCode);
    $CBresult     = $member->xpath($ChitBody);
    echo "<label class='collapse' for='" . $Line->ChitCode . "-" . $Line->ChitDate . "'>" . $Line->Description . "</label>
                             <input id='" . $Line->ChitCode . "-" . $Line->ChitDate . "' type='checkbox'>"; // Creates hide - show link for each Description item
    // Start getting the matching Chit Code from Chit/Body                            
    if ($CBresult) {
        $chit = $CBresult[0];
        echo "<div>Code: " . $LineChitCode . "<br>" . $chit . "</div>";
    } else {
        echo "<div>" . $Line->ChitCode . "</div>";
    }
}

Thank you, you saved me from 3 days of trying to figure this out!!

Upvotes: 2

yunus kula
yunus kula

Reputation: 919

you may use if ($Chit->Code == $Line->ChitCode) instead of if ($Chit->Code = $Line->ChitCode)

Upvotes: 0

Related Questions