Example of using the SPServices Search web service

24 Sep

Instead of CAML you can also use a search query by using SQL or keyword syntax to search the SharePoint environment client-side by using the Search web service. The SPServices library supports the Query operation to do this.      

Hereby I show you a few examples of how to use it.      

First let’s start building the query. The query is based on the Microsoft.Search.Query schema, which can be found here: http://msdn.microsoft.com/en-us/library/ms563775.aspx      

A query using keyword syntax:      

var queryText = "<QueryPacket xmlns='urn:Microsoft.Search.Query' Revision='1000'>"
queryText += "<Query>"
queryText += "<Context>"
queryText += "<QueryText language='en-US' type='STRING'>"
queryText += "Estonia";
queryText += "</QueryText>"
queryText += "</Context>"
queryText += "</Query>"
queryText += "</QueryPacket>";

To fire this query by the Query operation of the Search web service via SPServices the following code can be used:

        var title, url = "";

        $().SPServices({
            operation: "Query",
            queryXml: queryText,
            completefunc: function(xData, Status) {
                $(xData.responseXML).find("QueryResult").each(function() {
                    //let's see what the response looks like
                    $("#result").text($(this).text());
                });
            }
        });

       

#results is a div element with the id results to show the response of the query web service. The response format returned by the query web service for the Query operation is described by the Microsoft.Search.Response schema (http://msdn.microsoft.com/en-us/library/ms578335.aspx)      

The result of running the above example:

<ResponsePacket xmlns="urn:Microsoft.Search.Response">
  <Response>
    <Range>
      <StartAt>1</StartAt>
      <Count>1</Count>
      <TotalAvailable>1</TotalAvailable>
      <Results>
        <Document relevance="428" xmlns="urn:Microsoft.Search.Response.Document">
          <Title>Estonia</Title>
          <Action>
            <LinkUrl size="0" fileExt="aspx">http://your_url/Lists/Country/DispForm.aspx?ID=24</LinkUrl>
          </Action>
          <Description />
          <Date>2010-04-08T13:45:47+02:00</Date>
        </Document>
      </Results>
    </Range>
    <Status>SUCCESS</Status>
  </Response>
</ResponsePacket>

       

One result is returned here to show a simple and small piece of xml. The results element contains the actual result of the query, the document element contains a single content item in the search results.      

A query using SQL syntax:

var queryText = "<QueryPacket xmlns='urn:Microsoft.Search.Query' Revision='1000'>"
queryText += "<Query>"
queryText += "<Context>"
queryText += "<QueryText language='en-US' type='MSSQLFT'>"
queryText += "SELECT Title, Rank, Size, Description, Write, Path FROM portal..scope() WHERE CONTAINS ('Estonia') ORDER BY \"Rank\" DESC"
queryText += "</QueryText>"
queryText += "</Context>"
queryText += "</Query>"
queryText += "</QueryPacket>";

And the result:

<ResponsePacket xmlns="urn:Microsoft.Search.Response">
  <Response>
    <Range>
      <StartAt>1</StartAt>
      <Count>1</Count>
      <TotalAvailable>1</TotalAvailable>
      <Results>
        <Document xmlns="urn:Microsoft.Search.Response.Document">
          <Action>
            <LinkUrl fileExt="aspx">http://your_url/Lists/Country/DispForm.aspx?ID=24</LinkUrl>
          </Action>
          <Properties mlns="urn:Microsoft.Search.Response.Document.Document">
            <Property>
              <Name>TITLE</Name>
              <Type>String</Type>
              <Value>Estonia</Value>
            </Property>
            <Property>
              <Name>RANK</Name>
              <Type>Int64</Type>
              <Value>1000</Value>
            </Property>
            <Property>
              <Name>SIZE</Name>
              <Type>Int64</Type>
              <Value>0</Value>
            </Property>
            <Property>
              <Name>WRITE</Name>
              <Type>DateTime</Type>
              <Value>2010-04-08T13:45:47+02:00</Value>
            </Property>
            <Property>
              <Name>PATH</Name>
              <Type>String</Type>
              Value>http://your_url/Lists/Country/DispForm.aspx?ID=24</Value>
            </Property>
          </Properties>
        </Document>
      </Results>
    </Range>
    <Status>SUCCESS</Status>
  </Response>
</ResponsePacket>

The results of the keyword and SQL syntax are slightly different. Keep this in mind while traversing the xml and getting the title for instance.
By using the SQL syntax and getting the title in the resulting xml, the Property element is involved:

        $().SPServices({
            operation: "Query",
            queryXml: queryText,
            completefunc: function(xData, Status) {
                $(xData.responseXML).find("QueryResult").each(function() {
                    var x = $("<xml>" + $(this).text() + "</xml>");
                    //let's see what the response looks like
                    //$("#result").text($(this).text());

                    //traverse the xml to get the items
                    x.find("Document").each(function() {

                        //when using SQL syntax
                        url = $("Action>LinkUrl", $(this)).text();
                        $(this).find("Property").each(function() {
                            if ($("Name", $(this)).text() == "TITLE") {

                                title = $("Value", $(this)).text();
                            }
                        });
                        //end SQL syntax

                        $("#result").text("title: " + title + " - LinkUrl: " + url);
                    });
                });
            }

        });

By using the keyword syntax and getting the title, it’s just a direct child element of the Document element and this code can be used:      

        $().SPServices({
            operation: "Query",
            queryXml: queryText,
            completefunc: function(xData, Status) {
                $(xData.responseXML).find("QueryResult").each(function() {
                    var x = $("<xml>" + $(this).text() + "</xml>");
                    //let's see what the response looks like
                    //$("#result").text($(this).text());

                    //traverse the xml to get the items
                    x.find("Document").each(function() {
                        url = $("Action>LinkUrl", $(this)).text();
                        //when using keyword syntax
                        title = $("Title", $(this)).text();
                        //end keyword syntax
                        $("#result").text("title: " + title + " - LinkUrl: " + url);
                    });
                });
            }
        });

       

The examples described here give just one result for demonstration purposes. This can be seen at the elements count and totalavailable in the result xml. Count is the actual number of items returned, while totalavailable is the total number of results returned by the query web service. When getting real life results please mind the number of items returned by default is 10. Of course the query can be adjusted with a custom count:      

var queryText = "<QueryPacket xmlns='urn:Microsoft.Search.Query' Revision='1000'>"
queryText += "<Query>"
queryText += "<Range><Count>50</Count></Range>";
queryText += "<Context>"
queryText += "<QueryText language='en-US' type='STRING'>"
queryText += "Estonia";
queryText += "</QueryText>"
queryText += "</Context>"
queryText += "</Query>"
queryText += "</QueryPacket>";

      

To fully optimize the query to your needs please check out the Microsoft.Search.Query schema for a lot of useful options.

32 Replies to “Example of using the SPServices Search web service

  1. Pingback: Tweets die vermelden Example of using the SPServices Search web service -- Topsy.com

  2. Is there a way to get the text? Whether it contains “SUCCESS” or “ERROR_NO_RESULTS_FOUND”?

    Thanks,

    Luis

  3. Hey, have been looking for opinions of people who have tried this out first hand, and after hunting through bing, I stumbled upon your write up, and it islovely blog. Too bad I took this long getting to read your article. Saved you in my bookmarks already. Shall come back pretty soon. Keep on writing your blog will get really popular.

  4. Fantastic blog! I really appreciate how it? s quick on my eyes as well as the Information are well written. I’m questioning how i may be notified when a brand new publish continues to be made. I’ve subscribed for your rss feed which want to accomplish the trick! Possess a great day!

  5. When parsing XML in other contexts, you don’t have to bind to the <xml> node. Any thoughts as to why you have to with search results?

    Also in the response packet, there isn’t a “QueryResponse” node. How can a newbie learn these different nuances on their own? I appreciate your thoughts.

    Cheers,
    Matt

  6. Hi Matt,

    In the response a “QueryResponse” node can be found. In the above examples I use “QueryResult” nodes directly to get to the result nodes.
    The result I show in the examples is the content of the QueryResult node which starts with “ResponsePacket”.
    The full response when questioning:

    $("#result").text(xData.responseXML.xml);
    

    before:

    $(xData.responseXML).find("QueryResult").each(function () {
    

    shows the really raw 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>
        <QueryResponse xmlns="urn:Microsoft.Search">
          <QueryResult>[text]&lt;ResponsePacket xmlns="urn:Microsoft.Search.Response"&gt;&lt;Response&gt;&lt;Range&gt;
    <intentionally left out for readibility>
    ;&lt;/Range&gt;&lt;Status&gt;SUCCESS&lt;/Status&gt;&lt;/Response&gt;&lt;/ResponsePacket&gt;[/text]</QueryResult>
        </QueryResponse>
      </soap:Body>
    </soap:Envelope>
    

    (The text and /text aren’t part of it, but it keeps interpreting…)
    Binding the result to the node was neccesary in this case to perform a “find” method on it.
    As you can see the contents of the QueryResult node contains encoded xml. The result of $(“#result”).text($(this).text()) is decoded xml. So I thought I could use the find method on it, but it didn’t work. When explicitly binding to the xml node the find method worked. I don’t have a conclusive explanation for it.

    Lateron this code is used:

    $(this).find("Property").each(function () {
    

    this works, because $(this) is the result of:

    x.find("Results").each(function () {
    

    and apparently valid xml.

    Regards, Anita

  7. Hrmmm… It’s still all a little confusing, but thanks for your reply. When I write $(xData.responseXML.xml) to a textarea, the first node that appears is <ResponsePacket xmlns=”urn:Microsoft.Search.Response”>. I don’t see any of the raw xml as you’ve described. Do you think the textarea is stripping out some of my results?

    Cheers,
    Matt

  8.         $().SPServices({
                operation: "Query",
                queryXml: queryText,
                completefunc: function (xData, Status) {
                    $("#result").text(xData.responseXML.xml);
                    $(xData.responseXML).find("QueryResult").each(function () {
    

    Did you try like the above code?
    Put it in a CEWP to get the full XML.

    Can you let me know what your results are?

    Regards, Anita

  9. Thanks Anita! Using that method, I do get the whole <xml> and all of the nodes you’ve described. I definitely wasn’t using .text() and I’m sure that was the problem. I’m going to use that from now on. I’m sure it’ll come in handy.

  10. Pingback: Sharepoint Field Types « Alen Ziver Malhasoglu's Microsoft Commerce Server Blog

  11. Thanks much for the post!
    How do I filter on datetime column?

    For example, this query below is filtering on Write column > ‘2011-03-11 10:59:44.000’.Here the date value(2011-03-11) is taken into account but time value(10:59:44.000) is ignored.

    How can I also include the Timevalue for comparison?

    var queryText = “”

    queryText += “”

    queryText += “”

    queryText += “”

    queryText += “SELECT Title, Rank, Size, Description, Write, Path FROM portal..scope() WHERE CONTAINS (‘Estonia’) AND “\Write\” > ‘2011-03-11 10:59:44.000’ ORDER BY \”Rank\” DESC”

    queryText += “”

    queryText += “”

    queryText += “”

    queryText += “”;

  12. Hi Anita

    Thankyou very much for preparing this post. Succinct, easy to follow and very informative. Very grateful for the efforts of people like yourself in sharing your knowledge.

    Joel

  13. Just wanted to mention in case anyone gets this: when you try to use the MSSQLFT in SharePoint Foundation 2010 without search server (you would have to rename the ‘Search’ method in SPServices to become “SPSearch” instead), a straightforward query will get the error that “your query is malformed”. The issue is mentioned at http://social.technet.microsoft.com/Forums/en-US/sharepointsearch/thread/fc9f8c5f-0c91-4c60-beda-c33ac8ca8ed7/ and the problem is that SharePoint adds a site context after your sql string (even though you are specifying your context in your query text). So, to fix it, you add a space and 2 dashes at the end of your sql to effectively make that context thing become a comment, then your SQL should work just fine.

  14. Hi Brendan,

    Actually, I’m using Sharepoint Foundation 2010 and trying to query something from my custom site, I have got the error message “Your query is malformed” as you mentioned.
    My Query as below:
    String queryText = “”;
    queryText += “”;
    queryText += “”;
    queryText += “”;
    queryText += “SELECT Title from Scope() –“;
    queryText += “”;
    queryText += “”;
    queryText += “”;
    queryText += “”;

    What can I do to get it works? As you said I need to rename the “Search” to become “SPSearch”, where can I find the “Search” text?

  15. how to change the number of item been displayed in the result. for me it is always 10.

    How to paginate the results.

    Thanks
    Janesh

  16. Hey Anita,
    great article. I have a question referencing managed properties.

    I try to get search results via javascript by using the “Query” method of the /_vti_bin/search.asmx webservice (I am using spservices). The default fields are in the result, but I have a problem with managed properties. If I modify the Request XML by adding a properties tag with property tags in it the service answers “BAD REQUEST”.

    When I am using a coreresultswebpart, I get the managed properties I want (So the fields are correctly crawled).

    Here is my code example (if I comment the properties tags it works!):
    function MySearch(request) {
    var queryText = “”;
    queryText += “20”;
    queryText += “”;
    queryText += “”;
    queryText += “”;
    queryText += “ContentType:’SomeContentType’ ” + request.term;
    queryText += “”;
    queryText += “”;
    queryText += “3”;
    queryText += “”;
    queryText += “”;
    queryText += “”;
    queryText += “”;
    queryText += “”;

    $().SPServices({
    operation: “Query”,
    queryXml: queryText,
    completefunc: function(xData, Status) {
    // work with result…
    }
    });
    }

    How can I receive managed properties by using the serach.asmx?

    I tried also to use the GetSearchMetadata operation, but I do not know how to use it correctly.
    http://msdn.microsoft.com/de-de/library/websvcsearch.queryservice.getsearchmetadata(v=office.14).aspx

    Any ideas?

    Thanks
    Björn

  17. Can you tell me which version of jQuery and SPServices this works with. I’m using jQuery 1.10 and SPServices 2013 and it returns the responseText and responseXML but x.find(“Document”) finds nothing. The data is there however.

  18. Hi Clem,

    Sorry for the very late response, but I guess I used jQuery 1.3 and SPServices 0.5.4 at the time of writing.

    Regards, Anita

  19. Hi Anita,
    Thanks for your post. I have it working in dev but I’m having issues with prod. xData.responseXML is undefined. Below is my code

    // JavaScript Document
    $( document ).ready(function() {
    // alert(‘jquery’);
    // alert($().SPServices.SPGetCurrentSite());
    var queryText = “”
    queryText += “”
    queryText += “”
    queryText += “”
    queryText += “Medical”;
    queryText += “”
    queryText += “”
    queryText += “”
    queryText += “”;

    var title, url = “”;

    $().SPServices({
    operation: “Query”,
    queryXml: queryText,
    completefunc: function(xData, Status) {
    alert(xData.responseText); //this works
    alert(typeof xData.responseXML); // undefined
    $(xData.responseXML).find(“QueryResult”).each(function() {
    //let’s see what the response looks like
    $(“#result”).text($(this).text()); //nothing is displayed
    });
    }
    });
    });

    here’s what xData.responseText returns

    <?xml version=”1.0″ encoding=”utf-8″?><ResponsePacket xmlns=”urn:Microsoft.Search.Response”><Response><Range><StartAt>1</StartAt><Count>10</Count><TotalAvailable>115</TotalAvailable><Results><Document relevance=”11.103638648986816″ xmlns=”urn:Microsoft.Search.Response.Document”><Titl

  20. Had a few issues with the Search Results and I am not normally a sharing guy but here go

    1) Have to pre-parse the results to xml before I could get them to work
    2) Added xml attributes for size and filetype to results

    $().SPServices({
    operation: “Query”,
    queryXml: queryText,
    completefunc: function (data, status) {
    $(data.responseXML).find(“QueryResult”).each(function () {
    //Convert text results to XML document
    var x = “” + $(this).text() + “”;
    var xmlDoc = $.parseXML(x);
    x = $(xmlDoc);

    //traverse the xml to get the items
    x.find(“Document”).each(function() {
    url = $(“Action>LinkUrl”, $(this)).text();
    title = $(“Title”, $(this)).text();
    size = $(“Action>LinkUrl”, $(this)).attr(‘size’);
    ext = $(“Action>LinkUrl”, $(this)).attr(‘fileExt’);
    desc = $(“Description”, $(this)).text();

    $(“#results”).append(“” + title + “ size:” + size + ” ext:” + ext + “” + desc + “”);
    });
    });
    }
    });

  21. Hi Anita,

    I get an XML response when I use the code with this line: $(“#result”).text($(this).text());

    …but not when using the code that traverses the XML. I’m using SP2007. Please help.

  22. Hi Mohamed,

    What is the result of $(“#result”).text($(this).text());?
    Does the XML response contain “Document” items?

    Regards, Anita

Comments are closed.