XML无法解析具有自定义标记的SOAP-ENV的PHP中

huangapple go评论59阅读模式
英文:

XML not parse with soap-env having custom tags in PHP

问题

您正在尝试解析PHP中的XML响应时遇到错误。您首先尝试了simplexml_load_String,但得到了一个空的响应。然后,您尝试了DOM方法,但也没有得到期望的结果。您想要提取wsse:binarysecuritytoken节点的数据。

首先,确保您的XML文档被正确加载。以下是一种提取wsse:binarysecuritytoken节点值的方法:

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

$securityNodes = $dom->getElementsByTagName('wsse:binarysecuritytoken');
if ($securityNodes->length > 0) {
    $binarySecurityToken = $securityNodes->item(0)->textContent;
    echo "Binary Security Token: " . $binarySecurityToken;
} else {
    echo "Binary Security Token not found.";
}

这段代码首先加载XML文档,然后使用getElementsByTagName来查找wsse:binarysecuritytoken节点。如果找到了节点,它将提取节点的文本内容并输出。如果找不到节点,它会显示"Binary Security Token not found."。

希望这对您有所帮助。如果您仍然遇到问题,请提供更多详细信息,以便我们更好地协助您。

英文:

I am experiencing an error while parsing my XML response in PHP

I have a below XML response, when i call from CURL request

<?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>

To parse the above XML i have initially tried with the simplexml_load_String but it gives an empty response.

Then i tried DOM method by using following code, here considering $response->Data is the above XML.

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

It gives me following output again:

<!--?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>

So i plan to get data from NODE like below

> $XMLContent->getElementsByTagName('soap-env:header')->item(0)->nodeValue);

But instead of giving me a node values it start giving me and error.

I just want to get the data in the node wsse:binarysecuritytoken

Did anyone experience some thing like this?

Can you please help me in that??

UPDATE
Tried also following, but got not helpful still

$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);

答案1

得分: 0

好的,以下是已翻译的部分:

我终于花了几个小时,明白了!
我不得不根据以下标签名称进行修改,在最顶层我必须使用 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;                                                        
            }
        }
    }            
}
英文:

Ok finally after spent hours, i got that!
I had to modify according to tag names as below, in the most parent i had to used soap-env instead of 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;														
						}
					}
				}			
			}

答案2

得分: 0

这是SOAP,一种使用XML语法的对象序列化格式。最佳解决方案是使用SOAP库。PHP有一个名为ext/soap的扩展用于此目的。使用XML库将会是一个更底层的选项。

XML使用命名空间。命名空间使用唯一的URI进行指定。为了可读性和可维护性,XML为这些URI定义了别名,并将它们用作节点名称的前缀。然而,以下三个示例都应该被视为{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)。

// 使用的命名空间,键名不需要与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);
// 为命名空间注册别名
foreach ($xmlns as $alias => $uri) {
    $xpath->registerNamespace($alias, $uri);
}

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

var_dump($token);

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

英文:

This is SOAP, an object serialization format that uses XML syntax. Best solution is to use a SOAP library. PHP has ext/soap for this. Using an XML library would be a level lower.

The XML uses namespaces. Namespaces are specified using unique URIs. For readability/maintainability XML defines aliases for the URIs and uses them as prefixes for node names. However the following 3 examples all should be read as {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/"/>

Namespaces can be defined on any element node, so they can change even in a single document. That means that your code should not depend on the aliases/prefixes in the document, but the namespace URIs.

I strongly suggest defining an array variable/constant for the used namespaces. Then you can use Xpath and the namespace aware DOM methods (with the suffix 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() allows for Xpath expression that return node lists and scalar values. If you cast a node list (specified by a location path) to string it will return the text content of the first node or an empty string.

huangapple
  • 本文由 发表于 2023年2月24日 07:57:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75551465.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定