在PHP中读取SOAP XML

问题描述:

我对我的客户端执行SOAP调用。它将一个XML文档作为字符串返回(这是一种解决方法,我无能为力)。我有一个变量的XML,我需要阅读这个XML来获取我想要的信息。在PHP中读取SOAP XML

我在查找字段DomesticCustomerAddressesGridOwner。我想如果有人帮我找到DomesticCustomer-我可以自己做其余的事情。

注意:在本例中,每个字段下只有一个条目,但可能有多个条目,所以我需要能够对此进行foreach。

注意事项#2:由于我使用的客户端有一些奇怪的解决方法,因此它的响应(xml)是一个简单的字符串。

的XML是:

<?xml version="1.0" encoding="utf-8"?> 
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <soap:Body> 
     <MeteringPointIdResponse xmlns="http://www.ediel.no/schemas/public/nubix/MeteringPointIdResponse"> 
      <RequestId xmlns="">3423424234</RequestId> 
      <Requestor xmlns=""> 
       <GLN>234234234</GLN> 
      </Requestor> 
      <Customers xmlns=""> 
       <DomesticCustomer> 
        <LastName>Name</LastName> 
        <FirstName>Name</FirstName> 
        <BirthDate>xxx-xx-xx</BirthDate> 
        <MeterNumber>xxxxx</MeterNumber> 
        <Addresses> 
         <Address> 
          <Address1>345345</Address1> 
          <PostCode>3514</PostCode> 
          <Location>xxxxxx</Location> 
          <CountryCode>xx</CountryCode> 
          <Installation> 
           <Description>xxxxx</Description> 
           <MeteringPointId>xxxxxxxxxxxxxxx</MeteringPointId> 
           <MeteringMethod>xxxxxx</MeteringMethod> 
           <InstallationStatus>xxxx</InstallationStatus> 
           <LastReadOffDate>xxxx-xx-xx</LastReadOffDate> 
          </Installation> 
          <GridOwner> 
           <GLN>xxxxxxx</GLN> 
           <Name>xxxxxxxx</Name> 
           <ProdatAddress> 
            <InterchangeRecipient> 
             <Id>xxxxxxx</Id> 
             <Qualifier>xx</Qualifier> 
             <Subaddress>xxxxx</Subaddress> 
            </InterchangeRecipient> 
            <Party> 
             <Id>xxxxxxxxxx</Id> 
             <CodeListResponsible>xxxx</CodeListResponsible> 
            </Party> 
            <EDISyntax> 
             <CharSet>xxx</CharSet> 
             <SyntaxId>xxxx</SyntaxId> 
            </EDISyntax> 
            <SMTPAddress>[email protected]</SMTPAddress> 
           </ProdatAddress> 
          </GridOwner> 
         </Address> 
        </Addresses> 
       </DomesticCustomer> 
      </Customers> 
     </MeteringPointIdResponse> 
    </soap:Body> 
</soap:Envelope> 
+0

可能重复[从其他文件的类函数变量](http://*.com/questions/9363308/get-variable-from-other-files-class-function) – Gordon 2012-02-20 15:40:14

+0

你甚至阅读我的问题?这是关于阅读一个变量中的XML文档。尽可能远离相关事物。 – OptimusCrime 2012-02-20 15:43:42

+0

那又如何不重复呢?用SimpleXML加载变量,然后可以像显示的那样访问它。除了如何解析和处理XML之外,SOAP或HTML经常被回答,还有另一个问题要求如何从XML文档中获取''。在你的问题中没有任何具体的东西来证明你没有关闭它。请看右边的相关部分。 – Gordon 2012-02-20 15:54:49

如果您使用内置的库PHP,它解析响应并返回一个混合的对象/数组对象,它是与比XML无穷容易处理

编辑:由于您使用的是PHP内置的客户端,因此这里是我编写的一个简单的类。它 “变平” 的反响,可以很容易地检索像responces:

$soap = new SOAP($wsdl, $options); 
$soap->call("stuff goes here"); 
$soap->find("what you are looking for goes here"); 

    /** 
    * @author Troy Knapp 
    * @copyright 2011 
    * 
    * @version .1.1 
    */ 

class Soap { 

    //***VARIABLES***// 
var $request; //..............string; holds last soap request 
var $requestHeaders; //.......string; holds the headers for the last request 
var $response; //.............string; xml response 
var $responseHeaders; //......string; holds the headers for the last response 
var $result; //...............array; the soap response parsed into an array 
var $wsdlLocation; //.........string; url for the wsdl 
var $parameters; //...........array; saved array of parameters 
var $function; //.............string; name of function to be accessed 
var $findResult = array(); 
var $flatArray = array(); //..array; holds an easy to search array 
// 
//***OBJECTS***// 
var $client; //...................instance of SoapClient 
var $exception; //................obj; SoapFault exception object 
//  
//***DEFAULTS***// 
public $options = array(
    'trace' => 1 
); 

function __construct($wsdl, $options = false) { 
    if ($options == false) { 
     $options = $this->options; 
    } else { 
     $this->options = $options; 
    } 

    $this->wsdlLocation = $wsdl; 

    $this->client = new SoapClient($wsdl, $options); 
} 

/* 
* Executes a given function when supplied the proper function name, 
* parameters and options. 
*/ 
function call($function, $parameters, $options=NULL) { 
    $this->function = $function; 
    $this->parameters = $parameters; 

    try { 
     //$this->response = $this->client->__soapCall($function, $parameters, $options); 
     $this->response = $this->client->$function($parameters, $options); 
    } catch (SoapFault $exception) { 
     $this->$exception = $exception; 
    } 

    //get info about the last request 
    $this->request = $this->client->__getLastRequest(); 
    $this->requestHeaders = $this->client->__getLastRequestHeaders(); 

    //more info about the last responce 
    $this->responseHeaders = $this->client->__getLastResponseHeaders(); 

    //set up an easily searchable array of results 
    $this->flatten(); 

    return $this->response; 
} 

/* 
* Prints all kinds of interesting info about what went on for debugging 
* purposes 
*/ 
function printInfo() { 
    echo '<h2>SoapClient Info:</h2>'; 
    echo 'wsdl location: ' . $this->wsdl_location . '<br/>'; 
    echo 'SoapClient Options:'; 
    echoPre($this->options); 

    echo '<h2>Call Info:</h2>'; 
    echo 'Function Name: ' . $this->function . '<br/>'; 
    echo 'Parameters: '; 
    echoPre($this->parameters); 


    echo '<h2>Last Request: <br></h2>'; 
    echo $this->format($this->request); 

    echo '<h2>Request Headers: <br></h2>'; 
    echo $this->format($this->requestHeaders); 

    echo '<h2>Last Response: <br></h2>'; 
    echoPre($this->response); 

    echo '<h2>Response Headers: <br></h2>'; 
    echo $this->format($this->responseHeaders); 
} 

/* 
* Formats the xml to make it nice and purdy for display and debugging 
* purposes 
*/ 
function format($xml) { 

    // add marker linefeeds to aid the pretty-tokeniser (adds a linefeed between all tag-end boundaries) 
    $xml = preg_replace('/(>)(<)(\/*)/', "$1\n$2$3", $xml); 

    // now indent the tags 
    $token = strtok($xml, "\n"); 
    $result = ''; // holds formatted version as it is built 
    $pad = 0; // initial indent 
    $matches = array(); // returns from preg_matches() 
    // scan each line and adjust indent based on opening/closing tags 
    while ($token !== false) : 

     // test for the various tag states 
     // 1. open and closing tags on same line - no change 
     if (preg_match('/.+<\/\w[^>]*>$/', $token, $matches)) : 
      $indent = 0; 
     // 2. closing tag - outdent now 
     elseif (preg_match('/^<\/\w/', $token, $matches)) : 
      $pad--; 
     // 3. opening tag - don't pad this one, only subsequent tags 
     elseif (preg_match('/^<\w[^>]*[^\/]>.*$/', $token, $matches)) : 
      $indent = 1; 
     // 4. no indentation needed 
     else : 
      $indent = 0; 
     endif; 

     // pad the line with the required number of leading spaces 
     $line = str_pad($token, strlen($token) + $pad, ' ', STR_PAD_LEFT); 
     $result .= $line . "\n"; // add to the cumulative result, with linefeed 
     $token = strtok("\n"); // get the next token 
     $pad += $indent; // update the pad size for subsequent lines  
    endwhile; 

    $result = highlight_string($result); 

    //nl2br(htmlentities($result)); 
    return $result; 
} 

/* 
* Searches the pre flattened array for a given key. If there is only one 
* result, this will return a single value, if there are multiple results, 
* it will return an array of values. 
* 
* @param string; $search - search for a response with this key 
*/ 
function find($search=false) { 
    if ($search == false) { 
     return $this->flatArray; 
    } else { 
     if (isset($this->flatArray[$search])) { 
      $result = $this->flatArray[$search]; 
     } else { 
      return false; 
     } 
    } 

    if(count($result)==1){ 
     return $result[0]; 
    } 
    else{ 
     return $result; 
    } 
} 

/* 
* This method flattens an array/object result into an array that is easy 
* to search through. Search terms are set as keys with results set as 
* arrays owned by said keys. 
*/ 

function flatten($array=false) { 
    if ($array == false) { 
     $array = $this->response; 
    } 
    if (is_object($array)) { 
     //get the variables of object 
     $array = get_object_vars($array); 
    } 

    //howdy('array'); 
    //echoPre($array); 
    //echo "_______________<br>"; 

    if (is_array($array)) { 

     //loop through the sub elements and make sure they are arrays 
     foreach ($array as $key => $value) { 
      //if it's an object, we need to convert it to an array 
      if (is_object($value)) { 
       //get the variables of object 
       $value = get_object_vars($value); 
      } 

      //echo "key: $key value: "; 
      //echoPre($value); 
      //echo "_______________<br>"; 

      //push the key=>value pairs to the flat array 
      if (!isset($this->flatArray[$key])) { 
       $this->flatArray[$key] = array(); 
      } 

      array_push($this->flatArray[$key], $value); 

      if (is_array($value)) { 
       $this->flatten($value); 
      } 
     } 
    } 
} 

function getWSDL() { 
    $wsdl = file_get_contents($this->wsdlLocation); 
} 

}

+0

因为这是我们的提供者的一种解决方法,所以在返回时XML只是一个简单的字符串。我需要获取这个循环的xpath才能工作。 – OptimusCrime 2012-02-20 15:38:52

+0

我已经走下了试图将XML转换为数组的兔子洞,然后遍历该数组尝试解析它的值......除非你比我更聪明,我不会推荐它。 – 2012-02-20 15:49:48

+0

看到我自己的回答belove。这并不困难。 – OptimusCrime 2012-02-20 15:54:51

使用http://php.net/manual/en/class.soapclient.php(在PHP5证明你)

+2

我是......那根本不是这个问题的答案。 – OptimusCrime 2012-02-20 15:39:05

+0

对不起,我读得太快,并认为是错误的东西,我的坏:) – BenOfTheNorth 2012-02-20 15:48:46

它是那么简单。忘记注册名称空间。的

$xml = simplexml_load_string($xml); 
$xml->registerXPathNamespace('soap', 'http://schemas.xmlsoap.org/soap/envelope/'); 
foreach ($xml->xpath('//DomesticCustomer') as $item) 
{ 
    print_r($item); 
} 
+0

你没有在XPath查询中使用名称空间,所以这与注册名称空间无关。证明:http://codepad.viper-7.com/KuvI4C – Gordon 2012-02-20 16:03:13