php解析webservice服务

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

此条目发表在待分类分类目录。将固定链接加入收藏夹。