Я играл с привязкой данных gSOAP XML, загружая XML-документ в класс C++, изменяя данные и сериализуя его обратно в XML.Почему gSOAP устанавливает режим stdin в двоичный файл, если считывает данные из потока файлов?
Вот фрагмент из XML - Library.xml:
<?xml version="1.0" encoding="UTF-8"?>
<gt:Library xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:gt="http://www.bk.com/gSOAP/test">
<gt:Books>
<gt:Book isbn="0132350882" author="Robert C. Martin" title="Clean Code">
<gt:CopiesAvailable>2</gt:CopiesAvailable>
</gt:Book>
<gt:Book isbn="020161622X" author="Andrew Hunt" title="The Pragmatic Programmer">
<gt:CopiesAvailable>0</gt:CopiesAvailable>
</gt:Book>
<gt:Book isbn="0201633612" author="Erich Gamma" title="Design patterns">
<gt:CopiesAvailable>1</gt:CopiesAvailable>
</gt:Book>
</gt:Books>
...
</gt:Library>
Следующий код загружает XML в объект, модифицирует объект и упорядочивает его обратно в XML. Обратите внимание, что XML загружается из файла через поток файлов и данные, которые нужно добавить, получают от пользователя через stdin (cin).
main.cpp:
#include "soapH.h"
#include "gt.nsmap"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using std::cin;
using std::cout;
using std::endl;
using std::ifstream;
using std::ofstream;
using std::fstream;
using std::string;
using std::stringstream;
void DisplayAllBooks(const _gt__Library& library)
{
cout << "\n\nDisplaying all books in the library:" << endl;
std::vector<_gt__Library_Books_Book>::const_iterator it = library.Books.Book.begin();
for(;it != library.Books.Book.end(); it++)
{
cout << "\nBook:\n" << "\tTitle:" << (*it).title << "\n\tAuthor:" << (*it).author <<"\n\tISBN: " << (*it).isbn << "\n\tCopies available: " << static_cast<int>((*it).CopiesAvailable) << endl;
}
}
void AddBook(_gt__Library& library)
{
cout << "\n\nAdding a new book:" << endl;
_gt__Library_Books_Book book;
cout << "\tTitle: " << std::flush;
getline(cin, book.title);
cout << "\tAuthor: " << std::flush;
getline(cin, book.author);
cout << "\tISBN:" << std::flush;
getline(cin, book.isbn);
cout << "\tCopies available: " << std::flush;
string strCopiesAvailable;
getline(cin, strCopiesAvailable);
stringstream ss(strCopiesAvailable);
ss >> book.CopiesAvailable;
library.Books.Book.push_back(book);
}
// Terminate and destroy soap
void DestroySoap(struct soap* pSoap)
{
// remove deserialized class instances (C++ objects)
soap_destroy(pSoap);
// clean up and remove deserialized data
soap_end(pSoap);
// detach context (last use and no longer in scope)
soap_done(pSoap);
}
int main()
{
//
// Create and intialize soap
//
// gSOAP runtime context
struct soap soap;
// initialize runtime context
soap_init(&soap);
// Set input mode
soap_imode(&soap, SOAP_ENC_XML);
// reset deserializers; start new (de)serialization phase
soap_begin(&soap);
//
// Load XML (Deserialize)
//
_gt__Library library;
string strXML = "library.xml";
ifstream fstreamIN(strXML);
soap.is = &fstreamIN;
// calls soap_begin_recv, soap_get__gt__Library and soap_end_recv
if(soap_read__gt__Library(&soap, &library) != SOAP_OK)
{
std::cout << "soap_read__gt__Library() failed" << std::endl;
DestroySoap(&soap);
return 1;
}
fstreamIN.close();
//
// Display books before and after adding a new book
//
DisplayAllBooks(library);
AddBook(library);
DisplayAllBooks(library);
//
// Serialize
//
soap_set_omode(&soap, SOAP_XML_INDENT);
ofstream fstreamOUT("library.xml");
soap.os = &fstreamOUT;
// calls soap_begin_send, soap_serialize, soap_put and soap_end_send
if(soap_write__gt__Library(&soap, &library) != SOAP_OK)
{
std::cout << "soap_write__gt__Library() failed" << std::endl;
DestroySoap(&soap);
return 1;
}
fstreamOUT.close();
DestroySoap(&soap);
return 0;
}
После запуска этого тестового приложения, все отлично от всех вновь добавленных элементов имеют строки, которые заканчиваются с символом возврата каретки (CR - 
):
Модифицированными XML выглядит следующим образом:
<?xml version="1.0" encoding="UTF-8"?>
<gt:Library xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:gt="http://www.bk.com/gSOAP/test">
<gt:Books>
<gt:Book isbn="0132350882" author="Robert C. Martin" title="Clean Code">
<gt:CopiesAvailable>2</gt:CopiesAvailable>
</gt:Book>
<gt:Book isbn="020161622X" author="Andrew Hunt" title="The Pragmatic Programmer">
<gt:CopiesAvailable>0</gt:CopiesAvailable>
</gt:Book>
<gt:Book isbn="0201633612" author="Erich Gamma" title="Design patterns">
<gt:CopiesAvailable>1</gt:CopiesAvailable>
</gt:Book>
<gt:Book isbn="12345678
" author="Scott Meyers
" title="Effective C++
">
<gt:CopiesAvailable>123</gt:CopiesAvailable>
</gt:Book>
</gt:Books>
...
</gt:Library>
Я проследил источник ошибки и обнаружил следующее:
soap_read__gt__Library()
называет soap_begin_send()
, который выполняет следующую строку:
_setmode(soap->recvfd, _O_BINARY);
soap->recvfd
установлен в 0
в soap_init()
и 0
является значение файла дескриптора stdin
.
После режима stdin
«s изменяется на двоичном, библиотека STL не анализирует \r\n
к одному \n
для операций чтения и getline(cin, str)
, как обычно, читает все до \n
, копирование \r
в выходную строку. И это точно символ возврата каретки, который появляется в новых строках в конечном XML.
Мой вопрос: Почему gSOAP изменяет режим stdin
, если источником данных является поток файлов? Это ошибка в gSOAP?
Примечание:
Как и следовало ожидать, если режим stdio
«s будет вновь вернулась к _O_TEXT
после soap_begin_send()
но перед чтением данных из std::cin
, getline()
работает отлично. Вот патч:
_setmode(_fileno(stdin), _O_TEXT)
Спасибо за ваш ответ. Но зачем вообще использовать gSOAP * touch * стандартный поток ввода? Он считывает данные из потока файлов (выполняется 'soap-> is-> read()'), а не из 'stdio'. gSOAP оставляет 'stdio' в двоичном режиме после' soap_begin_send() 'и никогда не возвращает его обратно в текстовый режим по умолчанию. –
Вам не нужно изменять recvfd для использования потоков. Мыло -> поток имеет приоритет над soap-> recvfd. –