andrewtweber andrewtweber - 29 days ago 10
PHP Question

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.

Answer

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"