Using OpenAPI with C++[3] _VC调用WebService

来源:互联网 发布:买一个淘宝店铺 编辑:程序博客网 时间:2024/06/05 02:30
 

WSDL是什么呢?Web Services Description Language的缩写,是一个用来描述Web服务和说明如何与Web服务通信的XML语言。WSDL 文件包含以下元素:

Type:使用某种语法(如 XML 模式)的数据类型定义(string、int) Message:要传递的数据 Part:消息参数 Operation:服务支持的操作的抽象描述 Port Type / Interface:一个或多个端点支持的操作的抽象集。此名称已更改,因此可能会遇到两者中的任何一个。 Binding:特定端口类型的具体协议和数据格式规范 Port / Endpoint:绑定和网络地址的组合。此名称也已更改,因此可能会遇到两者中的任何一个。 Service:相关端点的集合,包括其关联的接口、操作、消息等。

CSDN在给我们看了API的声明和发送以及返回的XML格式后,我们还需要看下WSDL文件,才能随心所欲地针对各种OpenAPI书写代码。CSDN提供的接受我们发送的数据的地址为:http://forum.csdn.net/OpenApi/forumapi.asmx,查看其WSDL声明的URL就是:http://forum.csdn.net/OpenApi/forumapi.asmx?WSDL。一开始看是不是很头大?我们将其进行分块。

一个WSDL 的文档的主要结构是类似这样的:

  <definitions>

    <types>

    <!--  definition of types........-->

      

  </types>

    <message>

    <!--  definition of a message....-->

      

  </message>

    <portType>

    <!--  definition of a port.......-->

      

  </portType>

    <binding>

    <!--  definition of a binding....-->

      

  </binding>

这下就清楚了吧?具体的WSDL声明请见:http://www.w3.org/TR/wsdl。当然我们仅仅做调用开发的话,并不需要知道得那么详细。我们首先能看到CSDN的OpenAPI的WSDL中开头有定义了很多名称空间,(NameSpace):

<?xml version="1.0" encoding="utf-8"?>

<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"

                  xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"

                  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"

                  xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"

                  xmlns:tns="http://www.csdn.net/"

                  xmlns:s1="http://microsoft.com/wsdl/types/"

                  xmlns:s="http://www.w3.org/2001/XMLSchema"

                  xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"

                  xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"

                  targetNamespace="http://www.csdn.net/"

                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">

这些东西我们是需要的,看到了其中的s和s1了吧?我们的数据类型可定义在里面呢,这些对我们来说是很重要的,虽然在一篇中我们并没有用到,因为类型都是string,个人理解是因为默认的缘故,所以不需要声明节点的数据类型,不知道个人理解准确与否,不当之处还请读者斧正。<wsdl:portType name="ForumAPISoap">元素中,定义了各个API的发送和接受的Message。

<wsdl:portType name="ForumAPISoap">

  <wsdl:operation name="Post">

    <wsdl:input message="tns:PostSoapIn" />

    <wsdl:output message="tns:PostSoapOut" />

  </wsdl:operation>

  <wsdl:operation name="Reply">

    <wsdl:input message="tns:ReplySoapIn" />

    <wsdl:output message="tns:ReplySoapOut" />

  </wsdl:operation>

  <wsdl:operation name="GetForums">

    <wsdl:input message="tns:GetForumsSoapIn" />

    <wsdl:output message="tns:GetForumsSoapOut" />

  </wsdl:operation>

  <wsdl:operation name="CheckOutTopic">

    <wsdl:input message="tns:CheckOutTopicSoapIn" />

    <wsdl:output message="tns:CheckOutTopicSoapOut" />

  </wsdl:operation>

  <wsdl:operation name="GetTopicsOfUser">

    <wsdl:input message="tns:GetTopicsOfUserSoapIn" />

    <wsdl:output message="tns:GetTopicsOfUserSoapOut" />

  </wsdl:operation>

  <wsdl:operation name="PointDonate">

    <wsdl:input message="tns:PointDonateSoapIn" />

    <wsdl:output message="tns:PointDonateSoapOut" />

  </wsdl:operation>

  <wsdl:operation name="GetUserProfile">

    <wsdl:input message="tns:GetUserProfileSoapIn" />

    <wsdl:output message="tns:GetUserProfileSoapOut" />

  </wsdl:operation>

</wsdl:portType>

 

我们来看CSDN 的另外一个OpenAPI,这个是很多人都很关心的发帖的API——Post。从上面的portType中,我们可以看到input message是tns:PostSoapIn,output message是tns:PostSoapOut。各个Message的定义在上面,

<wsdl:message name="PostSoapIn">

  <wsdl:part name="parameters" element="tns:Post" />

</wsdl:message>

<wsdl:message name="PostSoapOut">

  <wsdl:part name="parameters" element="tns:PostResponse" />

</wsdl:message>

通过这里,我们知道了: PostSoapIn的Element是Post,而PostSoapOut的Element是PostResponse。我们还得往上看,我们知道了input和output的message,还需要在上面查message对应的Element声明。在Type中,我们看到了声明

<s:complexType name="Post">

  <s:sequence>

    <s:element minOccurs="1" maxOccurs="1" name="forumId" type="s1:guid" />

    <s:element minOccurs="0" maxOccurs="1" name="subject" type="s:string" />

    <s:element minOccurs="0" maxOccurs="1" name="body" type="s:string" />

    <s:element minOccurs="0" maxOccurs="1" name="tag" type="s:string" />

    <s:element minOccurs="1" maxOccurs="1" name="point" type="s:int" />

    <s:element minOccurs="1" maxOccurs="1" name="isAskExpert" type="s:boolean" />

    <s:element minOccurs="0" maxOccurs="1" name="expertUserName" type="s:string" />

    <s:element minOccurs="1" maxOccurs="1" name="editor" type="tns:EditorType" />

    <s:element minOccurs="0" maxOccurs="1" name="url" type="s:string" />

  </s:sequence>

</s:complexType>

 

<s:element name="PostResponse">

  <s:complexType>

    <s:sequence>

      <s:element minOccurs="1" maxOccurs="1" name="PostResult" type="s:boolean" />

      <s:element minOccurs="1" maxOccurs="1" name="error" type="tns:Error" />

      <s:element minOccurs="0" maxOccurs="1" name="topicUrl" type="s:string" />

    </s:sequence>

  </s:complexType>

</s:element>

<s:complexType name="Error">

  <s:sequence>

    <s:element minOccurs="1" maxOccurs="1" name="errId" type="s:int" />

    <s:element minOccurs="0" maxOccurs="1" name="errInfo" type="s:string" />

    <s:element minOccurs="0" maxOccurs="1" name="description" type="s:string" />

  </s:sequence>

</s:complexType>

而同时,在这之前我们就知道,Post这个API的发送的XML格式定义是:

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

               xmlns:xsd="http://www.w3.org/2001/XMLSchema"

               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

  <soap:Body>

    <Post xmlns="http://www.csdn.net/">

      <identity>

        <username>string</username>

        <password>string</password>

      </identity>

      <post>

        <forumId>guid</forumId>

        <subject>string</subject>

        <body>string</body>

        <tag>string</tag>

        <point>int</point>

        <isAskExpert>boolean</isAskExpert>

        <expertUserName>string</expertUserName>

        <editor>Text or Html or UBB</editor>

        <url>string</url>

      </post>

    </Post>

  </soap:Body>

</soap:Envelope>

返回的XML格式定义:

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

               xmlns:xsd="http://www.w3.org/2001/XMLSchema"

               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

  <soap:Body>

    <PostResponse xmlns="http://www.csdn.net/">

      <PostResult>boolean</PostResult>

      <error>

        <errId>int</errId>

        <errInfo>string</errInfo>

        <description>string</description>

      </error>

      <topicUrl>string</topicUrl>

    </PostResponse>

  </soap:Body>

</soap:Envelope>

我们可以看到,他们其实就是WDSL声明中的一个转换罢了,换了种直观的说法。如果我们是采用C#调用OpenAPI的话,就完全不需要考虑跑到那个WDSL文件里面去研究message,Type什么的,直接写在结构体里面,定义好就发送结构体,.Net内部都会自动帮你进行转换,但是C++就麻烦多了。^_^

我们需要发送的数据中有GUID类型,int类型,甚至boolean类型,这在C++中如何表示给XML知道呢?我们需要手工为Element打上类型标记,先看forumId这个元素,是guid类型,在WDSL中我们看到<s:element minOccurs="1" maxOccurs="1" name="forumId" type="s1:guid" />这么一行,说明它的类型是s1:guid,同理,int对应的表示为s:int,我们的代码需要进行改动。

还记得第一篇中的:

       Serializer->startEnvelope("SOAP","http://schemas.xmlsoap.org/soap/envelope/","");

 

吗,呵呵,我们给它加上三行名称空间定义。

       Serializer->SoapAttribute("tns","","http://www.csdn.net/","xmlns");

       Serializer->SoapAttribute("s","","http://www.w3.org/2001/XMLSchema","xmlns");

       Serializer->SoapAttribute("s1","","http://microsoft.com/wsdl/types/","xmlns");

 

现在就简单了,给Element开始的时候打上类型标记即可:

       Serializer->startBody("");  //<soap:Body>

#pragma region <Post>

       Serializer->startElement("Post","http://www.csdn.net/","NONE",""); //<Post xmlns="http://www.csdn.net/">

#pragma region <identity>

              Serializer->startElement("identity","http://www.csdn.net/","NONE","");//<identity>

 

                     Serializer->startElement("username","http://www.csdn.net/","NONE","");

                     Serializer->SoapAttribute("type", "", "s:string", "");

                     Serializer->writeString("tr0j4n");

                     Serializer->endElement();

 

                     Serializer->startElement("password","http://www.csdn.net/","NONE","");

                     Serializer->SoapAttribute("type", "", "s:string", "");

                     Serializer->writeString("5eab01aa1a2df9a5");

                     Serializer->endElement();

 

              Serializer->endElement(); //</identity>

#pragma endregion

 

#pragma region <post>

              Serializer->startElement("post","http://www.csdn.net/","NONE","");//<post>

#pragma region forumId

                     Serializer->startElement("forumId","http://www.csdn.net/","NONE","");

                     Serializer->SoapAttribute("type", "", "s1:guid", "");

                     Serializer->writeString("b3f8b246-f953-40a4-a4d4-7b8546ecce6c");

                     Serializer->endElement();

#pragma endregion

#pragma region subject

                     Serializer->startElement("subject","http://www.csdn.net/","NONE","");

                     Serializer->SoapAttribute("type", "", "s:string", "");

                     Serializer->writeString("PostThreadTest");

                     Serializer->endElement();

#pragma endregion

#pragma region body

                     Serializer->startElement("body","http://www.csdn.net/","NONE","");

                     Serializer->SoapAttribute("type", "", "s:string", "");

                     Serializer->writeString("RT");

                     Serializer->endElement();

#pragma endregion

#pragma region tag

                     Serializer->startElement("tag","http://www.csdn.net/","NONE","");

                     Serializer->SoapAttribute("type", "", "s:string", "");

                     Serializer->writeString("");

                     Serializer->endElement();

#pragma endregion

#pragma region point

                     Serializer->startElement("point","http://www.csdn.net/","NONE","");

                     Serializer->SoapAttribute("type", "", "s:int", "");

                     //int x=100;

                     Serializer->writeString("100");

                     Serializer->endElement();

#pragma endregion

#pragma region isAskExpert

                     Serializer->startElement("isAskExpert","http://www.csdn.net/","NONE","");

                     Serializer->SoapAttribute("type", "", "s:boolean", "");

                     //bool y=true;

                     Serializer->writeString("1");

                     Serializer->endElement();

#pragma endregion

#pragma region expertUserName

                     Serializer->startElement("expertUserName","http://www.csdn.net/","NONE","");

                     Serializer->SoapAttribute("type", "", "s:string", "");

                     Serializer->writeString("ALL");

                     Serializer->endElement();

#pragma endregion

#pragma region editor

                     Serializer->startElement("editor","http://www.csdn.net/","NONE","");

                     Serializer->SoapAttribute("type", "", "tns:EditorType", "");

                     Serializer->writeString("UBB");

                     Serializer->endElement();

#pragma endregion

 

              Serializer->endElement(); //</post>

#pragma endregion

       Serializer->endElement();//</Post>

#pragma endregion

       Serializer->endBody();//</soap:Body>

 

如上就是一个完整的发帖的C++调用Soap的代码了,b3f8b246-f953-40a4-a4d4-7b8546ecce6c是小版块的GUID,以下的分别是帖子的标题、帖子正文内容、标签,分数、是否向专家提问、专家姓名、编辑器种类(目前只支持UBB)。你全用WriteString即可,因为XML本来就是纯文本,那些类型的标示是在服务器接收到之后用作转换只用,这些资料网上都搜索不到,tr0j4n当时探索这个花了很多时间,走了不少弯路,现在吐血把心得都发出来给大家了。细心的读者发现其实少了一个字段,url,这个是帖子的URL,不过我们还没有发帖,怎么知道URL呢?没事,不写就好了,CSDN可能这里考虑得有些问题。服务器返回的XML中不是有个topicUrl嘛?那个就是生成的帖子的URL。

通过CSDN提供的Post API,您就可以发帖子标题前带有“[向 xXX提问]”红色字样的拉风帖子了。

 

文章出处:http://blog.csdn.net/tr0j4n/article/details/4970507

 

原创粉丝点击