到目前为止,本教程一直在讨论通过 Java 应用程序使用 API 来达到 Google Web 服务的使用目的,但这只是一种方便的办法。可以直接通过 SOAP 消息(在 http://api.google.com/search/beta2)使用服务本身。
SOAP 消息携带有关执行服务器端子程序的信息,参数在消息体内指定。服务器将发送一条 SOAP 消息作为响应,并在消息体内对信息进行编码。
然后,应用程序接收到响应,要么将其作为单独的信息处理,要么使用传统的 XML 方法对数据进行转换。
这一章将着眼于请求和响应 SOAP 消息和发送、接收消息的 JAXM 应用程序。(若想更多的了解使用 JAXM 发送、接收 SOAP 消息的信息,请参阅构建使用 Google API 的 Java 应用程序参考资料。)
首先,请看一个 JAXM 应用程序,它发送一条预先定义好的 SOAP 消息,并输出结果。
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPElement;
import java.io.FileInputStream;
import javax.xml.transform.stream.StreamSource;
import javax.xml.messaging.URLEndpoint;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamResult;
public class GoogleSOAP {
public static void main(String args[]) {
try {
//First create the connection
SOAPConnectionFactory soapConnFactory =
SOAPConnectionFactory.newInstance();
SOAPConnection connection =
soapConnFactory.createConnection();
//Next, create the actual message
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
//Create objects for the message parts
SOAPPart soapPart = message.getSOAPPart();
//Populate the Message
StreamSource preppedMsgSrc = new StreamSource(
new FileInputStream("search.msg"));
soapPart.setContent(preppedMsgSrc);
//Save the message
message.saveChanges();
//SEND THE MESSAGE AND GET A REPLY
//Set the destination
URLEndpoint destination =
new URLEndpoint("http://api.google.com/search/beta2");
//Send the message
SOAPMessage reply = connection.call(message, destination);
//SAVE THE OUTPUT
//Create the transformer
TransformerFactory transformerFactory =
TransformerFactory.newInstance();
Transformer transformer =
transformerFactory.newTransformer();
//Extract the content of the reply
Source sourceContent = reply.getSOAPPart().getContent();
//Set the output for the transformation
StreamResult result=new StreamResult("results.out");
transformer.transform(sourceContent, result);
//Close the connection
connection.close();
} catch(Exception e) {
System.out.println(e.getMessage());
}
}
}
这个应用程序首先创建了一个连接,然后是一个 SOAPMessage 对象。文件 search.msg 将填入消息的 SOAPPart,接着它会被发给 Google Web 服务。
以另外一条 SOAP 消息的形式,回复得以返回,它的相关信息在 SOAPPart 中。在这种情况下,实际上您并没有转换信息,而只是将 Transformer 用作序列化器把结果发给 results.out 文件。
在下几屏中,我会分析实际的消息。
搜索请求 SOAP 消息包含的参数和以前 API 所设置的完全相同,不过,现在这些参数是 XML 元素:
<?xml version='1.0' encoding='UTF-8'?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1: doGoogleSearch xmlns:ns1="urn:GoogleSearch"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<key xsi:type="xsd:string">00000000000000000000000000000000</key> <q xsi:type="xsd:string">"science fiction"</q>
<start xsi:type="xsd:int">0</start>
<maxResults xsi:type="xsd:int">10</maxResults>
<filter xsi:type="xsd:boolean">true</filter>
<restrict xsi:type="xsd:string"></restrict>
<safeSearch xsi:type="xsd:boolean">false</safeSearch>
<lr xsi:type="xsd:string"></lr>
<ie xsi:type="xsd:string">latin1</ie>
<oe xsi:type="xsd:string">latin1</oe>
</ns1: doGoogleSearch >
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
请注意,doGoogleSearch 这个方法名是在消息内指定的,而且列出了每个参数,即使是空值的参数。这与执行以下的方法是一样的:
doGoogleSearch("", ""science fiction"", 0, 10, true, "", false, "", "latin1",
"latin1")
结果 XML 文件携带的信息和 API 所提取的一样。以下所示的部分结果添加了一些空格以增加其易读性。
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:doGoogleSearchResponse
xmlns:ns1="urn:GoogleSearch"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="ns1:GoogleSearchResult">
<documentFiltering xsi:type="xsd:boolean">false</documentFiltering>
<estimatedTotalResultsCount xsi:type="xsd:int">
1500000</estimatedTotalResultsCount>
<directoryCategories
xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns2:Array"
ns2:arrayType="ns1:DirectoryCategory[0]">
</directoryCategories>
<searchTime xsi:type="xsd:double">0.060022</searchTime>
<resultElements
xmlns:ns3="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns3:Array" ns3:arrayType="ns1:ResultElement[10]">
<item xsi:type="ns1:ResultElement">
<cachedSize xsi:type="xsd:string">29k</cachedSize>
<hostName xsi:type="xsd:string"/>
<snippet xsi:type="xsd:string">
<b>...</b> After a long career creating superior
<b>science</b>-<b>fiction</b> TV,
writer/producer David Kemper<br> reflects on the finale of
Farscape's current season and his startling <b>...</b>
</snippet>
<directoryCategory xsi:type="ns1:DirectoryCategory">
<specialEncoding xsi:type="xsd:string"/>
<fullViewableName
xsi:type="xsd:string">Top/Arts/Literature/Genres/Science_Fiction
/Magazines_and_E-zines</fullViewableName>
</directoryCategory>
<relatedInformationPresent xsi:type="xsd:boolean">
true
</relatedInformationPresent>
<directoryTitle xsi:type="xsd:string">
<b>Science</b> <b>Fiction</b> Weekly
</directoryTitle>
<summary xsi:type="xsd:string">
The leading electronic publication covering the world of
<b>Science</b> <b>Fiction</b>, with news,
reviews, original...
</summary>
<URL xsi:type="xsd:string">http://www.scifi.com/sfw/</URL>
<title xsi:type="xsd:string">
<b>Science</b> <b>Fiction</b> Weekly
</title>
</item>
...
</resultElements>
<endIndex xsi:type="xsd:int">10</endIndex>
<searchTips xsi:type="xsd:string"/>
<searchComments xsi:type="xsd:string"/>
<startIndex xsi:type="xsd:int">1</startIndex>
<estimateIsExact xsi:type="xsd:boolean">false</estimateIsExact>
<searchQuery xsi:type="xsd:string">
&quot;science fiction&quot;
</searchQuery>
</return>
</ns1:doGoogleSearchResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
请注意,API 检索到的每条信息都可以在 XML 元素中使用。
利用结果与为将结果转换为需要的格式而创建一个样式表都很简单。例如,简单的样式表能提取站点标题和 URL:
<?xml version="1.0"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates select="//item"/>
</xsl:template>
<xsl:template match="item">
<xsl:value-of select="title"disable-output-escaping="yes"/><xsl:text>
</xsl:text><xsl:value-of select="URL"/><xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
接下来应用程序将调用该样式表……
...
//Create the transformer
TransformerFactory transformerFactory =
TransformerFactory.newInstance();
Source styleSheet = new StreamSource("translate.xsl");
Transformer transformer =
transformerFactory.newTransformer( styleSheet );
//Extract the content of the reply
Source sourceContent = reply.getSOAPPart().getContent();
//Set the output for the transformation
StreamResult result=new StreamResult("results.out");
transformer.transform(sourceContent, result);
...
……得到的是格式很规范的结果:
<b>Science</b> <b>Fiction</b> Weekly
http://www.scifi.com/sfw/
SCIFI.COM
http://www.scifi.com/
<b>Science</b> <b>Fiction</b> and Fantasy Writers of America, Inc.
http://www.sfwa.org/
The Link ping <b>Science</b> <b>Fiction</b> & Fantasy Archive
http://www2.lysator.liu.se/sf_archive/
...
请注意这只是很简单的示例。您可以使用 XSLT 来提取,甚至处理数据以使其可以包括在数据库和其它系统中,并使其可以为其它应用程序所用。
拼写建议的 SOAP 消息很直观。
请求:
<?xml version='1.0' encoding='UTF-8'?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:doSpellingSuggestion
xmlns:ns1="urn:GoogleSearch"
SOAP-ENV:encodingStyle=
"http://schemas.xmlsoap.org/soap/encoding/">
<key xsi:type="xsd:string">00000000000000000000000000000000</key>
<phrase xsi:type="xsd:string">scince</phrase>
</ns1:doSpellingSuggestion>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
结果:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"xmlns:xsd=
"http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:doSpellingSuggestionResponse xmlns:ns1="urn:GoogleSearch"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xsi:type="xsd:string">science</return>
</ns1:doSpellingSuggestionResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
由于响应是以 base64 返回的,所以缓存请求有点复杂。请求:
<?xml version='1.0' encoding='UTF-8'?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"xmlns:xsd=
"http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:doGetCachedPage xmlns:ns1="urn:GoogleSearch"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<key xsi:type="xsd:string">181gQtaOdlLD+83qvh6PnssQR5WlaB9d</key>
<url xsi:type="xsd:string">
http://www-106.ibm.com/developerworks/xml/library/x-tiphdln.html
</url>
</ns1:doGetCachedPage>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
生成结果:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:doGetCachedPageResponse xmlns:ns1="urn:GoogleSearch"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<return xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/"
xsi:type="ns2:base64">PG1ldGEgaHR0cC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50
PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9SVNPLTg4NTktMSI+CjxCQVNFIEhSRUY9Imh0dHA6Ly93d3ctMTA
2LmlibS5jb20vZGV2ZWxvcGVyd29ya3MveG1sL2xpYnJhcnkveC10aXBoZGxuLmh0bWwiPjx0YWJsZSBib
3JkZXI9MSB3aWR0aD0xMDAlPjx0cj48dGQ+PHRhYmxlIGJvcmRlcj0xIGJnY29sb3I9I2ZmZmZmZiBjZW
xscGFkZGluZz0xMCBjZWxsc3BhY2luZz0wIHdpZH...
ZT4NCjwhLS0gRU5EIElCTSBGT09URVIgLS0+PC9ib2R5Pgo8L2h0bWw+Cg==</return>
</ns1:doGetCachedPageResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
请务必相应调整您的应用程序,否则就请直接用 API 自动执行翻译。