I read other posts and solutions, and they don't work for me - or perhaps I'm not understanding them well enough.
I have a hp network scanner, and have a perl script that interacts through a series of transactions such that I can initiate a scan. I'm working to port that rather directly to php; more suitable for the server I want to run it on. Some transactions work, some don't. This is about one that doesn't.
I took the XML from one of the queries and it won't successfully parse (or this is where I don't understand it well enough). I'm running php version 7.1.12, in case there is something related to that.
my test outputs this:
> php xmltest.php
SimpleXMLElement Object
(
)
object(SimpleXMLElement)#1 (0) {
}
>
And if the xml is simpler (no name-space info I think), then the print_r() is quite verbose.
And here is the full test script with some actual data to process
error_reporting( E_ALL );
ini_set('display_errors', 1);
$test_1 = <<<EOM
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wst="http://schemas.xmlsoap.org/ws/2004/09/transfer"
xmlns:mex="http://schemas.xmlsoap.org/ws/2004/09/mex"
xmlns:wsdp="http://schemas.xmlsoap.org/ws/2006/02/devprof"
xmlns:PNPX="http://schemas.microsoft.com/windows/pnpx/2005/10"
xmlns:UNS1="http://www.microsoft.com/windows/test/testdevice/11/2005"
xmlns:dd="http://www.hp.com/schemas/imaging/con/dictionaries/1.0"
xmlns:wprt="http://schemas.microsoft.com/windows/2006/08/wdp/print"
xmlns:wscn="http://schemas.microsoft.com/windows/2006/08/wdp/scan">
<SOAP-ENV:Header>
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
<wsa:Action>http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse</wsa:Action>
<wsa:MessageID>urn:uuid:fec6e42d-5356-1f69-9c3a-001f2927cf33</wsa:MessageID>
<wsa:RelatesTo>urn:uuid:704ccde5-6861-415d-bd65-31dd9d7a8b98</wsa:RelatesTo>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<mex:Metadata>
<mex:MetadataSection Dialect="http://schemas.xmlsoap.org/ws/2006/02/devprof/ThisDevice">
<wsdp:ThisDevice>
<wsdp:FriendlyName xml:lang="en">Printer (HP Color LaserJet CM1312nfi MFP)</wsdp:FriendlyName>
<wsdp:FirmwareVersion>20140625</wsdp:FirmwareVersion>
<wsdp:SerialNumber>CNB885H665</wsdp:SerialNumber>
</wsdp:ThisDevice>
</mex:MetadataSection>
<mex:MetadataSection Dialect="http://schemas.xmlsoap.org/ws/2006/02/devprof/ThisModel">
<wsdp:ThisModel>
<wsdp:Manufacturer xml:lang="en">HP</wsdp:Manufacturer>
<wsdp:ManufacturerUrl>http://www.hp.com/</wsdp:ManufacturerUrl>
<wsdp:ModelName xml:lang="en">HP Color LaserJet CM1312nfi MFP</wsdp:ModelName>
<wsdp:ModelNumber>CM1312nfi MFP</wsdp:ModelNumber>
<wsdp:PresentationUrl>http://192.168.1.20:80/</wsdp:PresentationUrl>
<PNPX:DeviceCategory>Printers</PNPX:DeviceCategory>
</wsdp:ThisModel>
</mex:MetadataSection>
<mex:MetadataSection Dialect="http://schemas.xmlsoap.org/ws/2006/02/devprof/Relationship">
<wsdp:Relationship Type="http://schemas.xmlsoap.org/ws/2006/02/devprof/host">
<wsdp:Hosted>
<wsa:EndpointReference>
<wsa:Address>http://192.168.1.20:3910/</wsa:Address>
<wsa:ReferenceProperties>
<UNS1:ServiceIdentifier>uri:prn</UNS1:ServiceIdentifier>
</wsa:ReferenceProperties>
</wsa:EndpointReference>
<wsdp:Types>wprt:PrinterServiceType</wsdp:Types>
<wsdp:ServiceId>uri:1cd4F16e-7c8a-a7a0-3797-00145a8827ce</wsdp:ServiceId>
<PNPX:CompatibleId>http://schemas.microsoft.com/windows/2006/08/wdp/print/PrinterServiceType</PNPX:CompatibleId>
</wsdp:Hosted>
</wsdp:Relationship>
</mex:MetadataSection>
</mex:Metadata>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
EOM;
$myxml1 = simplexml_load_string($test_1);
print_r($myxml1);
var_dump($myxml1);
exit;
?>
There are several parameters nestled in there that I want to pull out. One, for instance is:
<wsa:Address>http://192.168.1.20:3910/</wsa:Address>
Can you help me close my knowledge gap on how to access this parameter?
thanks!
First of all, soap and namespaces just make parsing XML harder than it has to be. I've never parsed XML that had namespaces that actually made the XML better to understand, or had any benefit at all. I fully get why namespaces exist, but it just means jumping through some extra hoops to get the data out. The trick with namespaces is that you have to "enter in" to the namespace branch by asking that the namespace as a child.
<?php
error_reporting( E_ALL );
ini_set('display_errors', 1);
$str = <<<EOM
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"
xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wst="http://schemas.xmlsoap.org/ws/2004/09/transfer"
xmlns:mex="http://schemas.xmlsoap.org/ws/2004/09/mex"
xmlns:wsdp="http://schemas.xmlsoap.org/ws/2006/02/devprof"
xmlns:PNPX="http://schemas.microsoft.com/windows/pnpx/2005/10"
xmlns:UNS1="http://www.microsoft.com/windows/test/testdevice/11/2005"
xmlns:dd="http://www.hp.com/schemas/imaging/con/dictionaries/1.0"
xmlns:wprt="http://schemas.microsoft.com/windows/2006/08/wdp/print"
xmlns:wscn="http://schemas.microsoft.com/windows/2006/08/wdp/scan">
<SOAP-ENV:Header>
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To>
<wsa:Action>http://schemas.xmlsoap.org/ws/2004/09/transfer/GetResponse</wsa:Action>
<wsa:MessageID>urn:uuid:fec6e42d-5356-1f69-9c3a-001f2927cf33</wsa:MessageID>
<wsa:RelatesTo>urn:uuid:704ccde5-6861-415d-bd65-31dd9d7a8b98</wsa:RelatesTo>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<mex:Metadata>
<mex:MetadataSection Dialect="http://schemas.xmlsoap.org/ws/2006/02/devprof/ThisDevice">
<wsdp:ThisDevice>
<wsdp:FriendlyName xml:lang="en">Printer (HP Color LaserJet CM1312nfi MFP)</wsdp:FriendlyName>
<wsdp:FirmwareVersion>20140625</wsdp:FirmwareVersion>
<wsdp:SerialNumber>CNB885H665</wsdp:SerialNumber>
</wsdp:ThisDevice>
</mex:MetadataSection>
<mex:MetadataSection Dialect="http://schemas.xmlsoap.org/ws/2006/02/devprof/ThisModel">
<wsdp:ThisModel>
<wsdp:Manufacturer xml:lang="en">HP</wsdp:Manufacturer>
<wsdp:ManufacturerUrl>http://www.hp.com/</wsdp:ManufacturerUrl>
<wsdp:ModelName xml:lang="en">HP Color LaserJet CM1312nfi MFP</wsdp:ModelName>
<wsdp:ModelNumber>CM1312nfi MFP</wsdp:ModelNumber>
<wsdp:PresentationUrl>http://192.168.1.20:80/</wsdp:PresentationUrl>
<PNPX:DeviceCategory>Printers</PNPX:DeviceCategory>
</wsdp:ThisModel>
</mex:MetadataSection>
<mex:MetadataSection Dialect="http://schemas.xmlsoap.org/ws/2006/02/devprof/Relationship">
<wsdp:Relationship Type="http://schemas.xmlsoap.org/ws/2006/02/devprof/host">
<wsdp:Hosted>
<wsa:EndpointReference>
<wsa:Address>http://192.168.1.20:3910/</wsa:Address>
<wsa:ReferenceProperties>
<UNS1:ServiceIdentifier>uri:prn</UNS1:ServiceIdentifier>
</wsa:ReferenceProperties>
</wsa:EndpointReference>
<wsdp:Types>wprt:PrinterServiceType</wsdp:Types>
<wsdp:ServiceId>uri:1cd4F16e-7c8a-a7a0-3797-00145a8827ce</wsdp:ServiceId>
<PNPX:CompatibleId>http://schemas.microsoft.com/windows/2006/08/wdp/print/PrinterServiceType</PNPX:CompatibleId>
</wsdp:Hosted>
</wsdp:Relationship>
</mex:MetadataSection>
</mex:Metadata>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
EOM;
$xml = simplexml_load_string($str);
$namespaces = $xml->getNamespaces(true);
// Here we are saying that we want the Body node in the SOAP-ENV namespace
$body = $xml->children( $namespaces['SOAP-ENV'] )->Body;
// Inside that Body node, we want to get into the mex namespace
$mex = $body->children( $namespaces['mex'] );
// We want the MetadataSections that are in each of the mex namespaces
$metadataSections = $mex->Metadata->MetadataSection;
// Loop through each of the MetadataSections
foreach( $metadataSections as $meta )
{
// Get inside the wsdp namespace
$wsdp = $meta->children( $namespaces['wsdp'] );
// Check if there is a Hosted node inside a Relationship node
if( isset( $wsdp->Relationship->Hosted ) )
{
// Get the wsa namespace inside the Hosted node
$wsa = $wsdp->Relationship->Hosted->children( $namespaces['wsa'] );
// If there is an Address inside the EndpointReference node
if( isset( $wsa->EndpointReference->Address ) )
{
// Then output it
echo $wsa->EndpointReference->Address;
}
}
}
As an extremely simple example - if you just wanted the wsa:Address
element...
$myxml1 = simplexml_load_string($test_1);
$myxml1->registerXPathNamespace("wsa", "http://schemas.xmlsoap.org/ws/2004/08/addressing");
echo "wsa:Address=".(string)$myxml1->xpath("//wsa:Address")[0];
This just makes sure that the wsa
namespace is registered with the document and available to XPath expressions. Then the XPath expression just says - fetch element wsa:Address
from anywhere in the document. But as xpath
returns a list of all matches (even if there is only 1) so use [0]
to get the first item. This outputs...
wsa:Address=http://192.168.1.20:3910/
If you needed more data around the (for example) <wsdp:Hosted>
element, you could do something like...
$myxml1 = simplexml_load_string($test_1);
$myxml1->registerXPathNamespace("wsdp", "http://schemas.xmlsoap.org/ws/2006/02/devprof");
$hosted = $myxml1->xpath("//wsdp:Hosted")[0];
$hostedWSA = $hosted->children("wsa", true);
echo "wsa:Address=".(string)$hostedWSA->EndpointReference->Address.PHP_EOL;
$hostedWSPD = $hosted->children("wsdp", true);
echo "wsdp:Types=".(string)$hostedWSPD->Types.PHP_EOL;
So instead this starts of by fetching the correct element and then working with the various child nodes in the different namespaces within that node.