• C++请求web service与xml解析


    1. C++解析XML的开源库

            在项目中XML的解析使用的是开源的第三方库,TinyXML;这个解析库的模型通过XML文件,然后再内存中生成DOM模型,从而让我们能够非常方便的遍历这颗XML树。

    DOM模型即文档对象模型,是将整个文档分成多个元素(如:书、章、节、段等),并利用树型结构表示这些元素之间的顺序关系以及嵌套包括关系。先看一下TinyXML中的主要类和XML文档之间的相应关系,下图是TinyXML中主要class的类图,反应各个类之间的静态关系。

            TiXmlBase是全部类的基类,TiXmlNodeTiXmlAttribute两个类都继承自TiXMLBase类,当中TiXmlNode类指的是全部被<...>...<.../>包含的内容,而xml中的节点又详细分为下面几方面内容,各自是声明、凝视、节点以及节点间的文本,因此在TiXmlNode基础上又衍生出来这几个类TiXmlCommentTiXmlDeclarationTiXmlDocumentTiXmlElementTiXmlTextTiXmlUnknown,分别用来指明详细是xml中的哪一部分。TiXmlAttribute类不同于TiXmlNode,它指的是在尖括号中面的内容,像<...***=...>,当中***就是一个属性,这里採用一个XML文档详细说明一下:

    1.<?xml version="1.0" encoding="UTF-8"?>  
    2.<phonebook>  
    3.    <!--one item behalfs one contacted person.-->  
    4.    <item>  
    5.        <name>miaomaio</name>  
    6.    <addr>Shaanxi Xi'an</addr>  
    7.    <tel>13759911917</tel>  
    8.    <email>miaomiao@home.com</email>  
    9.    </item>  
    10.    <item>  
    11.        <name>gougou</name>  
    12.    <addr>Liaoning Shenyang</addr>  
    13.    <tel>15840330481</tel>  
    14.    <email>gougou@home.com</email>  
    15.    </item>  
    16.    <!--more contacted persons.-->  
    </phonebook>  
    

    l 像TiXmlDeclaration指的就是<?xml version="1.0" encoding="UTF-8"?>,

    l 像TiXmlComment指的就是<!--one item behalfs one contacted person.-->、<!--more contacted persons.-->,

    l 像TiXmlDocument指的就是整个xml文档,

    l 像TiXmlElement指的就是<phonebook>、<item>、<name>、<addr>等等这些节点,

    l 像TiXmlText指的就是‘gougou’、‘15840330481’这些夹在<item>与</item>、<name>与</name>、<addr>与</addr>之间的文本文字,

    l 像TiXmlAttribute指的就是<?xml version="1.0" encoding="UTF-8"?>节点中version、encoding,

    l 除此之外就是TiXmlUnknown。

    1) 读取XML文件

    //!xml文件读取,模拟调用接口返回char *字符串
    	filebuf *pbuf;
    	ifstream filestr;
    	long size;
    	char *buffer;
    
    	filestr.open(XML_EXAMPLE_FILE_NAME, ios::binary);
    	pbuf = filestr.rdbuf();
    	size = pbuf->pubseekoff(0,ios::end,ios::in);
    	pbuf->pubseekpos(0, ios::in);
    
    	buffer = new char[size];
    	pbuf->sgetn(buffer, size);
    	filestr.close();
    
    	//!从xml字符串中获取相关值
    	string strCreationTime;
    	string strJobId;
    	string strJobType;
    	string strJobName;
    	string strJobLeader;
    
    	TiXmlDocument *xmlDocument = new TiXmlDocument();
    	xmlDocument->Parse(buffer, 0, TIXML_DEFAULT_ENCODING);
    
    	TiXmlElement *RootElement = xmlDocument->RootElement();
    	TiXmlElement *fileHeaderElement = RootElement->FirstChildElement();
    	TiXmlElement *fileBodyElement = fileHeaderElement->NextSiblingElement();
    
    	for (TiXmlElement *nodeElement = fileHeaderElement->FirstChildElement(); nodeElement; nodeElement = nodeElement->NextSiblingElement())
    	{
    		string strElementKey = nodeElement->Value();
    		if (strElementKey.compare(XML_PARSE_CREATION_TIME) == 0)
    		{
    			strCreationTime = nodeElement->GetText();
    		}
    	}
    
    	for (TiXmlElement *nodeElement = fileBodyElement->FirstChildElement(); nodeElement; nodeElement = nodeElement->NextSiblingElement())
    	{
    		string strElementKey = nodeElement->Value();
    		if (strElementKey.compare(XML_PARSE_JOB_ID) == 0)
    		{
    			strJobId = nodeElement->GetText();
    		}
    
    		if (strElementKey.compare(XML_PARSE_JOB_TYPE) == 0)
    		{
    			strJobType = nodeElement->GetText();
    		}
    
    		if (strElementKey.compare(XML_PARSE_JOB_NAME) == 0)
    		{
    			strJobName = nodeElement->GetText();
    		}
    
    		if (strElementKey.compare(XML_PARSE_JOB_LEADER) == 0)
    		{
    			strJobLeader = nodeElement->GetText();
    		}
    	}

    2) 创建、生成XML文件

    以例如以下XML文件为例:

    <?xml version=”1.0” encoding=”gb2312”>
    <InterFaceFile>
         <FileHeader>
              <MessageType>ProxyMiddleWareJobSearch</MessageType>
              <Originator>WetLand</Originator>
    		  <Recipient>Platform</Recipient>
              <CreationTime>2014-9-18 10:25:20</CreationTime>
         </FileHeader>
         <FileBody>
              <UserName>...</UserName>
              <UserRoleID>13</UserRoleID> 
              <JobType></JobType> 
         </FileBody>
    </InterFaceFile>

     

    //! 构建XML字符串
    	TiXmlDocument *pDoc = new TiXmlDocument;
    	TiXmlDeclaration *pDeclaration = new TiXmlDeclaration("1.0", "gb2312", "");
    	pDoc->LinkEndChild(pDeclaration);
    
    	TiXmlElement *pEleRoot = new TiXmlElement("InterFaceFile");
    	pDoc->LinkEndChild(pEleRoot);
    
    	TiXmlElement *pEleFileHeader = new TiXmlElement("FileHeader");
    	TiXmlElement *pEleFileBody = new TiXmlElement("FileBody");
    	pEleRoot->LinkEndChild(pEleFileHeader);
    	pEleRoot->LinkEndChild(pEleFileBody);
    
    	TiXmlElement *pEleMessageType = new TiXmlElement("MessageType");
    	TiXmlElement *pEleOriginator = new TiXmlElement("Originator");
    	TiXmlElement *pEleRecipient = new TiXmlElement("Recipient");
    	TiXmlElement *pEleCreationTime = new TiXmlElement("CreationTime");
    	pEleFileHeader->LinkEndChild(pEleMessageType);
    	pEleFileHeader->LinkEndChild(pEleOriginator);
    	pEleFileHeader->LinkEndChild(pEleRecipient);
    	pEleFileHeader->LinkEndChild(pEleCreationTime);
    
    	TiXmlText *pEleMessageTypeText = new TiXmlText("ProxyMiddleWareJobSearch");
    	TiXmlText *pEleOriginatorText = new TiXmlText("WetLand");
    	TiXmlText *pEleRecipientText = new TiXmlText("Platform");
    	TiXmlText *pEleCreationTimeText = new TiXmlText("2014-9-18 10:25:20");
    
    	pEleMessageType->LinkEndChild(pEleMessageTypeText);
    	pEleOriginator->LinkEndChild(pEleOriginatorText);
    	pEleRecipient->LinkEndChild(pEleRecipientText);
    	pEleCreationTime->LinkEndChild(pEleCreationTimeText);
    
    	//!
    	TiXmlElement *pEleUserName = new TiXmlElement("UserName");
    	TiXmlElement *pEleUserRoleID = new TiXmlElement("UserRoleID");
    	TiXmlElement *pEleJobType = new TiXmlElement("JobType");
    	pEleFileBody->LinkEndChild(pEleUserName);
    	pEleFileBody->LinkEndChild(pEleUserRoleID);
    	pEleFileBody->LinkEndChild(pEleJobType);
    
    	TiXmlText *pEleUserNameText = new TiXmlText("...");
    	TiXmlText *pEleUserRoleIDText = new TiXmlText("13");
    	TiXmlText *pEleJobTypeText = new TiXmlText("");
    
    	pEleUserName->LinkEndChild(pEleUserNameText);
    	pEleUserRoleID->LinkEndChild(pEleUserRoleIDText);
    	pEleJobType->LinkEndChild(pEleJobTypeText);
    
    	pDoc->SaveFile("E:/houqd.xml");

    3) 生成XML字符串

    生成XML字符串仅仅须要将如上的pDoc->SaveFile(“E:/houqd.xml”)替换为例如以下:

    //!生成string字符串
    	TiXmlPrinter printer;
    	pDoc->Accept(&printer);
    
    	string strRequest(printer.CStr());

    2. C++调SOAP的开源库

    我们採用gsoap作为开源的web service的实现框架,能够从网上下载到开源的代码实现。下载地址:http://gsoap2.sourceforge.net/ 一般下载的gsoap工具包中已经包括了生成Web Serviceclient须要用到的两个工具(可运行文件):wsdl2h.exe和soapcpp2.exe,windows开发包一般在gsoap/bin/win32下,默认情况下wsdl2h并不支持SSL,即无法訪问HTTPS网站,假设想要支持SSL等很多其它功能,就须要自己又一次配置编译该gsoap工具包,以生成新的wsdl2h.exe和soapcpp2.h。这里,我採用的是原生的文件。

    相关參考资料:http://blog.csdn.net/zhaiwenjuan/article/details/6590941 

    1) gsoap生成本地代理

    1> 依据wsdl生成对应的头文件

        从Web服务提供者处获取Web ServiceWSDL文件,一般是一个URL,如:http://www.somewebservice.com/Service?Wsdl,当然也能够是一个WSDL形式的XML文件。

    使用gsoap的wsdl2h.exe,依据WSDL生成一个C/C++语法结构的头文件。

    比如:wsdl2h.exe -s -o Service.h http://www.somewebservice.com/Service?Wsdl

    这一步运行完后会得到一个头文件,如:Service.h

    该步的目的:实现WSDL文件到.h文件的数据映射。

    2> 依据生成的头文件生成相关代理文件

       使用gsoap的预编译器soapcpp2.exe,依据上一步得到的头文件来生成存根文件soapStub.h和client代码框架:

       如:soapcpp2.h -i -x -C -L Service.h

       这一步将会得到几个.nsmap.h.cpp文件。该步的目的:生成对应的底层通信代码。

    2) gsoap调用webservice接口

    将上几步生成的文件增加到project中,并包括响应的头文件,并採用例如以下的调用方式:

    string strRequest(printer.CStr());
    
    	//!web service调接口
    	string strWebServiceAddr = "http://172.16.10.209:8080/HDHT_J2EE/services/ProxyMiddleWareJob?wsdl";
    	ProxyMiddleWareJobHttpBindingProxy *proxy = new ProxyMiddleWareJobHttpBindingProxy();
    
    	_ns1__ProxyMiddleWareJobSearch inputParam;
    	_ns1__ProxyMiddleWareJobSearchResponse outputParam;
    	inputParam.in0 = const_cast<char *>(strRequest.c_str());
    
    	proxy->ProxyMiddleWareJobSearch(NULL,strWebServiceAddr.c_str() , &inputParam, outputParam);
    
    	string strResult = outputParam.out;

    3. 联调过程中出现的问题

    1) 參数传递问题

    这里,在使用web service调用接口时,依据曾经的思路(PHP的web service中的调用方式),想当然的将C++里面调用时參数的传递当成直接传递了,比如:上面调用ProxyMiddleWareJobSearch接口时,它接收一个xml格式的字符串,并返回一个xml格式的字符串,因此在刚開始使用时,採取的调用方式为:

    Proxy->ProxyMiddleWareJobSearch(NULL, strWebServiceAddr.c_str(), strRequest, strResult);採用的字符串形式,结果一直报错,意思是无法将const char *转换为_ns1__ProxyMiddleWareJobSearch *的形式,在后来运用中发现应该例如以下使用:

    _ns1__ProxyMiddleWareJobSearch inputParam; //! 代表输入

    _ns1__ProxyMiddleWareJobSearchResponse outputParam; //!代表输出

    inputParam.in0 = const_cast<char *>(strRequest.c_str()); //!输入第一个參数,

    假设接口须要第二个參数,则调用方式为:inputParam.in1 = ...

    string strResult = outputParam.out;  //! 调用后结果的返回。

    2) 中文乱码问题

    解决方法:在Java构建web service端,返回字符串之前,先进行base64的加密,然后c++作为web service的client调用完方法后,先对字符串进行base64的解密,这样就不存在乱码问题了。

    C++实现Base64的代码參考链接:

    http://www.cnblogs.com/phinecos/archive/2008/10/10/1308272.html

  • 相关阅读:
    HTML中CSS入门基础
    HTML基本代码教学,第三天
    HTML基本代码教学,第二天
    HTML基本代码教学片,认识HTML
    开学第一天,规章制度,教学大纲
    新的学期,从头开始
    开启新模式WinForm
    封装、继承、多态的基本详细使用方式与方法以及含义
    Python开发基础-Day4-布尔运算、集合
    Python开发基础-Day3-列表、元组和字典
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4297427.html
Copyright © 2020-2023  润新知