Search code examples
phpxmlsimplexmldomdocumentdomxpath

DOMXPath paths showing up as asterisks


I have an XML string, snippet below:

<?xml version="1.0"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
       xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <SendPurchases xmlns="urn:services.insurance">
            <Partner>
                <UserID>MyCompany</UserID>
                <Password>ABC123</Password>
            </Partner>
            <PurchasesRequest>
                <Total>100</Total> 
            </PurchasesRequest>
        </SendPurchases>
    </soap:Body>
</soap:Envelope>

I am converting the XML into a DOMDocument to make manipulation "easier":

$doc = new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);

I would then like to manipulate certain values, preferably using their paths:

$elements = $xpath->query('/soap:Envelope/soap:Body/SendPurchases/Partner/UserID');

However the above query is returning no results.

In fact when I loop through all of the elements inside the document:

foreach ($doc->getElementsByTagName('*') as $node) {
    echo $node->getNodePath() . "\n";
}

It returns something like this:

/soap:Envelope/soap:Body
/soap:Envelope/soap:Body/*
/soap:Envelope/soap:Body/*/*[1]
/soap:Envelope/soap:Body/*/*[1]/*[1]
/soap:Envelope/soap:Body/*/*[1]/*[2]
/soap:Envelope/soap:Body/*/*[2]
/soap:Envelope/soap:Body/*/*[2]/*[1]

As you can see all of the elements inside of <soap:Body> are replaced with asterisks and indexes instead of the element names.

Querying along that path works, but will not be easy for me to maintain and I would greatly prefer to use the element names instead.


Solution

  • Another option is to use local-name():

    $xml = '<?xml version="1.0"?>
        <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
            <soap:Body>
                <SendPurchases xmlns="urn:services.insurance">
                    <Partner>
                        <UserID>MyCompany</UserID>
                        <Password>ABC123</Password>
                    </Partner>
                    <PurchasesRequest>
                        <Total>100</Total> 
                    </PurchasesRequest>
                </SendPurchases>
            </soap:Body>
        </soap:Envelope>';
    $doc = new DOMDocument();
    $doc->loadXML($xml);
    $xpath = new DOMXPath($doc);
    
    $elements = $xpath->query("//*[local-name()='UserID']");
    
    var_dump($elements->item(0)->nodeValue);
    // string(9) "MyCompany"