C++Builder 5 Developers Guide
We will now examine and use a Web service made available by Google (not implemented in C++Builder 6 Enterprise, but in another development environment), with the obvious functionality to search Google.
Google Web APIs
Information about the official Google Web APIs (Beta 2 at the time of writing this book)as they call themcan be obtained from the Google Web site at http://www.google.com/apis/. I don't know why they call them simple APIs when, in fact, they are APIs made available as a Web service. Anyway, at the aforementioned URL, you can see that it takes only three steps to start to use the Google APIs:
-
Download the developer's kit
-
Create a Google Account
-
Write your program using your license key
The first step is easy and consists of downloading a 658,031 Byte ZIP file with the complete Google API (currently at Beta 2, released April 11, 2002). Samples for Java as well as .NET, an API reference, andmost importantly for usthe GoogleSearch.wsdl file, which contains the WSDL definition for the GoogleSearch Web service. We'll use this file as a starting point in step 3, when we're building our Web service client with C++Builder 6.
Google Search Key
The second step involves creating a Google account. This sounds more dangerous than it really is. The use of the Google API is free (at least at the time of writing), but you need to pass a personal key that will allow you up to 1,000 search queries per day for noncommercial use only. To get this key, you need to register yourself with an existing email address and a password (although you can forget that password). An email message will be sent to the specified account in order to verify the email address. After you've received the email message and clicked the link inside, you will receive a second message with your special Google Search Key. In my case, that key is 1WpiIaxr+k+hbyYbRLZOJfg7X9NgI837. The key is included in the source code, so the project on the CD-ROM with this book will work right from the start, although it will only work 1,000 times each day (for all combined users of the executable). Therefore, you might want to register yourself and get your own personal Google Search key, which entitles you to 1,000 daily search queries for yourself.
Google Search
Armed with the GoogleSearch.wsdl file and the Google Search Key, we can start C++Builder 6 (Professional or Enterprise) and build our Web service client. Start a new C++Builder project and save the (empty) main form in GoogleForm.cpp and the project itself in Google42.bpr . The first thing we need to do now is to generate a C++ import unit for the WSDL definition found in the GoogleSearch.wsdl file, so activate File, New, Other, and select the WSDL Importer Wizard from the Object Repository. Instead of specifying a URL for the Google Search, you can use the local GoogleSearch.wsdl filethis is especially handy in case you do not have a live Internet connection available at all times because all information is in the local WSDL file.
Click on the Next button, which will show a preview of the generated import unit as well as a treeview with the GoogleSearch specific types, interfaces, and methods (as can be seen in Figure 19.12).
Figure 19.12. GoogleSearch types and interfaces.
As we can see in the treeview, there are three structure types: DirectoryCategory , ResultElement , and GoogleSearchResult ; two array types: ResultElementArray and DirectoryCategoryArray ; and one interface called GoogleSearchPort with three member functions: doGetCachedPage , doSpellingSuggestion , and doGoogleSearch . After we click the Finish button, the C++ import unit is generated in file GoogleSearch.cpp with the type definitions in GoogleSearch.h .
To illustrate the things we can do with the result, here are the GoogleSearchResult , ResultElementArray , and ResultElement type summaries with only their __published property names (and not their private fields) taken from the generated GoodleSearch.h file:
class ResultElement : public TRemotable { __published: __property AnsiString summary; __property AnsiString URL; __property AnsiString snippet; __property AnsiString title; __property AnsiString cachedSize; __property bool relatedInformationPresent; __property AnsiString hostName; __property DirectoryCategory* directoryCategory; __property AnsiString directoryTitle; }; typedef DynamicArray<ResultElement*> ResultElementArray; /* "urn:GoogleSearch" */ class GoogleSearchResult : public TRemotable { __published: __property bool documentFiltering __property AnsiString searchComments __property int estimatedTotalResultsCount __property bool estimateIsExact __property ResultElementArray resultElements __property AnsiString searchQuery __property int startIndex __property int endIndex __property AnsiString searchTips __property DirectoryCategoryArray directoryCategories __property double searchTime };
The GoogleSearchPort interface with its three methods and their arguments is defined as follows :
__interface INTERFACE_UUID("{0B396A82-A4DD-69A7-A771-6D80F8831A71}") GoogleSearchPort : public IInvokable { public: virtual TByteDynArray doGetCachedPage(const AnsiString key, const AnsiString url) = 0; virtual AnsiString doSpellingSuggestion(const AnsiString key, const AnsiString phrase) = 0; virtual GoogleSearchResult* doGoogleSearch(const AnsiString key, const AnsiString q, const int start, const int maxResults, const bool filter, const AnsiString restrict, const bool safeSearch, const AnsiString lr, const AnsiString ie, const AnsiString oe) = 0; }; typedef DelphiInterface<GoogleSearchPort> _di_GoogleSearchPort;
And, of course, we also have the helpful GetGoogleSearchPort() function that will return the _di_GoogleSearchPort interface for instant use.
As you might have realized by now, the DirectoryCategory is not a type that we will use at this time, but the ResultItem and GoogleSearchResult are the two result classes that will be used in this section. The GoogleSearchResult contains the resultElements property that points to an array of ResultItems . Finally, the method goGoogleSearch() of the GoogleSearchPort interface is the most interesting, so let's examine that one in more detail.
doGoogleSearch
The definition of the doGoogleSearch() method of the GoogleSearchPort interface is as follows (this time with some meaningful comments for each argument):
virtual GoogleSearchResult* doGoogleSearch(const AnsiString key, // your own Google Search Key const AnsiString q,; // query string const int start, // start URLs const int maxResults, // maximum results const bool filter, // filter alike results? const AnsiString restrict, // restrictions const bool safeSearch, // adult filter? const AnsiString lr, // language? const AnsiString ie, // input encoding const AnsiString oe) = 0; // output encoding
Ouch! A lot of arguments, that's for sure. Fortunately, the Google Search API ZIP-file that we downloaded earlier also contains a file APIs_Reference.html (of 100,417 bytes) containing more information about the search request formats and search results formats; including the meaning of the arguments to doGoogleSearch() .
The key argument is the Google Search Key that you have to obtain (we can use the key 1WpiIaxr+k+hbyYbRLZOJfg7X9NgI837). The q argument is the actual query (there's a subsection on the complete query syntax, which includes the site: option to specify that you want to search within a specific Web site). The start argument specifies where you want to start the results, and maxResults specifies how many results you want to receive (with a maximum of 10). Because you can only get a maximum of 10 results at a given time, start can be used to specify where to start. If start is 0, you get the first 10 results. To get the next 10 results, you must pass a value of 10 in start , and so on. This will quickly consume your 1,000 available daily queries, so be aware not to use this to obtain all 142,000 results for "Dr. Bob" on the Web. Personally, I think the first 10 results are just fine, so I use 0 for start and 10 for maxResults . The filter argument can be used to filter results that are very similar, something that I also often use at Google myself , so I pass true as value for filter . The restrict argument can be used to restrict the search query to a specific country or topic within Google. The safeSearch argument can be set to true to make sure you don't get any "adult" search results. Handy if you want to build your own custom search engine for your kids at home (although I haven't tested this fully to make sure it really works as advertised). The lr argument is a bit similar to the restrict argument, and can be used to select results in a specific language ( lr ), such as Dutch or English (there seem to be no distinction between English, American English, or any of the other English dialects). Finally, the ie and oe arguments specify the Input and Output Encoding, which can be set to latin1 for Dutch and English (see the reference document for more information).
In short, my call to doGoogleSearch() , for a given query string inside an TEdit called edtQuery , would look as follows:
GetGoogleSearchPort()->doGoogleSearch("1WpiIaxr+k+hbyYbRLZOJfg7X9NgI837", edtQuery->Text, 0, 10, True, "", True, "lang_en", "latin1", "latin1");
This would give us a result of type GoogleSearchResult , which is derived from TRemoteable . GoogleSearchResult is covered next.
GoogleSearchResult
The GoogleSearchResult has a number of useful properties such as estimatedTotal ResultsCount , searchTime , and resultElements . The last one is an array of which the elements are of type ResultElement , having a number of interesting subproperties such as title , URL , and cachedSize . We can use a TStringGrid to display the results. In fact, let's now build the GUI and actually write some code. The steps are as follows:
-
Drop a TPanel component on the GoogleForm . Set its Align property to alTop , and clear the Caption property.
-
Drop a TButton component on the right of the TPanel , set its Name property to btnSearch , its Caption property to Search , the Anchor->Right subproperty to true , and the Anchor->Left subproperty to false. These last two changes will ensure the button stays glued to the right of the panel, even if you resize the GoogleForm .
-
Drop a TEdit component on the left side of the TPanel , and resize, so it almost reaches the TButton (see Figure 19.13). Set its Name to edtQuery , clear the Text property, and set the Anchor->Right subproperty to true .
Figure 19.13. GoogleSearch Output.
-
Drop a TStringGrid component on the GoogleForm , right under the TPanel , set its Align property to alClient , so the TStringGrid occupies the remainder of the GoogleForm . Set its ColCount property to 4, its RowCount property to 11 (that's 10 plus the header), set the DefaultRowHeight property to 21, and finally set the Options->goRowSelect subproperty to true.
-
Now, resize the Form to make the StringGrid fit without scrolling. To initialize the columns of the StringGrid , write the follow code in the OnCreate event handler of the Form :
void __fastcall TForm1::FormCreate(TObject *Sender) { StringGrid1->ColWidths[0] = 20; StringGrid1->ColWidths[1] = (StringGrid1->ClientWidth - 55) / 2; StringGrid1->ColWidths[2] = StringGrid1->ColWidths[1]; StringGrid1->ColWidths[3] = 32; StringGrid1->Cells[0][0] = (AnsiString)" #"; StringGrid1->Cells[3][0] = (AnsiString)" KB"; }
The OnClick event handler of the TButton component can be used to make the call to doGoogleSearch and show the results inside the TStringGrid component. This code is as follows:
void __fastcall TForm1::btnSearchClick(TObject *Sender) { for (int row=1; row<=10; row++) for (int col=0; col<=3; col++) StringGrid1->Cells[col][row] = ""; // clear StringGrid GoogleSearchResult* Results = GetGoogleSearchPort()->doGoogleSearch("1WpiIaxr+k+hbyYbRLZOJfg7X9NgI837", edtQuery->Text, 0, 10, True, "", True, "lang_en", "latin1", "latin1"); Caption = IntToStr(Results->estimatedTotalResultsCount) + " results in " + FloatToStr(Results->searchTime) + " seconds."; for (int i=Results->resultElements.Low; i <= Results->resultElements.High; i++) { StringGrid1->Cells[0][i+1] = IntToStr(i+1); StringGrid1->Cells[1][i+1] = Results->resultElements[i]->title; StringGrid1->Cells[2][i+1] = Results->resultElements[i]->URL; StringGrid1->Cells[3][i+1] = Results->resultElements[i]->cachedSize; } }
The result is a Windows application that can be used to enter a number of search words and return the top 10 URLs. To jump directly to one of the resulting URLs, we only have to implement the OnDlbClick event handler of the TStringGrid , as follows:
void __fastcall TForm1::StringGrid1DblClick(TObject *Sender) { TStringGrid* SG = dynamic_cast<TStringGrid*>(Sender); ShellExecute(Handle,"open",SG->Cells[2][SG->Row].c_str(),NULL,0,SW_NORMAL); }
The best thing is that you can integrate this feature in your own (noncommercial) applications as well, of course. As long as an Internet connection is available to talk to Google's official Search Web service.
Apart from searching for keywords in a Windows GUI application (or added as a dialog to your own application), another good use of this functionality could be to add it to a Web site, transformed as Web server application. In that case, you can prefix the Query text with the site: keyword, including the name of the Web site you're looking at. For example, " site:www.drbob42.com " to look for the keyword in pages on my own Web site. As an example of the output, take a look at Figure 19.14 which shows a search for the BizSnap WebServices SOAP combination in the site:www.drbob42.com .
Figure 19.14. GoogleSearch Web sitespecific results.
|
Top |