A usable draft.
parent
a21102e963
commit
032a5a96a1
@ -0,0 +1,25 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
project(csoap)
|
||||||
|
|
||||||
|
add_definitions(-DUNICODE -D_UNICODE)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
# Win7 (asio needs this)
|
||||||
|
add_definitions(-D_WIN32_WINNT=0x0601)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
|
find_package(Boost)
|
||||||
|
if(Boost_FOUND)
|
||||||
|
include_directories(${Boost_INCLUDE_DIRS})
|
||||||
|
link_directories(${Boost_LIBRARY_DIRS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories(${PROJECT_SOURCE_DIR}/src)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
|
|
@ -0,0 +1,3 @@
|
|||||||
|
add_subdirectory(pugixml)
|
||||||
|
add_subdirectory(csoap)
|
||||||
|
add_subdirectory(demo)
|
@ -0,0 +1,8 @@
|
|||||||
|
if(UNIX)
|
||||||
|
add_definitions(-D_GLIBCXX_USE_WCHAR_T -std=c++11)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(GLOB SRCS *.cc *.h)
|
||||||
|
|
||||||
|
add_library(csoap ${SRCS})
|
||||||
|
|
@ -0,0 +1,27 @@
|
|||||||
|
#include "csoap/common.h"
|
||||||
|
|
||||||
|
namespace csoap {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Parameter::Parameter(const std::string& key, const std::string& value)
|
||||||
|
: key_(key) {
|
||||||
|
value_ = LexicalCast<std::string>(value, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter::Parameter(const std::string& key, int value)
|
||||||
|
: key_(key) {
|
||||||
|
value_ = LexicalCast<std::string>(value, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter::Parameter(const std::string& key, float value)
|
||||||
|
: key_(key) {
|
||||||
|
value_ = LexicalCast<std::string>(value, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
Parameter::Parameter(const std::string& key, bool value)
|
||||||
|
: key_(key) {
|
||||||
|
value_ = LexicalCast<std::string>(value, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace csoap
|
@ -0,0 +1,69 @@
|
|||||||
|
#ifndef CSOAP_COMMON_H_
|
||||||
|
#define CSOAP_COMMON_H_
|
||||||
|
|
||||||
|
// Common definitions.
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "boost/lexical_cast.hpp"
|
||||||
|
|
||||||
|
namespace csoap {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Wrapper for boost::lexcical_cast.
|
||||||
|
// Usage:
|
||||||
|
// LexicalCast<int>("123", 0);
|
||||||
|
// LexicalCast<std::string>(123, "");
|
||||||
|
template <typename To, typename From>
|
||||||
|
To LexicalCast(const From& input, const To& default_output) {
|
||||||
|
try {
|
||||||
|
return boost::lexical_cast<To>(input);
|
||||||
|
} catch (boost::bad_lexical_cast&) {
|
||||||
|
return default_output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// XML namespace name/url pair.
|
||||||
|
// E.g., { "soapenv", "http://schemas.xmlsoap.org/soap/envelope/" }
|
||||||
|
class Namespace {
|
||||||
|
public:
|
||||||
|
std::string name;
|
||||||
|
std::string url;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Parameter in the SOAP request envelope.
|
||||||
|
class Parameter {
|
||||||
|
public:
|
||||||
|
Parameter(const std::string& key, const std::string& value);
|
||||||
|
Parameter(const std::string& key, int value);
|
||||||
|
Parameter(const std::string& key, float value);
|
||||||
|
Parameter(const std::string& key, bool value);
|
||||||
|
|
||||||
|
const char* c_key() const {
|
||||||
|
return key_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& key() const {
|
||||||
|
return key_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* c_value() const {
|
||||||
|
return value_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& value() const {
|
||||||
|
return value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string key_;
|
||||||
|
std::string value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace csoap
|
||||||
|
|
||||||
|
#endif // CSOAP_COMMON_H_
|
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef CSOAP_CSOAP_H_
|
||||||
|
#define CSOAP_CSOAP_H_
|
||||||
|
|
||||||
|
// Include all csoap headers.
|
||||||
|
|
||||||
|
#include "csoap/http_client.h"
|
||||||
|
#include "csoap/soap_request_envelope.h"
|
||||||
|
#include "csoap/soap_response_parser.h"
|
||||||
|
#include "csoap/xml.h"
|
||||||
|
|
||||||
|
#endif // CSOAP_CSOAP_H_
|
@ -0,0 +1,253 @@
|
|||||||
|
#include "csoap/http_client.h"
|
||||||
|
|
||||||
|
#include "boost/bind.hpp"
|
||||||
|
#include "boost/algorithm/string.hpp"
|
||||||
|
|
||||||
|
#include "csoap/common.h"
|
||||||
|
|
||||||
|
namespace csoap {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static const std::string kCRLF = "\r\n";
|
||||||
|
|
||||||
|
// NOTE:
|
||||||
|
// Each header field consists of a name followed by a colon (":") and the
|
||||||
|
// field value. Field names are case-insensitive.
|
||||||
|
// See http://stackoverflow.com/questions/5258977/are-http-headers-case-sensitive
|
||||||
|
static const std::string kFieldContentTypeName = "Content-Type";
|
||||||
|
static const std::string kFieldContentLengthName = "Content-Length";
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
HttpRequest::HttpRequest(HttpVersion version)
|
||||||
|
: version_(version)
|
||||||
|
, keep_alive_(true)
|
||||||
|
, content_length_(std::string::npos) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpRequest::ToString(std::string& req_string) const {
|
||||||
|
// Start line
|
||||||
|
|
||||||
|
req_string += "POST ";
|
||||||
|
req_string += url_;
|
||||||
|
req_string += " ";
|
||||||
|
|
||||||
|
if (version_ == kHttpV10) {
|
||||||
|
req_string += "HTTP/1.0";
|
||||||
|
} else {
|
||||||
|
req_string += "HTTP/1.1";
|
||||||
|
}
|
||||||
|
req_string += kCRLF;
|
||||||
|
|
||||||
|
// Header fields
|
||||||
|
|
||||||
|
if (!content_type_.empty()) {
|
||||||
|
req_string += kFieldContentTypeName;
|
||||||
|
req_string += ": ";
|
||||||
|
req_string += content_type_;
|
||||||
|
req_string += kCRLF;
|
||||||
|
}
|
||||||
|
|
||||||
|
req_string += kFieldContentLengthName;
|
||||||
|
req_string += ": ";
|
||||||
|
req_string += LexicalCast<std::string>(content_length_, "0");
|
||||||
|
req_string += kCRLF;
|
||||||
|
|
||||||
|
req_string += "SOAPAction: ";
|
||||||
|
req_string += soap_action_;
|
||||||
|
req_string += kCRLF;
|
||||||
|
|
||||||
|
req_string += "Host: ";
|
||||||
|
req_string += host_;
|
||||||
|
if (!port_.empty()) {
|
||||||
|
req_string += ":";
|
||||||
|
req_string += port_;
|
||||||
|
}
|
||||||
|
req_string += kCRLF;
|
||||||
|
|
||||||
|
if (keep_alive_) {
|
||||||
|
req_string += "Connection: Keep-Alive";
|
||||||
|
req_string += kCRLF;
|
||||||
|
}
|
||||||
|
|
||||||
|
req_string += kCRLF;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
HttpResponse::HttpResponse()
|
||||||
|
: status_(0)
|
||||||
|
, content_length_(0)
|
||||||
|
, start_line_parsed_(false)
|
||||||
|
, header_parsed_(false)
|
||||||
|
, finished_(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpResponse::Parse(const char* data, size_t len) {
|
||||||
|
if (header_parsed_) {
|
||||||
|
// Add the data to the content.
|
||||||
|
content_.append(data, len);
|
||||||
|
|
||||||
|
if (content_.length() >= content_length_) {
|
||||||
|
// All content has been read.
|
||||||
|
finished_ = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pending_data_.append(data, len);
|
||||||
|
size_t off = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
size_t pos = pending_data_.find(kCRLF, off);
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos == off) { // End of headers.
|
||||||
|
off = pos + 2; // Skip "\r\n".
|
||||||
|
header_parsed_ = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string line = pending_data_.substr(off, pos - off);
|
||||||
|
|
||||||
|
if (!start_line_parsed_) {
|
||||||
|
ParseStartLine(line); // TODO: Error handling.
|
||||||
|
start_line_parsed_ = true;
|
||||||
|
} else {
|
||||||
|
ParseHeaderField(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
off = pos + 2; // Skip "\r\n".
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header_parsed_) {
|
||||||
|
// Headers just ended.
|
||||||
|
content_ += pending_data_.substr(off);
|
||||||
|
|
||||||
|
if (content_.length() >= content_length_) {
|
||||||
|
// All content has been read.
|
||||||
|
finished_ = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Save the unparsed piece for next parsing.
|
||||||
|
pending_data_ = pending_data_.substr(off);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HttpResponse::ParseStartLine(const std::string& line) {
|
||||||
|
std::vector<std::string> parts;
|
||||||
|
boost::split(parts, line, boost::is_any_of(" "), boost::token_compress_on);
|
||||||
|
|
||||||
|
if (parts.size() != 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
status_ = boost::lexical_cast<int>(parts[1]);
|
||||||
|
} catch (boost::bad_lexical_cast&) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
reason_ = parts[2];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HttpResponse::ParseHeaderField(const std::string& line) {
|
||||||
|
size_t pos = line.find(':');
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string name = line.substr(0, pos);
|
||||||
|
|
||||||
|
++pos; // Skip ':'.
|
||||||
|
while (line[pos] == ' ') { // Skip spaces.
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string value = line.substr(pos);
|
||||||
|
|
||||||
|
if (boost::iequals(name, kFieldContentTypeName)) {
|
||||||
|
content_type_ = value;
|
||||||
|
} else if (boost::iequals(name, kFieldContentLengthName)) {
|
||||||
|
try {
|
||||||
|
content_length_ = boost::lexical_cast<size_t>(value);
|
||||||
|
} catch (boost::bad_lexical_cast&) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Unsupported, ignore.
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
HttpClient::HttpClient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpClient::~HttpClient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HttpClient::SendRequest(const HttpRequest& request,
|
||||||
|
const std::string& body) {
|
||||||
|
using boost::asio::ip::tcp;
|
||||||
|
|
||||||
|
tcp::socket socket(io_service_);
|
||||||
|
|
||||||
|
tcp::resolver resolver(io_service_);
|
||||||
|
|
||||||
|
std::string port = request.port();
|
||||||
|
if (port.empty()) {
|
||||||
|
port = "80";
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp::resolver::query query(request.host(), port);
|
||||||
|
|
||||||
|
boost::system::error_code error;
|
||||||
|
tcp::resolver::iterator it = resolver.resolve(query, error);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket.connect(*it, error);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string request_str;
|
||||||
|
request.ToString(request_str);
|
||||||
|
|
||||||
|
try {
|
||||||
|
boost::asio::write(socket, boost::asio::buffer(request_str));
|
||||||
|
boost::asio::write(socket, boost::asio::buffer(body));
|
||||||
|
} catch (boost::system::system_error&) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and parse HTTP response.
|
||||||
|
|
||||||
|
while (!response_.finished()) {
|
||||||
|
try {
|
||||||
|
size_t len = socket.read_some(boost::asio::buffer(bytes_));
|
||||||
|
response_.Parse(bytes_.data(), len);
|
||||||
|
|
||||||
|
} catch (boost::system::system_error&) {
|
||||||
|
// Should be EOF, but ...
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace csoap
|
@ -0,0 +1,171 @@
|
|||||||
|
#ifndef CSOAP_HTTP_CLIENT_H_
|
||||||
|
#define CSOAP_HTTP_CLIENT_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "boost/asio.hpp"
|
||||||
|
|
||||||
|
// A little concept about URL (From HTTP The Definitive Guide):
|
||||||
|
// Say you want to fetch the URL http://www.joes-hardware.com/seasonal/index-fall.html:
|
||||||
|
// - The first part of the URL(http) is the URL scheme. The scheme tells a web client
|
||||||
|
// *how* to access the resource. In this case, the URL says to use the HTTP protocol.
|
||||||
|
// - The second part of the URL (www.joes-hardware.com) is the server location.
|
||||||
|
// This tells the web client *where* the resource is hosted.
|
||||||
|
// - The third part of the URL(/seasonal/index-fall.html) is the resource path. The
|
||||||
|
// path tells *what* particular local resource on the server is being requested.
|
||||||
|
|
||||||
|
namespace csoap {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
enum HttpVersion {
|
||||||
|
kHttpV10,
|
||||||
|
kHttpV11,
|
||||||
|
};
|
||||||
|
|
||||||
|
//enum HttpStatus {
|
||||||
|
// kHttpOK = 200,
|
||||||
|
//};
|
||||||
|
|
||||||
|
enum HeaderField {
|
||||||
|
kHeaderContentType,
|
||||||
|
kHeaderContentLength,
|
||||||
|
kHeaderHost,
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// HTTP request.
|
||||||
|
// NOTE:
|
||||||
|
// - Only POST method is supported.
|
||||||
|
// See http://stackoverflow.com/questions/26339317/do-soap-web-services-support-only-post-http-method
|
||||||
|
class HttpRequest {
|
||||||
|
public:
|
||||||
|
HttpRequest(HttpVersion version);
|
||||||
|
|
||||||
|
void set_uri(const std::string& uri) {
|
||||||
|
url_ = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_content_type(const std::string& content_type) {
|
||||||
|
content_type_ = content_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_content_length(size_t content_length) {
|
||||||
|
content_length_ = content_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_keep_alive(bool keep_alive) {
|
||||||
|
keep_alive_ = keep_alive;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& host() const {
|
||||||
|
return host_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& port() const {
|
||||||
|
return port_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// \param host Descriptive host name or numeric IP address.
|
||||||
|
// \param port Numeric port number.
|
||||||
|
void set_host(const std::string& host, const std::string& port) {
|
||||||
|
host_ = host;
|
||||||
|
port_ = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SOAP specific.
|
||||||
|
void set_soap_action(const std::string& soap_action) {
|
||||||
|
soap_action_ = soap_action;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToString(std::string& req_string) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HttpVersion version_;
|
||||||
|
|
||||||
|
// Request URL.
|
||||||
|
// A complete URL naming the requested resource, or the path component of the URL.
|
||||||
|
std::string url_;
|
||||||
|
|
||||||
|
std::string content_type_;
|
||||||
|
size_t content_length_;
|
||||||
|
|
||||||
|
std::string host_;
|
||||||
|
std::string port_;
|
||||||
|
|
||||||
|
bool keep_alive_;
|
||||||
|
|
||||||
|
std::string soap_action_;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class HttpResponse {
|
||||||
|
public:
|
||||||
|
HttpResponse();
|
||||||
|
|
||||||
|
void Parse(const char* data, size_t len);
|
||||||
|
|
||||||
|
bool finished() const {
|
||||||
|
return finished_;
|
||||||
|
}
|
||||||
|
|
||||||
|
int status() const {
|
||||||
|
return status_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& reason() const {
|
||||||
|
return reason_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& content() const {
|
||||||
|
return content_;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Parse start line, e.g., "HTTP/1.1 200 OK".
|
||||||
|
bool ParseStartLine(const std::string& line);
|
||||||
|
|
||||||
|
// Parse a header line, e.g., "Content-Length: 19".
|
||||||
|
bool ParseHeaderField(const std::string& line);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int status_; // HTTP status, e.g., 200.
|
||||||
|
std::string reason_;
|
||||||
|
std::string content_type_;
|
||||||
|
size_t content_length_;
|
||||||
|
std::string content_;
|
||||||
|
|
||||||
|
// Data waiting to be parsed.
|
||||||
|
std::string pending_data_;
|
||||||
|
|
||||||
|
// Parsing helper flags.
|
||||||
|
bool start_line_parsed_;
|
||||||
|
bool header_parsed_;
|
||||||
|
bool finished_;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class HttpClient {
|
||||||
|
public:
|
||||||
|
HttpClient();
|
||||||
|
~HttpClient();
|
||||||
|
|
||||||
|
bool SendRequest(const HttpRequest& request,
|
||||||
|
const std::string& body);
|
||||||
|
|
||||||
|
const HttpResponse& response() const {
|
||||||
|
return response_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::asio::io_service io_service_;
|
||||||
|
std::array<char, 1024> bytes_;
|
||||||
|
|
||||||
|
HttpResponse response_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace csoap
|
||||||
|
|
||||||
|
#endif // CSOAP_HTTP_CLIENT_H_
|
@ -0,0 +1,67 @@
|
|||||||
|
#include "csoap/soap_request_envelope.h"
|
||||||
|
|
||||||
|
#include "csoap/xml.h"
|
||||||
|
|
||||||
|
namespace csoap {
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Append "xmlns" attribute.
|
||||||
|
static void AppendAttrNS(pugi::xml_node& xnode, const Namespace& ns) {
|
||||||
|
xml::AppendAttr(xnode, "xmlns", ns.name, ns.url);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
SoapRequestEnvelope::SoapRequestEnvelope(const std::string& operation)
|
||||||
|
: operation_(operation) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoapRequestEnvelope::SetNamespace(NSType ns_type, const Namespace& ns) {
|
||||||
|
assert(ns_type < kCountNS);
|
||||||
|
namespaces_[ns_type] = ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoapRequestEnvelope::SetNamespace(NSType ns_type,
|
||||||
|
const std::string& name,
|
||||||
|
const std::string& url) {
|
||||||
|
assert(ns_type < kCountNS);
|
||||||
|
|
||||||
|
namespaces_[ns_type].name = name;
|
||||||
|
namespaces_[ns_type].url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoapRequestEnvelope::AddParameter(const std::string& key,
|
||||||
|
const std::string& value) {
|
||||||
|
parameters_.push_back(Parameter(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoapRequestEnvelope::AddParameter(const Parameter& parameter) {
|
||||||
|
parameters_.push_back(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoapRequestEnvelope::ToXmlString(std::string* xml_string) {
|
||||||
|
std::string& soapenv_ns = namespaces_[kSoapEnvelopeNS].name;
|
||||||
|
std::string& srv_ns = namespaces_[kServiceNS].name;
|
||||||
|
|
||||||
|
pugi::xml_document xdoc;
|
||||||
|
pugi::xml_node xroot = xml::AppendChild(xdoc, soapenv_ns, "Envelope");
|
||||||
|
|
||||||
|
AppendAttrNS(xroot, namespaces_[kSoapEnvelopeNS]);
|
||||||
|
AppendAttrNS(xroot, namespaces_[kServiceNS]);
|
||||||
|
|
||||||
|
xml::AppendChild(xroot, soapenv_ns, "Header");
|
||||||
|
|
||||||
|
pugi::xml_node xbody = xml::AppendChild(xroot, soapenv_ns, "Body");
|
||||||
|
pugi::xml_node xoperation = xml::AppendChild(xbody, srv_ns, operation_);
|
||||||
|
|
||||||
|
for (Parameter& p : parameters_) {
|
||||||
|
pugi::xml_node xparam = xml::AppendChild(xoperation, srv_ns, p.c_key());
|
||||||
|
xparam.text().set(p.c_value());
|
||||||
|
}
|
||||||
|
|
||||||
|
xml::XmlStrRefWriter writer(xml_string);
|
||||||
|
xdoc.print(writer, "\t", pugi::format_default, pugi::encoding_utf8);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace csoap
|
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef CSOAP_SOAP_REQUEST_ENVELOPE_H_
|
||||||
|
#define CSOAP_SOAP_REQUEST_ENVELOPE_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "csoap/common.h"
|
||||||
|
|
||||||
|
namespace csoap {
|
||||||
|
|
||||||
|
// SOAP request envelope.
|
||||||
|
// Used to compose the SOAP envelope XML which will be sent as the HTTP
|
||||||
|
// request body.
|
||||||
|
class SoapRequestEnvelope {
|
||||||
|
public:
|
||||||
|
enum NSType {
|
||||||
|
kSoapEnvelopeNS = 0,
|
||||||
|
kServiceNS,
|
||||||
|
kCountNS,
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SoapRequestEnvelope(const std::string& operation);
|
||||||
|
|
||||||
|
void SetNamespace(NSType ns_type, const Namespace& ns);
|
||||||
|
|
||||||
|
void SetNamespace(NSType ns_type,
|
||||||
|
const std::string& name,
|
||||||
|
const std::string& url);
|
||||||
|
|
||||||
|
void AddParameter(const std::string& key, const std::string& value);
|
||||||
|
void AddParameter(const Parameter& parameter);
|
||||||
|
|
||||||
|
void ToXmlString(std::string* xml_string);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Namespace namespaces_[kCountNS];
|
||||||
|
|
||||||
|
std::string operation_;
|
||||||
|
std::vector<Parameter> parameters_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace csoap
|
||||||
|
|
||||||
|
#endif // CSOAP_SOAP_REQUEST_ENVELOPE_H_
|
@ -0,0 +1,46 @@
|
|||||||
|
#include "csoap/soap_response_parser.h"
|
||||||
|
|
||||||
|
#include "csoap/xml.h"
|
||||||
|
|
||||||
|
namespace csoap {
|
||||||
|
|
||||||
|
SoapResponseParser::SoapResponseParser() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SoapResponseParser::Parse(const std::string& content,
|
||||||
|
const std::string& message_name,
|
||||||
|
const std::string& element_name,
|
||||||
|
std::string* element_value) {
|
||||||
|
pugi::xml_document xdoc;
|
||||||
|
pugi::xml_parse_result result = xdoc.load_string(content.c_str());
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
//std::cout << "Error: " << result.description() << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pugi::xml_node xroot = xdoc.document_element();
|
||||||
|
|
||||||
|
soapenv_ns_ = csoap::xml::GetNsPrefix(xroot);
|
||||||
|
|
||||||
|
pugi::xml_node xbody = csoap::xml::GetChild(xroot, soapenv_ns_, "Body");
|
||||||
|
if (!xbody) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pugi::xml_node xmessage = csoap::xml::GetChildNoNS(xbody, message_name);
|
||||||
|
if (!xmessage) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pugi::xml_node xelement = csoap::xml::GetChildNoNS(xmessage, element_name);
|
||||||
|
if (!xelement) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*element_value = xelement.text().get();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace csoap
|
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef CSOAP_RESPONSE_PARSER_H_
|
||||||
|
#define CSOAP_RESPONSE_PARSER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace csoap {
|
||||||
|
|
||||||
|
class SoapResponseParser {
|
||||||
|
public:
|
||||||
|
SoapResponseParser();
|
||||||
|
|
||||||
|
// <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
|
||||||
|
// <soapenv:Body>
|
||||||
|
// <ns:getPatientResponse xmlns:ns="http://service.csdm.carestream.com">
|
||||||
|
// <ns:return> ...
|
||||||
|
bool Parse(const std::string& content,
|
||||||
|
const std::string& message_name,
|
||||||
|
const std::string& element_name,
|
||||||
|
std::string* element_value);
|
||||||
|
|
||||||
|
const std::string& soapenv_ns() const {
|
||||||
|
return soapenv_ns_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Soap envelope namespace in the response XML.
|
||||||
|
std::string soapenv_ns_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace csoap
|
||||||
|
|
||||||
|
#endif // CSOAP_RESPONSE_PARSER_H_
|
@ -0,0 +1,62 @@
|
|||||||
|
#include "csoap/xml.h"
|
||||||
|
|
||||||
|
namespace csoap {
|
||||||
|
namespace xml {
|
||||||
|
|
||||||
|
std::string GetNsPrefix(const pugi::xml_node& xnode) {
|
||||||
|
std::string node_name = xnode.name();
|
||||||
|
|
||||||
|
size_t pos = node_name.find(':');
|
||||||
|
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
return node_name.substr(0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pugi::xml_node AppendChild(pugi::xml_node& xnode,
|
||||||
|
const std::string& ns,
|
||||||
|
const std::string& name) {
|
||||||
|
std::string ns_name = ns + ":" + name;
|
||||||
|
return xnode.append_child(ns_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
pugi::xml_node GetChild(pugi::xml_node& xnode,
|
||||||
|
const std::string& ns,
|
||||||
|
const std::string& name) {
|
||||||
|
return xnode.child((ns + ":" + name).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
pugi::xml_node GetChildNoNS(pugi::xml_node& xnode,
|
||||||
|
const std::string& name) {
|
||||||
|
pugi::xml_node xchild = xnode.first_child();
|
||||||
|
while (xchild) {
|
||||||
|
std::string child_name = xchild.name();
|
||||||
|
|
||||||
|
// Remove NS prefix.
|
||||||
|
size_t pos = child_name.find(':');
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
child_name = child_name.substr(pos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child_name == name) {
|
||||||
|
return xchild;
|
||||||
|
}
|
||||||
|
|
||||||
|
xchild = xchild.next_sibling();
|
||||||
|
}
|
||||||
|
|
||||||
|
return pugi::xml_node();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppendAttr(pugi::xml_node& xnode,
|
||||||
|
const std::string& ns,
|
||||||
|
const std::string& name,
|
||||||
|
const std::string& value) {
|
||||||
|
std::string ns_name = ns + ":" + name;
|
||||||
|
xnode.append_attribute(ns_name.c_str()) = value.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace xml
|
||||||
|
} // namespace csoap
|
@ -0,0 +1,63 @@
|
|||||||
|
#ifndef CSOAP_XML_H_
|
||||||
|
#define CSOAP_XML_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "pugixml/pugixml.hpp"
|
||||||
|
|
||||||
|
// XML utilities.
|
||||||
|
|
||||||
|
namespace csoap {
|
||||||
|
namespace xml {
|
||||||
|
|
||||||
|
// Get the namespace prefix from node name.
|
||||||
|
// Example:
|
||||||
|
// Node name: soapenv:Envelope
|
||||||
|
// NS prefix: soapenv
|
||||||
|
std::string GetNsPrefix(const pugi::xml_node& xnode);
|
||||||
|
|
||||||
|
// Append a child with the given name which is prefixed by a namespace.
|
||||||
|
// E.g., AppendChild(xnode, "soapenv", "Envelope") will append a child with
|
||||||
|
// name "soapenv:Envelope".
|
||||||
|
pugi::xml_node AppendChild(pugi::xml_node& xnode,
|
||||||
|
const std::string& ns,
|
||||||
|
const std::string& name);
|
||||||
|
|
||||||
|
pugi::xml_node GetChild(pugi::xml_node& xnode,
|
||||||
|
const std::string& ns,
|
||||||
|
const std::string& name);
|
||||||
|
|
||||||
|
pugi::xml_node GetChildNoNS(pugi::xml_node& xnode,
|
||||||
|
const std::string& name);
|
||||||
|
|
||||||
|
// Append a attribute with the given name which is prefixed by a namespace.
|
||||||
|
void AppendAttr(pugi::xml_node& xnode,
|
||||||
|
const std::string& ns,
|
||||||
|
const std::string& name,
|
||||||
|
const std::string& value);
|
||||||
|
|
||||||
|
// An XML writer writing to a referenced string.
|
||||||
|
// Example:
|
||||||
|
// pugi::xml_document xdoc;
|
||||||
|
// ...
|
||||||
|
// std::string xml_string;
|
||||||
|
// XmlStrRefWriter writer(&xml_string);
|
||||||
|
// xdoc.print(writer, " ", pugi::format_default, pugi::encoding_utf8);
|
||||||
|
class XmlStrRefWriter : public pugi::xml_writer {
|
||||||
|
public:
|
||||||
|
explicit XmlStrRefWriter(std::string* result)
|
||||||
|
: result_(result) {
|
||||||
|
result_->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void write(const void* data, size_t size) override {
|
||||||
|
result_->append(static_cast<const char*>(data), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string* result_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace xml
|
||||||
|
} // namespace csoap
|
||||||
|
|
||||||
|
#endif // CSOAP_XML_H_
|
@ -0,0 +1,10 @@
|
|||||||
|
if(UNIX)
|
||||||
|
add_definitions(-D_GLIBCXX_USE_WCHAR_T -std=c++11)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(GLOB SRCS *.cc *.h)
|
||||||
|
|
||||||
|
add_executable(demo ${SRCS})
|
||||||
|
|
||||||
|
target_link_libraries(demo csoap pugixml)
|
||||||
|
|
@ -0,0 +1,93 @@
|
|||||||
|
#include "demo/calculator.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "pugixml/pugixml.hpp"
|
||||||
|
#include "csoap/csoap.h"
|
||||||
|
|
||||||
|
namespace demo {
|
||||||
|
|
||||||
|
Calculator::Calculator() {
|
||||||
|
Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Calculator::Add(float x, float y, float* result) {
|
||||||
|
csoap::Parameter parameters[] = {
|
||||||
|
{ "x", x },
|
||||||
|
{ "y", y }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string result_str;
|
||||||
|
if (!Call("add", parameters, 2, &result_str)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
*result = boost::lexical_cast<float>(result_str);
|
||||||
|
} catch (boost::bad_lexical_cast&) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Calculator::Init() {
|
||||||
|
soap_envelope_ns_ = { "soapenv", "http://schemas.xmlsoap.org/soap/envelope/" };
|
||||||
|
service_ns_ = { "ser", "http://www.parasoft.com/wsdl/calculator/" };
|
||||||
|
|
||||||
|
host_ = "ws1.parasoft.com";
|
||||||
|
port_ = ""; // Use default: 80
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Calculator::Call(const std::string& operation,
|
||||||
|
const csoap::Parameter* parameters,
|
||||||
|
size_t count,
|
||||||
|
std::string* result) {
|
||||||
|
csoap::SoapRequestEnvelope req_envelope(operation);
|
||||||
|
|
||||||
|
req_envelope.SetNamespace(csoap::SoapRequestEnvelope::kSoapEnvelopeNS, soap_envelope_ns_);
|
||||||
|
req_envelope.SetNamespace(csoap::SoapRequestEnvelope::kServiceNS, service_ns_);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
req_envelope.AddParameter(parameters[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string request_body;
|
||||||
|
req_envelope.ToXmlString(&request_body);
|
||||||
|
|
||||||
|
csoap::HttpRequest http_request(csoap::kHttpV11);
|
||||||
|
|
||||||
|
http_request.set_uri("http://ws1.parasoft.com/glue/calculator");
|
||||||
|
http_request.set_content_type("text/xml; charset=utf-8");
|
||||||
|
http_request.set_content_length(request_body.size());
|
||||||
|
http_request.set_host(host_, port_);
|
||||||
|
http_request.set_keep_alive(true);
|
||||||
|
|
||||||
|
http_request.set_soap_action(operation);
|
||||||
|
|
||||||
|
csoap::HttpClient http_client;
|
||||||
|
|
||||||
|
if (!http_client.SendRequest(http_request, request_body)) {
|
||||||
|
std::cerr << "Failed to send HTTP request." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const csoap::HttpResponse& http_response = http_client.response();
|
||||||
|
|
||||||
|
std::cout << http_response.status() << " " << http_response.reason() << std::endl;
|
||||||
|
|
||||||
|
csoap::SoapResponseParser soap_response_parser;
|
||||||
|
|
||||||
|
std::string rsp_message_name = operation + "Response";
|
||||||
|
std::string rsp_element_name = "Result";
|
||||||
|
|
||||||
|
soap_response_parser.Parse(http_response.content(),
|
||||||
|
rsp_message_name,
|
||||||
|
rsp_element_name,
|
||||||
|
result);
|
||||||
|
|
||||||
|
//std::cout << "return:\n" << *result << std::endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace demo
|
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef DEMO_CALCULATOR_H_
|
||||||
|
#define DEMO_CALCULATOR_H_
|
||||||
|
|
||||||
|
// Wrapper of calculator.wsdl.
|
||||||
|
// See http://service-repository.com/service/overview/877027757
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "csoap/common.h"
|
||||||
|
|
||||||
|
namespace demo {
|
||||||
|
|
||||||
|
class Calculator {
|
||||||
|
public:
|
||||||
|
Calculator();
|
||||||
|
|
||||||
|
bool Add(float x, float y, float* result);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
bool Call(const std::string& operation,
|
||||||
|
const csoap::Parameter* parameters,
|
||||||
|
size_t count,
|
||||||
|
std::string* result);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string url_; // Request URL
|
||||||
|
|
||||||
|
std::string host_;
|
||||||
|
std::string port_;
|
||||||
|
|
||||||
|
csoap::Namespace soap_envelope_ns_;
|
||||||
|
csoap::Namespace service_ns_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace demo
|
||||||
|
|
||||||
|
#endif // DEMO_CALCULATOR_H_
|
@ -0,0 +1,250 @@
|
|||||||
|
<?xml version="1.0" encoding="US-ASCII"?>
|
||||||
|
<!--generated by GLUE Standard 4.1.2 on Fri Nov 21 13:50:48 PST 2003-->
|
||||||
|
<wsdl:definitions name="Calculator"
|
||||||
|
targetNamespace="http://www.parasoft.com/wsdl/calculator/"
|
||||||
|
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
|
||||||
|
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
|
||||||
|
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
|
||||||
|
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
|
||||||
|
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
|
||||||
|
xmlns:tme="http://www.themindelectric.com/"
|
||||||
|
xmlns:tns="http://www.parasoft.com/wsdl/calculator/"
|
||||||
|
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
|
||||||
|
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||||
|
<wsdl:types>
|
||||||
|
<xsd:schema
|
||||||
|
elementFormDefault="qualified"
|
||||||
|
targetNamespace="http://www.parasoft.com/wsdl/calculator/">
|
||||||
|
<xsd:element
|
||||||
|
name="add">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element
|
||||||
|
name="x" type="xsd:float"/>
|
||||||
|
<xsd:element name="y"
|
||||||
|
type="xsd:float"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element
|
||||||
|
name="addResponse">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element
|
||||||
|
name="Result"
|
||||||
|
type="xsd:float"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element
|
||||||
|
name="divide">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element
|
||||||
|
name="numerator" type="xsd:float"/>
|
||||||
|
<xsd:element
|
||||||
|
name="denominator"
|
||||||
|
type="xsd:float"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element
|
||||||
|
name="divideResponse">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element
|
||||||
|
name="Result"
|
||||||
|
type="xsd:float"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element
|
||||||
|
name="multiply">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element
|
||||||
|
name="x" type="xsd:float"/>
|
||||||
|
<xsd:element name="y"
|
||||||
|
type="xsd:float"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element
|
||||||
|
name="multiplyResponse">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element
|
||||||
|
name="Result"
|
||||||
|
type="xsd:float"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element
|
||||||
|
name="subtract">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element
|
||||||
|
name="x" type="xsd:float"/>
|
||||||
|
<xsd:element name="y"
|
||||||
|
type="xsd:float"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element
|
||||||
|
name="subtractResponse">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element
|
||||||
|
name="Result"
|
||||||
|
type="xsd:float"/>
|
||||||
|
</xsd:sequence>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
</wsdl:types>
|
||||||
|
<wsdl:message
|
||||||
|
name="add0In">
|
||||||
|
<wsdl:part element="tns:add"
|
||||||
|
name="parameters"/>
|
||||||
|
</wsdl:message>
|
||||||
|
<wsdl:message
|
||||||
|
name="add0Out">
|
||||||
|
<wsdl:part element="tns:addResponse"
|
||||||
|
name="parameters"/>
|
||||||
|
</wsdl:message>
|
||||||
|
<wsdl:message
|
||||||
|
name="divide1In">
|
||||||
|
<wsdl:part element="tns:divide"
|
||||||
|
name="parameters"/>
|
||||||
|
</wsdl:message>
|
||||||
|
<wsdl:message
|
||||||
|
name="divide1Out">
|
||||||
|
<wsdl:part element="tns:divideResponse"
|
||||||
|
name="parameters"/>
|
||||||
|
</wsdl:message>
|
||||||
|
<wsdl:message
|
||||||
|
name="multiply2In">
|
||||||
|
<wsdl:part element="tns:multiply"
|
||||||
|
name="parameters"/>
|
||||||
|
</wsdl:message>
|
||||||
|
<wsdl:message
|
||||||
|
name="multiply2Out">
|
||||||
|
<wsdl:part element="tns:multiplyResponse"
|
||||||
|
name="parameters"/>
|
||||||
|
</wsdl:message>
|
||||||
|
<wsdl:message
|
||||||
|
name="subtract3In">
|
||||||
|
<wsdl:part element="tns:subtract"
|
||||||
|
name="parameters"/>
|
||||||
|
</wsdl:message>
|
||||||
|
<wsdl:message
|
||||||
|
name="subtract3Out">
|
||||||
|
<wsdl:part element="tns:subtractResponse"
|
||||||
|
name="parameters"/>
|
||||||
|
</wsdl:message>
|
||||||
|
<wsdl:portType
|
||||||
|
name="ICalculator">
|
||||||
|
<wsdl:operation name="add"
|
||||||
|
parameterOrder="x y">
|
||||||
|
<wsdl:input message="tns:add0In"
|
||||||
|
name="add0In"/>
|
||||||
|
<wsdl:output message="tns:add0Out"
|
||||||
|
name="add0Out"/>
|
||||||
|
</wsdl:operation>
|
||||||
|
<wsdl:operation name="divide"
|
||||||
|
parameterOrder="numerator denominator">
|
||||||
|
<wsdl:input
|
||||||
|
message="tns:divide1In" name="divide1In"/>
|
||||||
|
<wsdl:output
|
||||||
|
message="tns:divide1Out"
|
||||||
|
name="divide1Out"/>
|
||||||
|
</wsdl:operation>
|
||||||
|
<wsdl:operation
|
||||||
|
name="multiply" parameterOrder="x y">
|
||||||
|
<wsdl:input
|
||||||
|
message="tns:multiply2In" name="multiply2In"/>
|
||||||
|
<wsdl:output
|
||||||
|
message="tns:multiply2Out"
|
||||||
|
name="multiply2Out"/>
|
||||||
|
</wsdl:operation>
|
||||||
|
<wsdl:operation
|
||||||
|
name="subtract" parameterOrder="x y">
|
||||||
|
<wsdl:input
|
||||||
|
message="tns:subtract3In" name="subtract3In"/>
|
||||||
|
<wsdl:output
|
||||||
|
message="tns:subtract3Out"
|
||||||
|
name="subtract3Out"/>
|
||||||
|
</wsdl:operation>
|
||||||
|
</wsdl:portType>
|
||||||
|
<wsdl:binding
|
||||||
|
name="ICalculator" type="tns:ICalculator">
|
||||||
|
<soap:binding
|
||||||
|
style="document"
|
||||||
|
transport="http://schemas.xmlsoap.org/soap/http"/>
|
||||||
|
<wsdl:operation
|
||||||
|
name="add">
|
||||||
|
<soap:operation soapAction="add"
|
||||||
|
style="document"/>
|
||||||
|
<wsdl:input name="add0In">
|
||||||
|
<soap:body
|
||||||
|
use="literal"/>
|
||||||
|
</wsdl:input>
|
||||||
|
<wsdl:output
|
||||||
|
name="add0Out">
|
||||||
|
<soap:body
|
||||||
|
use="literal"/>
|
||||||
|
</wsdl:output>
|
||||||
|
</wsdl:operation>
|
||||||
|
<wsdl:operation
|
||||||
|
name="divide">
|
||||||
|
<soap:operation soapAction="divide"
|
||||||
|
style="document"/>
|
||||||
|
<wsdl:input name="divide1In">
|
||||||
|
<soap:body
|
||||||
|
use="literal"/>
|
||||||
|
</wsdl:input>
|
||||||
|
<wsdl:output
|
||||||
|
name="divide1Out">
|
||||||
|
<soap:body
|
||||||
|
use="literal"/>
|
||||||
|
</wsdl:output>
|
||||||
|
</wsdl:operation>
|
||||||
|
<wsdl:operation
|
||||||
|
name="multiply">
|
||||||
|
<soap:operation soapAction="multiply"
|
||||||
|
style="document"/>
|
||||||
|
<wsdl:input name="multiply2In">
|
||||||
|
<soap:body
|
||||||
|
use="literal"/>
|
||||||
|
</wsdl:input>
|
||||||
|
<wsdl:output
|
||||||
|
name="multiply2Out">
|
||||||
|
<soap:body
|
||||||
|
use="literal"/>
|
||||||
|
</wsdl:output>
|
||||||
|
</wsdl:operation>
|
||||||
|
<wsdl:operation
|
||||||
|
name="subtract">
|
||||||
|
<soap:operation soapAction="subtract"
|
||||||
|
style="document"/>
|
||||||
|
<wsdl:input name="subtract3In">
|
||||||
|
<soap:body
|
||||||
|
use="literal"/>
|
||||||
|
</wsdl:input>
|
||||||
|
<wsdl:output
|
||||||
|
name="subtract3Out">
|
||||||
|
<soap:body
|
||||||
|
use="literal"/>
|
||||||
|
</wsdl:output>
|
||||||
|
</wsdl:operation>
|
||||||
|
</wsdl:binding>
|
||||||
|
<wsdl:service
|
||||||
|
name="Calculator">
|
||||||
|
<wsdl:documentation>instance of class webtool.soap.examples.calculator.Calculator</wsdl:documentation>
|
||||||
|
<wsdl:port
|
||||||
|
binding="tns:ICalculator" name="ICalculator">
|
||||||
|
<soap:address
|
||||||
|
location="http://ws1.parasoft.com/glue/calculator"/>
|
||||||
|
</wsdl:port>
|
||||||
|
</wsdl:service>
|
||||||
|
</wsdl:definitions>
|
@ -0,0 +1,15 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include "demo/calculator.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
demo::Calculator calculator;
|
||||||
|
|
||||||
|
float result = 0.0;
|
||||||
|
if (!calculator.Add(1.0, 2.0, &result)) {
|
||||||
|
std::cerr << "Failed to call web service." << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "Add result: " << std::showpoint << result << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
project(pugixml)
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
|
set(HEADERS pugixml.hpp pugiconfig.hpp)
|
||||||
|
set(SOURCES ${HEADERS} pugixml.cpp)
|
||||||
|
|
||||||
|
add_library(pugixml STATIC ${SOURCES})
|
@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* pugixml parser - version 1.8
|
||||||
|
* --------------------------------------------------------
|
||||||
|
* Copyright (C) 2006-2016, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
||||||
|
* Report bugs and download new versions at http://pugixml.org/
|
||||||
|
*
|
||||||
|
* This library is distributed under the MIT License. See notice at the end
|
||||||
|
* of this file.
|
||||||
|
*
|
||||||
|
* This work is based on the pugxml parser, which is:
|
||||||
|
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HEADER_PUGICONFIG_HPP
|
||||||
|
#define HEADER_PUGICONFIG_HPP
|
||||||
|
|
||||||
|
// Uncomment this to enable wchar_t mode
|
||||||
|
// #define PUGIXML_WCHAR_MODE
|
||||||
|
|
||||||
|
// Uncomment this to enable compact mode
|
||||||
|
// #define PUGIXML_COMPACT
|
||||||
|
|
||||||
|
// Uncomment this to disable XPath
|
||||||
|
// #define PUGIXML_NO_XPATH
|
||||||
|
|
||||||
|
// Uncomment this to disable STL
|
||||||
|
// #define PUGIXML_NO_STL
|
||||||
|
|
||||||
|
// Uncomment this to disable exceptions
|
||||||
|
// #define PUGIXML_NO_EXCEPTIONS
|
||||||
|
|
||||||
|
// Set this to control attributes for public classes/functions, i.e.:
|
||||||
|
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
|
||||||
|
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
|
||||||
|
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
|
||||||
|
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
|
||||||
|
|
||||||
|
// Tune these constants to adjust memory-related behavior
|
||||||
|
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
|
||||||
|
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
|
||||||
|
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
|
||||||
|
|
||||||
|
// Uncomment this to switch to header-only version
|
||||||
|
// #define PUGIXML_HEADER_ONLY
|
||||||
|
|
||||||
|
// Uncomment this to enable long long support
|
||||||
|
// #define PUGIXML_HAS_LONG_LONG
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2006-2016 Arseny Kapoulkine
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person
|
||||||
|
* obtaining a copy of this software and associated documentation
|
||||||
|
* files (the "Software"), to deal in the Software without
|
||||||
|
* restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following
|
||||||
|
* conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue