2012-02-01 14:05

[PHP] 用 SoapServer 建立 Microsoft Office Research Service

這裡我用 Webservice Helper 來處理 WSDL 的問題,所以範例也是 Base 在 Webservice Helper 上面,在開始前請檢查是否有 php_soapphp_xsl 這兩個套件。


為了相容於 Research Service 的名稱空間,在輸出入的定義上需要在包一層資料類型,所以需要以下的類型定義:
StatusResponse.class.php
<?php
/**
 * Return object to Status method
 */
class StatusResponse {
    /** @var string */
    public $StatusResult;
}

Registration.class.php
<?php
/**
 * Input object to Registration method
 */
class Registration {
    /** @var string */
    public $registrationXml;
}

RegistrationResponse.class.php
<?php
/**
 * Return object to Registration method
 */
class RegistrationResponse {
    /** @var string */
    public $RegistrationResult;
}

Query.class.php
<?php
/**
 * Input object to Query method
 */
class Query {
    /** @var string */
    public $queryXml;
}

QueryResponse.class.php
<?php
/**
 * Return object to Query method
 */
class QueryResponse {
    /** @var string */
    public $QueryResult;
}


接著是建立 Web Service 的 Method,主要定義 Registration 跟 Query 這兩個 Method 就可以了,Registration 是用在新增 Research Service 到 Research Pane 時會呼叫的 Method,主要是提供 Research Pane 所需要的 Service 資訊。
而 Query 則是真正再處理資料查詢的 Method,而 QueryResponse 中的 domain 及 QueryId 必需與 QueryXml 中所給的相同,不然 Client 端會無法辨識回傳結果。
<?php
/**
 * Microsoft Office Research Service
 *
 */

class MsOfficeResearch {

    /**
     * Entry point to test if server is alive. Will return 'ONLINE' or 'OFFLINE'
     * @param void
     * @return StatusResponse
     */
    function Status() {
        $result = new StatusResponse;
        $result->StatusResult = 'ONLINE';
        return $result;
    }


    /**
     * Basic registration entry point
     * @param Registration $registrationXml
     * @return RegistrationResponse
     */
    public function Registration($registrationXml) {
//      debugDump('registrationXml: '.$request->registrationXml);

        $dom = new DOMDocument();

        $proUpdate = $dom->createElementNS("urn:Microsoft.Search.Registration.Response",'ProviderUpdate');
        $proUpdate->appendChild( new DOMElement('Status',"SUCCESS") );

        $providers = $proUpdate->appendChild( new DOMElement('Providers') );
        $provider = $providers->appendChild( new DOMElement('Provider') );
        $provider->appendChild( new DOMElement('Id',"{62E1D68D-E1C4-4CC5-9D0C-D4B7999C4B77}") );
        $provider->appendChild( new DOMElement('Name',"Research Service") );
        $provider->appendChild( new DOMElement('QueryPath',"http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']) );
        $provider->appendChild( new DOMElement('RegistrationPath',"http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']) );
        $provider->appendChild( new DOMElement('Type',"SOAP") );
        $provider->appendChild( new DOMElement('Revision',"1") );

        $services = $provider->appendChild( new DOMElement('Services') );
        $service = $services->appendChild( new DOMElement('Service') );
        $service->appendChild( new DOMElement('Id',"{0297CD20-047F-4256-0104-000004040001}") );
        $service->appendChild( new DOMElement('Name',"Research Service Name") );
        $service->appendChild( new DOMElement('Description',"Research Service Description") );
        $service->appendChild( new DOMElement('Copyright',"") );
        $service->appendChild( new DOMElement('Display',"On") );
        $service->appendChild( new DOMElement('Category',"RESEARCH_GENERAL") );

        $response = new RegistrationResponse;
        $response->RegistrationResult = $dom->saveXML($proUpdate);
        return $response;
    }



    /**
     * Basic entrypoint for Query
     * @param Query $queryXml
     * @return QueryResponse
     */
    function Query($queryXml) {
        if(is_object($queryXml)){ $queryXml = $queryXml->queryXml; }
//      debugDump('queryXml: '.$queryXml);

        /*解析請求的 XML*/
        $dom = new DOMDocument();
        $dom->loadXML($queryXml);
        $domain = $dom->getElementsByTagName('Query')->item(0)->getAttribute('domain');
        $queryId = $dom->getElementsByTagName('QueryId')->item(0)->nodeValue;

        /*建立返回的結構*/
        $packet = $dom->createElementNS("urn:Microsoft.Search.Response",'ResponsePacket');
        $packet->setAttribute('revision',"1");
        $response = $packet->appendChild( new DOMElement('Response') );
        $response->setAttribute('domain', $domain );
        $response->appendChild( new DOMElement('QueryId', $queryId) );
        $range = $response->appendChild( new DOMElement('Range') );
        $results = $range->appendChild( new DOMElement('Results') );
        $content = $results->appendChild( new DOMElement('Content',"","urn:Microsoft.Search.Response.Content") );

        /*請求查詢*/
        $status = "ERROR_NO_RESULTS_FOUND";
        $queryText = trim( $dom->getElementsByTagName('QueryText')->item(0)->nodeValue );
        if(!empty($queryText)){
//          debugDump($queryText);
            $line = $content->appendChild( new DOMElement('P') );
            $line->nodeValue = htmlspecialchars($queryText, ENT_QUOTES);
            $status = "SUCCESS";
        }

        $response->appendChild( new DOMElement('Status',$status) );

        /*設定回傳結構*/
        $response = new QueryResponse;
        $response->QueryResult = $dom->saveXML($packet);
        return $response;
    }

}


關於資料交換的 XML 格式如下:
Registration Response XML
<ProviderUpdate xmlns='urn:Microsoft.Search.Registration.Response'>
    <Status>SUCCESS</Status>
    <Providers><Provider>
        <Id>{88686849-2DD9-474d-9300-778E3336FA77}</Id>
        <Name>EpgTools</Name>
        <QueryPath>http://localhost/service.php</QueryPath>
        <RegistrationPath>http://localhost/service.php</RegistrationPath>
        <Type>SOAP</Type>
        <Revision>1</Revision>
        <Services><Service>
            <Id>63d351db-d12e-448b-8541-9f794e1ec977</Id>
            <Name>Research Service Name</Name>
            <Data>1031/1033/4</Data>
            <Description>Research Service Description</Description>
            <AboutPath>helpId:553713956</AboutPath>
            <Copyright>All content Copyright (c) 2003.</Copyright>
            <Display>On</Display>
            <Category>RESEARCH_GENERAL</Category>
            <OptionsPath></OptionsPath>
            <Parental>Unsupported</Parental>
        </Service></Services>
    </Provider></Providers>
</ProviderUpdate>

Query XML
<QueryPacket xmlns="urn:Microsoft.Search.Query" revision="1" build="(11.0.5606)">
    <Query domain="{6E3B8AA1-5131-403E-AEF3-E7AFC2E88557}">
        <QueryId>{5A4FD162-DB71-45BC-8721-F059D28947B3}</QueryId>
        <OriginatorId>{F6FF7BE0-F39C-4ddc-A7D0-09A4C6C647A5}</OriginatorId>
        <SupportedFormats>
            <Format revision="1">urn:Microsoft.Search.Response.Document:Document</Format>
            <Format revision="1">urn:Microsoft.Search.Response.Content:Content</Format>
            <Format revision="1">urn:Microsoft.Search.Response.Form:Form</Format>
        </SupportedFormats>
        <Context>
            <QueryText type="STRING" language="zh-tw">test</QueryText>
            <LanguagePreference>zh-tw</LanguagePreference>
            <Requery></Requery>
        </Context>
        <Range id="result"></Range>
        <OfficeContext xmlns="urn:Microsoft.Search.Query.Office.Context" revision="1">
            <UserPreferences>
                <ParentalControl>false</ParentalControl>
            </UserPreferences>
            <ServiceData>EWATW</ServiceData>
            <ApplicationContext>
                <Name>Microsoft Office</Name>
                <Version>(11.0.5606)</Version>
                <SystemInformation>
                    <SkuLanguage>zh-tw</SkuLanguage>
                    <LanguagePack>zh-tw</LanguagePack>
                    <InterfaceLanguage>zh-tw</InterfaceLanguage>
                    <Location>TW</Location>
                </SystemInformation>
            </ApplicationContext>
            <QueryLanguage>zh-tw</QueryLanguage>
            <KeyboardLanguage>zh-tw</KeyboardLanguage>
        </OfficeContext>
        <Keywords xmlns="urn:Microsoft.Search.Query.Office.Keywords" revision="1">
            <QueryText>test</QueryText>
            <Keyword>
                <Word>test</Word>
            </Keyword>
        </Keywords>
    </Query>
</QueryPacket>

Query Response XML
<ResponsePacket xmlns="urn:Microsoft.Search.Response" revision="1">
    <Response domain="{6e3b8aa1-5131-403e-aef3-e7afc2e88557}">
        <QueryId>{5A4FD162-DB71-45BC-8721-F059D28947B3}</QueryId>
        <Range><Results>
            <Content xmlns="urn:Microsoft.Search.Response.Content">
                <any />
            </Content>
        </Results></Range>
        <Status>SUCCESS</Status>
    </Response>
</ResponsePacket>


範例下載:
SearchService.zip


參考資料:
Serveur SOAP en PHP 5 pour "Microsoft Office Research Service"
The Definitive Hello World Custom Research Service Tutorial
Microsoft.Search.Response.Content Schema Documentation

0 回應: