skip to Main Content

Ugh. PHP dummy here sorry. Searched and searched here, but search foo not good enough. I feel like I’m dancing around an answer, but array_filter, array_search, recursive etc. I’m just not getting a handle on it mentally haha.

I have this sample from an XML export where the ordering of the XML is NOT consistent nor well formed and the nesting levels are even different at times etc. etc. so I can’t grab values based on where it is specifically in the export, which even dummy me could do:

<INFRA>
<GUID>7C32C0A2-EF31-11E9-8128-4CCC6A98779E</GUID>
<ID>501</ID>
<NAME>P Cedar</NAME>
<TYP>36</TYP>
<TYPKRZ>50_IN_36_PARKPLATZ</TYPKRZ>
<TYPNAME>parking place</TYPNAME>
<STATUS>open</STATUS>
<STATUSWERT k="SONSTIGE" v="miscellaneous">1</STATUSWERT>
</INFRA>

In this instance I need to find/search for unique string <NAME>P Cedar</NAME> no matter where in the export it may end up. Then I need to assign a variable to the <STATUS> of that particular <INFRA><NAME> so I can do some operators against it. TIA!

2

Answers


  1. Here is a solution based on DOM and XPath:

    $xml = <<<XML
    <ROOT>
        <NESTED>
            <INFRA>
                <GUID>7C32C0A2-EF31-11E9-8128-4CCC6A98779E</GUID>
                <ID>501</ID>
                <NAME>P Cedar</NAME>
                <TYP>36</TYP>
                <TYPKRZ>50_IN_36_PARKPLATZ</TYPKRZ>
                <TYPNAME>parking place</TYPNAME>
                <STATUS>open</STATUS>
                <STATUSWERT k="SONSTIGE" v="miscellaneous">1</STATUSWERT>
            </INFRA>
            <INFRA>
                <GUID>7C32C0A2-EF31-11E9-8128-4CCC6A98779E</GUID>
                <ID>501</ID>
                <NAME>D John</NAME>
                <TYP>36</TYP>
                <TYPKRZ>50_IN_36_PARKPLATZ</TYPKRZ>
                <TYPNAME>parking place</TYPNAME>
                <STATUS>closed</STATUS>
                <STATUSWERT k="SONSTIGE" v="miscellaneous">1</STATUSWERT>
            </INFRA>
        </NESTED>
    </ROOT>
    XML;
    
    function getStatus($doc, $name)
    {
        $xpath = new DOMXPath($doc);
        $entries = $xpath->query('//INFRA/NAME');
        foreach($entries as $entry)
        {
            if($entry->textContent == $name)
                return $entry->parentNode->getElementsByTagName('STATUS')[0]->textContent;
        }
        return null;    
    }
    
    $doc = new DOMDocument();
    $doc->loadXML($xml);
    echo getStatus($doc, 'P Cedar'); // open
    echo getStatus($doc, 'D John'); // closed
    

    For performance reason, consider extracting all the NAME / STATUS pairs at once (no need to execute the XPath query several times).

    Login or Signup to reply.
  2. Use DOMXpath::evaluate(). Xpath expressions allow for complex conditions and casts. So you logic can be put directly into an expression:

    • Any INFRA element in the document: //INFRA
    • … with a child element NAME: //INFRA[NAME]
    • … that equals P Cedar: //INFRA[NAME="P Cedar"]
    • … the STATUS children: //INFRA[NAME="P Cedar"]/STATUS
    • … as a string: string(//INFRA[NAME="P Cedar"]/STATUS)

    Xpath functions like string() take a list of nodes and use the text content of the first node (or an empty string).

    $document = new DOMDocument();
    $document->loadXML(getXML());
    $xpath = new DOMXPath($document);
    
    var_dump($xpath->evaluate('string(//INFRA[NAME = "P Cedar"]/STATUS)'));
    var_dump($xpath->evaluate('string(//INFRA[NAME = "D John"]/STATUS)'));
    
    function getXML() {
      return <<<XML
    <ROOT>
        <NESTED>
            <INFRA>
                <GUID>7C32C0A2-EF31-11E9-8128-4CCC6A98779E</GUID>
                <ID>501</ID>
                <NAME>P Cedar</NAME>
                <TYP>36</TYP>
                <TYPKRZ>50_IN_36_PARKPLATZ</TYPKRZ>
                <TYPNAME>parking place</TYPNAME>
                <STATUS>open</STATUS>
                <STATUSWERT k="SONSTIGE" v="miscellaneous">1</STATUSWERT>
            </INFRA>
            <INFRA>
                <GUID>7C32C0A2-EF31-11E9-8128-4CCC6A98779E</GUID>
                <ID>501</ID>
                <NAME>D John</NAME>
                <TYP>36</TYP>
                <TYPKRZ>50_IN_36_PARKPLATZ</TYPKRZ>
                <TYPNAME>parking place</TYPNAME>
                <STATUS>closed</STATUS>
                <STATUSWERT k="SONSTIGE" v="miscellaneous">1</STATUSWERT>
            </INFRA>
        </NESTED>
    </ROOT>
    XML;
    }
    ```; 
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search