0

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!

1
  • As you said, there are many other questions about getting an element out of XML containing namespaces using PHP. If you can link to one that you tried to follow, show your attempt to adapt the solution in that link to get wsa:Address, that will give us a hint of what you knew and what is the gap to actually accomplish the task, and therefor it will be easier for us to help Commented Jan 25, 2018 at 3:07

2 Answers 2

1

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;
        }
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

This gets me just what I needed, and is easy to extrapolate into some of the more complex scenarios ahead.
0

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.

2 Comments

This example looks to be useful for "surgical" needs, where a single element is needed - as you noted.
The second example shows how you would fetch a start point for a group of data - 'wsdp:Hosted'. The most important thing about this is that it's independent of the structure of the enclosing data. Even if they changed the enclosing document, it would still work. When you try and traverse a complex structure level by level, it's open to changes over time and suddenly the code fails to find the data.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.