在PHP中,无法使用具有自定义标记的soap-env解析XML

f87krz0w  于 2023-02-28  发布在  PHP
关注(0)|答案(2)|浏览(192)

在PHP中解析XML响应时遇到错误
当我从CURL请求调用时,我收到一个低于XML的响应

<?xml version="1.0" encoding="UTF-8"?> <soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
    <soap-env:Header>
        <eb:MessageHeader xmlns:eb="http://www.ebxml.org/namespaces/messageHeader" eb:version="1.0" soap-env:mustUnderstand="1">
            <eb:From>
                <eb:PartyId eb:type="URI">Sabre_API</eb:PartyId>
            </eb:From>
            <eb:To>
                <eb:PartyId eb:type="URI">Agency</eb:PartyId>
            </eb:To>
            <eb:ConversationId>2021.01.DevStudio</eb:ConversationId>
            <eb:Service eb:type="sabreXML">Session</eb:Service>
            <eb:Action>TokenCreateRS</eb:Action>
            <eb:MessageData>
                <eb:MessageId>1913771794839350290</eb:MessageId>
                <eb:Timestamp>2023-02-23T22:04:43</eb:Timestamp>
            </eb:MessageData>
        </eb:MessageHeader>
        <wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext">
            <wsse:BinarySecurityToken valueType="String" EncodingType="wsse:Base64Binary">T1RLAQLASo74A7olKG7QnepeFqs19UHX+0Cds9QiDZoYfu677xC3Vkr9a+OcQhutjPL4atVMAADQRtHIXdehGg/0OVuPdia/0cM233jFDvyJJHgJHC3o8gV2ssS63b4Y0lgCG59SiG4tmEcqAXcYAMlnq+wJ4TfsOIDFwYdP+D0peSEFBM/m3EyOUqc4idJ+vO4S7xENCeQ7UX4YVKjVLJs788omPDbSIRNo85KQ5QxRprldV0jucJpAtbNfs1DrMHFqNIPyg0CpVpgXILkFx0azkcAuvmbHMHLqqO13WJEOhsG0KDBhBhRn8CwoCgD9foXL24W6yGu8Ecm0Fzvb/MuAjuYm9s48yg**</wsse:BinarySecurityToken>
        </wsse:Security>
    </soap-env:Header>
    <soap-env:Body>
        <sws:TokenCreateRS xmlns:sws="http://webservices.sabre.com" Version="1.0.0">
            <sws:Success/>
        </sws:TokenCreateRS>
    </soap-env:Body> </soap-env:Envelope>

为了解析上面的XML,我最初尝试使用simplexml_load_String,但它给出了一个空响应。
然后我尝试使用下面的代码DOM方法,这里考虑**$response-〉Data**是上面的XML。

$dom = new DOMDocument;
    $dom->preserveWhiteSpace = false;
    $dom->loadXML($response->Data);
    $dom->formatOutput = true;      
    $XMLContent = $dom->saveXML();

它再次给出以下输出:

<!--?xml version="1.0" encoding="UTF-8"?-->
<soap-env:envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">   <soap-env:header>
    <eb:messageheader xmlns:eb="http://www.ebxml.org/namespaces/messageHeader" eb:version="1.0" soap-env:mustunderstand="1">
      <eb:from>
        <eb:partyid eb:type="URI">Sabre_API</eb:partyid>
      </eb:from>
      <eb:to>
        <eb:partyid eb:type="URI">Agency</eb:partyid>
      </eb:to>
      <eb:conversationid>2021.01.DevStudio</eb:conversationid>
      <eb:service eb:type="sabreXML">Session</eb:service>
      <eb:action>TokenCreateRS</eb:action>
      <eb:messagedata>
        <eb:messageid>1002038859236010450</eb:messageid>
        <eb:timestamp>2023-02-23T23:52:03</eb:timestamp>
      </eb:messagedata>
    </eb:messageheader>
    <wsse:security xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/12/secext">
      <wsse:binarysecuritytoken valuetype="String" encodingtype="wsse:Base64Binary">T1RLAQJZqih4+TYQmYCcdj42lcej5nckNWdo6WNb8edNl3xNtxAkqmu2YKjKki1OKQ7B3HK3AADQCGiRWrlzFPM0KB4foAOsSF+I+5eXE32uQ23LLd+hOduY2BCJYqPw7CvwCJ/LfNjy3P+QyvClvu6ysctC3a0GjmixDPDqCIckcXPb+XDFyYhR5G5QzQjch/Eax25koLnNvfN8rlvjNq+ENJmaV17wP43GLo1pzd19d9HGMn1VgjrJiVGWAb1ezyeiFNAd1VuBD2lAmdlo4jvZJzAS/fklZvwNFbKME64YpaFRptoLz0FKmz47y1TVYFtV6TZxbKirP3PDms0aGlItbJ4apPSB2Q**</wsse:binarysecuritytoken>
    </wsse:security>   </soap-env:header>   <soap-env:body>
    <sws:tokencreaters xmlns:sws="http://webservices.sabre.com" version="1.0.0">
      <sws:success>
    </sws:success></sws:tokencreaters>   </soap-env:body> </soap-env:envelope>

因此,我计划从NODE获取数据,如下所示
$XML内容-〉按标记名获取元素('soap-env:header')-〉项目(0)-〉节点值);

但它没有给我一个节点值,而是开始给我错误。

我只想获取节点wsse:binarysecuritytoken中的数据
有人经历过这样的事吗?
你能帮我一下吗?

更新也尝试跟踪,但仍然没有帮助

$domDocument = new DOMDocument();
$domDocument->loadXML($XMLContent);
$carriers=array();
$results=$domDocument->getElementsByTagName("wsse:Security");
foreach($results as $result)
{
    foreach($result->childNodes as $node)
    {
        if($node instanceof DOMElement)
        {
            array_push($carriers, $node->textContent);
        }
    }

}
var_dump($carriers);
sqyvllje

sqyvllje1#

这是SOAP,一种使用XML语法的对象序列化格式。最好的解决方案是使用SOAP库。PHP有ext/soap用于此。使用XML库会低一层。
XML使用名称空间。名称空间是使用唯一的URI指定的。为了便于阅读/维护,XML定义了URI的别名,并将它们用作节点名的前缀。但是,以下3个示例都应读作{http://schemas.xmlsoap.org/soap/envelope/}Envelope

  • <soap-env:envelope xmlns::soap-env="http://schemas.xmlsoap.org/soap/Envelope/"/>
  • <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"/>
  • <Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"/>

命名空间可以在任何元素节点上定义,因此它们甚至可以在单个文档中更改。这意味着您的代码不应该依赖于文档中的别名/前缀,而是依赖于命名空间URI。
我强烈建议为所使用的名称空间定义一个数组变量/常量,然后就可以使用Xpath和名称空间感知DOM方法(后缀为NS)。

// used namespaces, the keys do NOT need to match the prefixes in the XML.
$xmlns = [
    'soap' => 'http://schemas.xmlsoap.org/soap/envelope/',
    'eb' => 'http://www.ebxml.org/namespaces/messageHeader',
    'sec' => 'http://schemas.xmlsoap.org/ws/2002/12/secext'
];

$document = new DOMDocument();
$document->loadXML(getSoapXmlString());
$xpath = new DOMXpath($document);
// register your aliases for the namespaces
foreach ($xmlns as $alias => $uri) {
    $xpath->registerNamespace($alias, $uri);
}

$token = $xpath->evaluate(
  'string(//sec:Security/sec:BinarySecurityToken)'
); 

var_dump($token);

DOMXpath::evaluate()允许使用返回节点列表和标量值的Xpath表达式。如果将节点列表(由位置路径指定)强制转换为字符串,它将返回第一个节点的文本内容或空字符串。

hts6caw3

hts6caw32#

好了,终于花了几个小时,我得到了!我不得不修改根据标签名称如下,在大多数家长我不得不使用soap-env而不是SOAP。

$dom = new DOMDocument;
            $dom->preserveWhiteSpace = false;
            $dom->loadXML($response->Data);
            $dom->formatOutput = true;      
            $XMLContent = $dom->saveXML();

            $xml = simplexml_load_String($XMLContent, null, null, 'soap-env', true);    

            if(!$xml)
                trigger_error("Encoding Error!", E_USER_ERROR);
            
            $Results = $xml->children('soap-env',true);
                
            foreach($Results->children('soap-env',true) as $fault){
                if(strcmp($fault->getName(),'Fault') == 0){
                    trigger_error("Error occurred request/response processing!", E_USER_ERROR);
                }
            }
    
            foreach($Results->children('wsse',true) as $nodes){         
                if(strcmp($nodes->getName(),'Security') == 0){
                    foreach($nodes->children('wsse',true) as $securityNodes){
                        if(strcmp($securityNodes->getName(),'BinarySecurityToken') == 0){                           
                            $tokenParsed = (string)$securityNodes;                                                      
                        }
                    }
                }           
            }

相关问题