webservice服务我认为不是个非常通用的接口,虽然这是个标准的接口,但是跨语言处理问题还是非常多的,比如我用PHP来处理java提供的webservice就是一个非常麻烦的事情。
PHP自带soap扩展,本来以为用来解析java的soap服务很容易,但发现问题很多,php间通讯是没有问题的,但格式与java的不一样,就通讯不上了。
感慨:json是真心不错的。
好在PHP无比强大,模拟数据也实现了数据通讯。
首先,因为php的soap扩展提供给服务器的数据,服务器端不匹配,所以就不用soap扩展了,改用curl模拟。
完整代码:
<?php $soap='<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <AisQuery xmlns="http://www.kingdee.com/Public"/> </soap:Body> </soap:Envelope>'; //$soap=file_get_contents("A.xml");//从文件获取字符串的方式 //echo $soap; $ch=curl_init(); //curl_setopt($ch,CURLOPT_URL,"http://192.16.1.12/soap.php"); curl_setopt($ch,CURLOPT_URL,"http://192.168.100.108/KDWEBSERVICE/Public.asmx"); curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); curl_setopt($ch,CURLOPT_POST,1); curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type:text/xml; charset=utf-8")); curl_setopt($ch,CURLOPT_POSTFIELDS,$soap); $data=curl_exec($ch); curl_close($ch); //echo $data;//得到返回数据 $dom = new DOMDocument(); $dom->loadXML($data); // 获取所有的AisInfo标签 $AisInfo = $dom ->getElementsByTagName("AisInfo" ); // 循环遍历AisInfo标签 foreach ($AisInfo as $post ){ // 获取AisInfo标签 $AisName = $post ->getElementsByTagName("AisName" ); $AisID = $post ->getElementsByTagName("AisID" ); $Number = $post ->getElementsByTagName("Number" ); /** * 要获取标签的属性要分两部走 * < title id ="1" > PHP XML处理</ title > * 1. 获取标签中所有属性的列表也就是$*->item(0)->attributes * 2. 获取标签中第一个属性,因为其在第一位所以用item(0) * 3. $title ->item(0)->attributes->item(0)->nodeValue * * 小提示: * 若取属性的值可以用item(*)->nodeValue * 若取属性的标签可以用item(*)->nodeName * 若取属性的类型可以用item(*)->nodeType */ echo $AisName ->item(0)->nodeName .': '. $AisName ->item(0)->nodeValue . "<br />" ; echo "AisID: " . $AisID ->item(0)->nodeValue . "<br />" ; echo "Number: " . $Number->item(0)->nodeValue . "<br />" ; echo "Version: " . $post ->getElementsByTagName("Version") ->item(0)->nodeValue . "<br /><br />" ; } ?>
php直接post了服务器需要的xml数据,返回的数据是xml符合soap规范。
这个xml的处理也需要一点特殊,首先,xml_parse_into_struct,这个方式可以获取数据,但是得到的数组的格式我看了,不是很容易处理。再有能直接处理的就是这个DOMDocument了。这个获取到的是dom对象,按照上文的代码可以解析,还有另一种方法是解析成数组再处理。
function getArray($node) { $array = false; if ($node->hasAttributes()) { foreach ($node->attributes as $attr) { $array[$attr->nodeName] = $attr->nodeValue; } } if ($node->hasChildNodes()) { if ($node->childNodes->length == 1) { $array[$node->firstChild->nodeName] = getArray($node->firstChild); } else { foreach ($node->childNodes as $childNode) { if ($childNode->nodeType != XML_TEXT_NODE) { $array[$childNode->nodeName][] = getArray($childNode); } } } } else { return $node->nodeValue; } return $array; } $doc=new DOMDocument(); $doc->loadXML($data); $root=$doc->documentElement; //var_dump($root); //print_r($root); //print_r(getArray($root->firstChild)); //print_r(getArray($root->firstChild->firstChild->firstChild->firstChild)); //$items=getArray($root->firstChild->firstChild->firstChild->firstChild); $items=getArray($root->firstChild); //print_r($items); $num=count($items['AisQueryResponse']['AisQueryResult'][0]['AisInfo']); for($i=0;$i<$num;$i++){ echo 'AisID:'.$items['AisQueryResponse']['AisQueryResult'][0]['AisInfo'][$i]['AisID'][0]['#text'].'</br>'; echo 'AisName:',$items['AisQueryResponse']['AisQueryResult'][0]['AisInfo'][$i]['AisName'][0]['#text'],'</br>'; echo 'Number:',$items['AisQueryResponse']['AisQueryResult'][0]['AisInfo'][$i]['Number'][0]['#text'],'</br>'; echo 'Version:',$items['AisQueryResponse']['AisQueryResult'][0]['AisInfo'][$i]['Version'][0]['#text'],'</br>'; }
用getArray函数获取到数组对象,然后处理数组就可以。但是发现1条数据的时候和两条数据的情况数组的深度发生了变化,还没有细研究。
2017-6-1更新:
本来以为上边的代码可以用了,但测试k3v14.2没有问题,测试我们公司正在用的k3v10.3却不能通过。说明他们的服务器本身就不是一样的。侦听了下源码,发现10.3版本的k3需要传递的头是不一样的。改改就可以适配了。主要是curl部分的不同。需要一个SOAPAction。另外再说下一个小工具,SRSniffer,这个软件真不错,其它的软件如Fiddler2等需要做代理啊,或者需要.net环境啊,或者需要只能调试浏览器的通讯什么的,这个真是简单好用。
$ch=curl_init(); curl_setopt($ch,CURLOPT_URL,"http://192.168.100.108/KDWEBSERVICE/Public.asmx"); curl_setopt($ch,CURLOPT_RETURNTRANSFER,1); curl_setopt($ch,CURLOPT_POST,1); //curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type:text/xml"));//k3v14.2 testpass curl_setopt($ch, CURLOPT_HTTPHEADER, Array("Content-Type:text/xml","SOAPAction:\"http://www.kingdee.com/Public/AisQuery\""));//k3v10.3 testpass curl_setopt($ch,CURLOPT_POSTFIELDS,$soap); $data=curl_exec($ch); curl_close($ch);