Search code examples
phpxmlxpathsimplexml

Accessing a specific XML element using xpath in PHP 7.x


Ok so I have some XML data.

$mydata = <<<XML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE fmresultset PUBLIC "-//FMI//DTD fmresultset//EN" "https://HIDDEN:443/fmi/xml/fmresultset.dtd">
<fmresultset xmlns="http://www.filemaker.com/xml/fmresultset" version="1.0">    
    <resultset count="1" fetch-size="1">
        <record mod-id="27" record-id="754">
            <field name="a_Constant_c">
                <data>1</data>
            </field>
            <field name="a_Sch_ID_pk">
                <data>100060</data>
            </field>
            <field name="a_SchoolHead_pk">
                <data>100060_1</data>
            </field>
            <field name="b___Data_____________">
                <data/>
            </field>
            <field name="b_1Name_School_Code_t">
                <data>PJA</data>
            </field>
            <field name="b_1Name_School_t">
                <data>Palmetto</data>
            </field>
            <field name="b_1Name_SchoolHead_t">
                <data>John Doe</data>
            </field>
            <field name="b_Ad_Address1_t">
                <data/>
            </field>
            <field name="b_Ad_Address2_t">
                <data>123 Main St.</data>           
        </record>
    </resultset>
</fmresultset>
XML;

Now what I want to do is basically be able to read the value of the data from a specific field and assign it to a variable.

So far I have something like this...

$xml = simplexml_load_string($mydata);

Now I want to be able to assign let's say the data in the field name b_1Name_School_Code_t (which is PJA)

So I think it should be something like this

$school = $xml->resultset->record->field->data;
echo "School Name: ".$school;

Then I would like to see on the screen

School Name: PJA

So what I am missing to be able to make this happen?


Solution

  • You are only getting to the first field element in your example, which is why you get 1. Instead, loop through all the field elements, and stop when you get to the one you need:

    $xml = simplexml_load_string($mydata);
    $fields = $xml->resultset->record->field;
    foreach ($fields as $field) {
        if ((string) $field->attributes()->name === "b_1Name_School_Code_t") {
            echo "School name: ".$field->data; // School name: PJA
            break;
        }
    }
    

    Demo

    I use SimpleXMLElement::attributes() to get the name attribute of the element (note the cast to string, otherwise you get an SimpleXMLElement)

    However, it would make more sense to use XPath to go directly to the element you're after:

    $xml = simplexml_load_string($mydata);
    $xml->registerXPathNamespace("fmresultset", "http://www.filemaker.com/xml/fmresultset");
    $node = $xml->xpath("//fmresultset:resultset/fmresultset:record/fmresultset:field[@name='b_1Name_School_Code_t']");
    var_dump($node[0]->data); // PJA
    

    Demo

    Notice the namespace registration and the accessing of the first element, since xpath() returns an array of SimpleXMLElements