Blog

All Blog Posts  |  Next Post  |  Previous Post

Using the Microsoft Bing API from Delphi

Bookmarks: 

Tuesday, July 28, 2009

With the Bing API, Microsoft provides a set of easy to use services that can be useful for your Delphi web applications as well as Win32 applications. A starting point to discover the capabilities of the Bing API is http://www.bing.com/developers. The first thing you need to do to get started with the Bing API is getting a Bing AppID. The URL to apply for a Bing AppID is http://www.bing.com/developers/createapp.aspx. Basically, using the Bing API is free on the condition you respect the Microsoft terms of usage which are fortunately quite flexible.
When you have the AppID, you're ready to start. The easiest way to use the Bing API is by using the HTTP GET request that returns an XML file with results. The Bing API provides access to several search types. The search type is defined as a SourceType. In the v2.0 API, following source types are available:

  • Ad SourceType: get content related ads
  • Image SourceType: search an image
  • InstantAnswer SourceType: get direct answer to questions like "what is the capital city of Germany"
  • MobileWeb SourceType:
  • News SourceType: get information from news headlines
  • Phonebook SourceType: get address & phone number information
  • RelatedSearch SourceType: get a related search question
  • Spell SourceType: perfom spell checking
  • Translation SourceType: perform a translation
  • Video SourceType: search a video
  • Web SourceType: perform a regular web search
Using the Bing API with Delphi can be done with sending a HTTP GET request to api.bing.net with following structure:
http://api.bing.net/xml.aspx?Appid=YourAppID
&Query=YourQueryString
&Sources=YourSourceType(s) + more options

This HTTP GET request returns an XML file containing the results. Delphi 2009 provides all required components to start using the API. You can use the Indy TidHTTP component to do the HTTP GET request and the TXMLDocument component to parse the result XML file. To make it ourselves even easier, we're going to use the TWebCopy component here to get the result XML file and TXMLDocument to parse the result.

Example 1: Searching the web
Searching the web is performed with the 'web' SourceType. A typical request looks like:
http://api.bing.net/xml.aspx?Appid=YourAppID
&Query=Delphi&Sources=web

Optional, we can set the requested number of results and the offset of the result, ie:
http://api.bing.net/xml.aspx?Appid=YourAppID
&Query=Delphi&Sources=web&web.count=20&web.offset=40

To quickly get the result XML file, we use TWebCopy in following way:
  with webcopy.Items.Add do
  begin
    // AppID is a string constant containing our AppID, searchstr is our search query.
    url := 'http://api.search.live.net/xml.aspx?Appid=' + AppID + '&query='+HTTPEncode(searchstr)+'&sources=web&web.count='+inttostr(count)+'&web.offset='+inttostr(offset);
    TargetFilename := 'response.xml';
    Protocol := wpHttp;
  end;
  webcopy.ShowDialog := false;
  webcopy.Execute;
This creates the XML file response.xml in the application folder (don't try this on Windows Vista in the Program Files folder!). We use the standard Delphi component TXMLDocument to parse it to get the Description text for each page found and return this in a TStringList:
  xmldoc := TXMLDocument.Create(application);
  xmldoc.LoadFromFile('response.xml');

  inode := xmldoc.ChildNodes.FindNode('SearchResponse');

  if Assigned(inode) then
  begin
    uri := 'http://schemas.microsoft.com/LiveSearch/2008/04/XML/web';
    mnode := inode.ChildNodes.FindNode('Web',uri);
    if Assigned(mnode) then
    begin
      rnode := mnode.ChildNodes.FindNode('Results',uri);
      if Assigned(rnode) then
      begin
        Result := TStringList.Create;
        for j := 0 to rnode.ChildNodes.Count - 1 do
        begin
          irnode := rnode.ChildNodes.Nodes[j];
          dnode := irnode.ChildNodes.FindNode('Description',uri);
          if Assigned(dnode) then
            Result.Add(dnode.NodeValue);
        end;
      end;
    end;
  end;

  xmldoc.Free;
In this sample code snippet, we simply retriebed the description text Bing shows for the URL's found. We could as well extract the URL itself, page title, timestamp of page, ...

Example 2: Translating a text from English to German
The Bing API also offers a service to translate text from a source language to a target language. The HTTP query is very similar to the web search. We just need to specify the SourceType as Translation and specify the translation source language option and translation target language option. We encapsulated all this in one easy to use function:
function HTTPEncode(const AStr: string): string;
const
  NoConversion = ['A'..'Z', 'a'..'z', '*', '@', '.', '_', '-'];
var
  i: integer;
begin
  Result := '';

  for i := 1 to Length(AStr) do
  begin
    if CharInSet(AStr[i],NoConversion) then
      Result := Result + AStr[i]
    else
      Result := Result + Format('%%%.2x',[ord(AStr[i])]);
  end;
end;

function GetTranslation(text, fromLang, toLang: string): string;
var
  xmldoc: TXMLDocument;
  inode,mnode,rnode,irnode: IXMLNode;
  j: integer;
  uri: string;
  webcopy: TWebCopy;

begin
  Result := '';

  webcopy := TWebCopy.Create(application);

  try
    webcopy.Items.Clear;
    with webcopy.Items.Add do
    begin
      url := 'http://api.search.live.net/xml.aspx?Appid=' + AppID + '&query='+HTTPEncode(text)+
        '&sources=translation'+
        '&Translation.SourceLanguage=' + fromLang +
        '&Translation.TargetLanguage=' + toLang;

      TargetFilename := 'response.xml';
      Protocol := wpHttp;
    end;
    webcopy.ShowDialog := false;
    webcopy.Execute;
  finally
    webcopy.Free;
  end;

  xmldoc := TXMLDocument.Create(application);

  try
    xmldoc.LoadFromFile('response.xml');

    inode := xmldoc.ChildNodes.FindNode('SearchResponse');

    if Assigned(inode) then
    begin
      uri := 'http://schemas.microsoft.com/LiveSearch/2008/04/XML/translation';
      mnode := inode.ChildNodes.FindNode('Translation',uri);
      if Assigned(mnode) then
      begin
        rnode := mnode.ChildNodes.FindNode('Results',uri);
        if Assigned(rnode) then
        begin
          irnode := rnode.ChildNodes.FindNode('TranslationResult',uri);
          if Assigned(irnode) then
            Result := irnode.ChildNodes.FindNode('TranslatedTerm',uri).NodeValue;
        end;
      end;
    end;
  finally
    xmldoc.Free;
  end;
end;

begin
   // sample call:
   ShowMessage(GetTranslation('Hello world','En','De'));
end;
This sample code will translate "Hello world" from English to "hallo Welt" in German.

Example 3: Perform a spelling correction
The Bing API can offer us English spell checking as well. Again, the interface is very similar, ie. a simple HTTP GET request with the SourceType Spell. We also encapsulated this API in one easy to use Delphi function:
function DoSpellCheck(text: string): string;
var
  xmldoc: TXMLDocument;
  inode,mnode,rnode,irnode: IXMLNode;
  j: integer;
  uri: string;
  webcopy: TWebCopy;
begin
  Result := '';

  webcopy := TWebCopy.Create(application);
  try
    with webcopy.Items.Add do
    begin
      url := 'http://api.bing.net/xml.aspx?Appid=' + AppID + '&query='+HTTPEncode(text)+
        '&Sources=Spell&Version=2.0&Market=en-us&Options=EnableHighlighting';

      TargetFilename := 'response.xml';
      Protocol := wpHttp;
    end;
    webcopy.ShowDialog := false;
    webcopy.Execute;
  finally
    webcopy.Free;
  end;

  xmldoc := TXMLDocument.Create(application);
  try
    xmldoc.LoadFromFile('response.xml');

    inode := xmldoc.ChildNodes.FindNode('SearchResponse');

    if Assigned(inode) then
    begin
      uri := 'http://schemas.microsoft.com/LiveSearch/2008/04/XML/spell';

      mnode := inode.ChildNodes.FindNode('Spell',uri);
      if Assigned(mnode) then
      begin
        rnode := mnode.ChildNodes.FindNode('Results',uri);
        if Assigned(rnode) then
        begin
          irnode := rnode.ChildNodes.FindNode('SpellResult',uri);
          if Assigned(irnode) then
            Result := irnode.ChildNodes.FindNode('Value',uri).NodeValue;
        end;
      end;
    end;
  finally
    xmldoc.Free;
  end;
end;

begin
  // sample call with a forced spelling error
  ShowMessage( DoSpellCheck('Mispeling words is a common ocurrence') );
end;
Example 4: Getting an image from the web
While there are a couple of more interesting SourceType's such as News, InstantAnswer, Video, the concept is always identical. In this last example, we use the Bing API to retrieve the first image from the web that matches our search string and display it in the application. We make it ourselves easy here by using the TMS TWebImage that does all the work of downloading and displaying the result image. The resulting code is:
function GetImageLink(searchstr: string): string;
var
  xmldoc: TXMLDocument;
  inode,mnode,rnode,irnode: IXMLNode;
  j: integer;
  uri: string;
  webcopy: TWebCopy;
begin
  Result := '';

  webcopy := TWebCopy.Create(application);
  try
    with webcopy.Items.Add do
    begin
      url := 'http://api.bing.net/xml.aspx?Appid=' + AppID + '&query='+HTTPEncode(searchstr)+'&sources=image&image.count=1';
      TargetFilename := 'response.xml';
      Protocol := wpHttp;
    end;
    webcopy.ShowDialog := false;
    webcopy.Execute;
  finally
    webcopy.Free;
  end;

  xmldoc := TXMLDocument.Create(application);
  try
    xmldoc.LoadFromFile('response.xml');

    inode := xmldoc.ChildNodes.FindNode('SearchResponse');

    if Assigned(inode) then
    begin
      uri := 'http://schemas.microsoft.com/LiveSearch/2008/04/XML/multimedia';
      mnode := inode.ChildNodes.FindNode('Image',uri);
      if Assigned(mnode) then
      begin
        rnode := mnode.ChildNodes.FindNode('Results',uri);
        if Assigned(rnode) then
        begin
          irnode := rnode.ChildNodes.Nodes[0];
          if Assigned(irnode) then
            Result := irnode.ChildNodes.FindNode('MediaUrl',uri).NodeValue;
        end;
      end;
    end;
  finally
    xmldoc.Free;
  end;
end;

begin
  // sample retrieving an image hyperlink and show it on the form using a TWebImage component
  imageurl := GetImageLink('mercedes SL gullwing');
  caption := imageurl;
  Screen.Cursor := crHourGlass;
  WebImage1.URL := imageurl;
  Screen.Cursor := crDefault;
end;
This sample code will show the wonderful Mercedes SL gullwing in a TWebImage component dropped on the form. We hope these samples give you inspiration to add some interesting functionality in your Delphi Win32 or Delphi IntraWeb applications!

Bruno Fierens


Bookmarks: 

This blog post has received 2 comments.


1. Monday, March 22, 2010 at 8:21:54 AM

This is fine for "European" languages but translating from Russian does not work correctly - the XML returned is not correctly formatted and therefore the English returned is garbage. Using JSon does seem to work however.

Peter Manning


2. Monday, June 22, 2015 at 5:46:14 PM

Does the translate example still work?

Alexandre

Garcia alexandre




Add a new comment

You will receive a confirmation mail with a link to validate your comment, please use a valid email address.
All fields are required.



All Blog Posts  |  Next Post  |  Previous Post