英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论