2012-02-20 215 views
0

我對我的客戶端執行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://stackoverflow.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

回答

1

如果您使用內置的庫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

0

它是那麼簡單。忘記註冊名稱空間。的

$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