Reorganize examples; fix soap issues.

This commit is contained in:
Chunting Gu
2019-03-15 14:40:36 +08:00
parent 05782b773a
commit 616f5a3f5e
49 changed files with 959 additions and 1091 deletions
+61
View File
@@ -0,0 +1,61 @@
#include "examples/common/book.h"
#include <algorithm>
#include <iostream>
const Book kNullBook{};
std::ostream& operator<<(std::ostream& os, const Book& book) {
os << "{ " << book.id << ", " << book.title << ", " << book.price << " }";
return os;
}
const Book& BookStore::GetBook(const std::string& id) const {
auto it = FindBook(id);
return (it == books_.end() ? kNullBook : *it);
}
std::string BookStore::AddBook(const Book& book) {
std::string id = NewID();
books_.push_back({ id, book.title, book.price });
return id;
}
bool BookStore::UpdateBook(const Book& book) {
auto it = FindBook(book.id);
if (it != books_.end()) {
it->title = book.title;
it->price = book.price;
return true;
}
return false;
}
bool BookStore::DeleteBook(const std::string& id) {
auto it = FindBook(id);
if (it != books_.end()) {
books_.erase(it);
return true;
}
return false;
}
std::list<Book>::const_iterator BookStore::FindBook(const std::string& id)
const {
return std::find_if(books_.begin(), books_.end(),
[&id](const Book& book) { return book.id == id; });
}
std::list<Book>::iterator BookStore::FindBook(const std::string& id) {
return std::find_if(books_.begin(), books_.end(),
[&id](Book& book) { return book.id == id; });
}
std::string BookStore::NewID() const {
static int s_id_counter = 0;
++s_id_counter;
return std::to_string(s_id_counter);
}
+47
View File
@@ -0,0 +1,47 @@
#ifndef EXAMPLE_COMMON_BOOK_H_
#define EXAMPLE_COMMON_BOOK_H_
#include <list>
#include <string>
// In-memory test data.
// There should be some database in a real product.
struct Book {
std::string id;
std::string title;
double price;
bool IsNull() const { return id.empty(); }
};
std::ostream& operator<<(std::ostream& os, const Book& book);
extern const Book kNullBook;
class BookStore {
public:
const std::list<Book>& books() const { return books_; }
const Book& GetBook(const std::string& id) const;
// Add a book, return the ID.
// NOTE: The ID of the input book will be ignored so should be empty.
std::string AddBook(const Book& book);
bool UpdateBook(const Book& book);
bool DeleteBook(const std::string& id);
private:
std::list<Book>::const_iterator FindBook(const std::string& id) const;
std::list<Book>::iterator FindBook(const std::string& id);
// Allocate a new book ID.
std::string NewID() const;
std::list<Book> books_;
};
#endif // EXAMPLE_COMMON_BOOK_H_
+57
View File
@@ -0,0 +1,57 @@
#include "examples/common/book_json.h"
#include <sstream>
#include <iostream>
#include "json/json.h"
#include "examples/common/book.h"
std::string JsonToString(const Json::Value& json) {
Json::StreamWriterBuilder builder;
return Json::writeString(builder, json);
}
Json::Value StringToJson(const std::string& str) {
Json::Value json;
Json::CharReaderBuilder builder;
std::stringstream stream(str);
std::string errs;
if (!Json::parseFromStream(builder, stream, &json, &errs)) {
std::cerr << errs << std::endl;
}
return json;
}
Json::Value BookToJson(const Book& book) {
Json::Value json;
json["id"] = book.id;
json["title"] = book.title;
json["price"] = book.price;
return json;
}
Book JsonToBook(const Json::Value& json) {
return {
json["id"].asString(),
json["title"].asString(),
json["price"].asDouble(),
};
}
std::string BookToJsonString(const Book& book) {
return JsonToString(BookToJson(book));
}
bool JsonStringToBook(const std::string& json_str, Book* book) {
Json::Value json = StringToJson(json_str);
if (!json) {
return false;
}
*book = JsonToBook(json);
return true;
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef EXAMPLE_COMMON_BOOK_JSON_H_
#define EXAMPLE_COMMON_BOOK_JSON_H_
#include <string>
#include "json/json-forwards.h"
struct Book;
std::string JsonToString(const Json::Value& json);
Json::Value StringToJson(const std::string& str);
Json::Value BookToJson(const Book& book);
Book JsonToBook(const Json::Value& json);
std::string BookToJsonString(const Book& book);
bool JsonStringToBook(const std::string& json_str, Book* book);
#endif // EXAMPLE_COMMON_BOOK_JSON_H_
+147
View File
@@ -0,0 +1,147 @@
#include "examples/common/book_xml.h"
#include <cassert>
#include <functional>
#include <sstream>
#include "examples/common/book.h"
// -----------------------------------------------------------------------------
// Print a XML node to string.
static std::string PrintXml(pugi::xml_node xnode, bool format_raw = true,
const char* indent = "") {
std::stringstream ss;
unsigned int flags = format_raw ? pugi::format_raw : pugi::format_indent;
xnode.print(ss, indent, flags);
return ss.str();
}
// -----------------------------------------------------------------------------
bool XmlToBook(pugi::xml_node xbook, Book* book) {
assert(xbook.name() == std::string("book"));
book->id = xbook.child("id").text().as_string();
book->title = xbook.child("title").text().as_string();
book->price = xbook.child("price").text().as_double();
return true;
}
void BookToXml(const Book& book, pugi::xml_node* xparent) {
pugi::xml_node xbook = xparent->append_child("book");
xbook.append_child("id").text().set(book.id.c_str());
xbook.append_child("title").text().set(book.title.c_str());
xbook.append_child("price").text().set(book.price);
}
bool XmlToBookList(pugi::xml_node xbooks, std::list<Book>* books) {
assert(xbooks.name() == std::string("books"));
pugi::xml_node xbook = xbooks.child("book");
while (xbook) {
Book book{
xbook.child("id").text().as_string(),
xbook.child("title").text().as_string(),
xbook.child("price").text().as_double()
};
books->push_back(book);
xbook = xbook.next_sibling("book");
}
return true;
}
void BookListToXml(const std::list<Book>& books, pugi::xml_node* xparent) {
pugi::xml_node xbooks = xparent->append_child("books");
for (const Book& book : books) {
BookToXml(book, &xbooks);
}
}
bool XmlStringToBook(const std::string& xml_string, Book* book) {
pugi::xml_document xdoc;
if (!xdoc.load_string(xml_string.c_str())) {
return false;
}
pugi::xml_node xbook = xdoc.document_element();
if (!xbook) {
return false;
}
if (xbook.name() != std::string("book")) {
return false;
}
return XmlToBook(xbook, book);
}
std::string BookToXmlString(const Book& book, bool format_raw,
const char* indent) {
pugi::xml_document xdoc;
BookToXml(book, &xdoc);
return PrintXml(xdoc);
}
// -----------------------------------------------------------------------------
std::string NewRequestXml(const Book& book) {
pugi::xml_document xdoc;
pugi::xml_node xwebcc = xdoc.append_child("webcc");
xwebcc.append_attribute("type") = "request";
BookToXml(book, &xwebcc);
return PrintXml(xdoc, false, " ");
}
// -----------------------------------------------------------------------------
static std::string __NewResultXml(int code, const char* message,
std::function<void(pugi::xml_node*)> callback) {
pugi::xml_document xdoc;
pugi::xml_node xwebcc = xdoc.append_child("webcc");
xwebcc.append_attribute("type") = "response";
pugi::xml_node xstatus = xwebcc.append_child("status");
xstatus.append_attribute("code") = code;
xstatus.append_attribute("message") = message;
if (callback) {
callback(&xwebcc);
}
return PrintXml(xdoc, false, " ");
}
std::string NewResultXml(int code, const char* message) {
return __NewResultXml(code, message, {});
}
std::string NewResultXml(int code, const char* message, const char* node,
const char* key, const char* value) {
auto callback = [node, key, value](pugi::xml_node* xparent) {
pugi::xml_node xnode = xparent->append_child(node);
xnode.append_child(key).text() = value;
};
return __NewResultXml(code, message, callback);
}
std::string NewResultXml(int code, const char* message, const Book& book) {
return __NewResultXml(code, message,
std::bind(BookToXml, book, std::placeholders::_1));
}
std::string NewResultXml(int code, const char* message,
const std::list<Book>& books) {
return __NewResultXml(code, message,
std::bind(BookListToXml, books, std::placeholders::_1));
}
+111
View File
@@ -0,0 +1,111 @@
#ifndef EXAMPLE_COMMON_BOOK_XML_H_
#define EXAMPLE_COMMON_BOOK_XML_H_
#include <list>
#include <string>
#include "pugixml/pugixml.hpp"
struct Book;
// -----------------------------------------------------------------------------
// Convert the following XML node to a book object.
// <book>
// <id>1</id>
// <title>1984</title>
// <price>12.3</price>
// </book>
bool XmlToBook(pugi::xml_node xbook, Book* book);
// Convert a book object to XML and append to the given parent.
void BookToXml(const Book& book, pugi::xml_node* xparent);
// Convert the following XML node to a list of book objects.
// <books>
// <book>
// <id>1</id>
// <title>1984</title>
// <price>12.3</price>
// </book>
// ...
// </books>
bool XmlToBookList(pugi::xml_node xbooks, std::list<Book>* books);
// Convert a list of book objects to XML and append to the given parent.
void BookListToXml(const std::list<Book>& books, pugi::xml_node* xparent);
// Convert the following XML string to a book object.
// <book>
// <id>1</id>
// <title>1984</title>
// <price>12.3</price>
// </book>
bool XmlStringToBook(const std::string& xml_string, Book* book);
// Convert a book object to XML string.
std::string BookToXmlString(const Book& book, bool format_raw = true,
const char* indent = "");
// -----------------------------------------------------------------------------
// This example defines its own result XML which will be embedded into the SOAP
// envolope as CDATA. The general schema of this result XML is:
// <webcc type = "result">
// <status code = "{code}" message = "{message}">
// </webcc>
// The "status" node is mandatory, you should define proper status codes and
// messages according to your needs.
// Additional data is attached as the sibling of "status" node, e.g.,
// <webcc type = "result">
// <status code = "{code}" message = "{message}">
// <book>
// <id>{book.id}</id>
// <title>{book.title}</title>
// <price>{book.price}</price>
// </book>
// </webcc>
// Create a result XML as below:
// <webcc type = "result">
// <status code = "{code}" message = "{message}">
// </webcc>
std::string NewResultXml(int code, const char* message);
// Create a result XML as below:
// <webcc type = "result">
// <status code = "{code}" message = "{message}">
// <{node}>
// <{key}>{value}</{key}>
// </{node}>
// </webcc>
std::string NewResultXml(int code, const char* message, const char* node,
const char* key, const char* value);
// Create a result XML as below:
// <webcc type = "result">
// <status code = "{code}" message = "{message}">
// <book>
// <id>{book.id}</id>
// <title>{book.title}</title>
// <price>{book.price}</price>
// </book>
// </webcc>
std::string NewResultXml(int code, const char* message, const Book& book);
// Create a result XML as below:
// <webcc type = "result">
// <status code = "{code}" message = "{message}">
// <books>
// <book>
// <id>{book.id}</id>
// <title>{book.title}</title>
// <price>{book.price}</price>
// </book>
// ...
// </books>
// </webcc>
std::string NewResultXml(int code, const char* message,
const std::list<Book>& books);
#endif // EXAMPLE_COMMON_BOOK_XML_H_