douchen2011 2018-01-25 00:58
浏览 146
已采纳

PHP - 解析具有命名空间元素的xml

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!

  • 写回答

2条回答 默认 最新

  • drxkx6149 2018-01-25 05:09
    关注

    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;
            }
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 远程桌面文档内容复制粘贴,格式会变化
  • ¥15 关于#java#的问题:找一份能快速看完mooc视频的代码
  • ¥15 这种微信登录授权 谁可以做啊
  • ¥15 请问我该如何添加自己的数据去运行蚁群算法代码
  • ¥20 用HslCommunication 连接欧姆龙 plc有时会连接失败。报异常为“未知错误”
  • ¥15 网络设备配置与管理这个该怎么弄
  • ¥20 机器学习能否像多层线性模型一样处理嵌套数据
  • ¥20 西门子S7-Graph,S7-300,梯形图
  • ¥50 用易语言http 访问不了网页
  • ¥50 safari浏览器fetch提交数据后数据丢失问题