CAPÍTULO 1. CONCEPTO Y ANTECEDENTES HISTÓRICO
1.2. Los precedentes históricos de la cláusula de conciencia en el
To deserialize a data type, its soap getfunction is used. The outline of a program that deserializes two variables var1and var2 is for example:
T1 var1; T2 var2;
struct soap soap; ...
soap init(&soap); // initialize at least once
[soap imode(&soap, flags);]// set input-mode flags soap begin(&soap); // begin new decoding phase
[soap.is = an input stream;]// C++
[soap.recvfd = an input file desriptpr;]// C
soap begin recv(&soap); // if HTTP/MIME/DIME/GZIP headers are present, parse them
if (!soap get Type1(&soap, &var1, ”[namespace-prefix:]element-name1”, ”[namespace-prefix:]type- name1”))
... error ...
if (!soap get Type2(&soap, &var2, ”[namespace-prefix:]element-name2”, ”[namespace-prefix:]type- name1”))
... error ... ...
soap end recv(&soap); // check consistency of id/hrefs soap destroy(&soap); // remove deserialized class instances
soap end(&soap); // remove temporary data, including the decoded data on the heap soap done(&soap); // finalize last use of the environment
The strings[namespace-prefix:]type-name1and[namespace-prefix:]type-name2are the schema types of the elements and should match the xsi:type attribute of the receiving message. To omit the match, useNULLas the type. For class instances, method invocation can be used instead of a function call if the object is already instantiated, i.e. obj.soap get(&soap, ”...”, ”...”).
Thesoap begincall resets the deserializers. Thesoap destroyandsoap endcalls remove the temporary data structures and the decoded data that was placed on the heap.
To remove temporary data while retaining the deserialized data on the heap, the function soap free
should be called instead of soap destroyand soap end.
One call to the soap get Type function of a type Type scans the entire input to process its XML content and to capture SOAP 1.1 independent elements (which contain multi-referenced objects). As a result, soap.error will set to SOAP EOF. Also storing multiple objects into one file will fail to decode them properly with multiplesoap getcalls. A well-formed XML document should only have one root anyway, so don’t save multiple objects into one file. If you must save multiple objects, create a linked list or an array of objects and save the linked list or array. You could use the
soap in Type function instead of the soap get Type function. The soap in Type function parses one XML element at a time.
You can deserialize class instances from a stream as follows:
myClass obj; struct soap soap;
soap init(&soap); // initialize
soap begin(&soap); // begin new decoding phase soap.is = cin; // read from cin
soap begin recv(&soap); // if HTTP header is present, parse it if (!obj.get(&soap, ”myClass”, NULL)
... error ...
soap end recv(&soap); // check consistency of id/hrefs ...
soap end(&soap); // remove temporary data, including the decoded data on the heap soap done(&soap); // finalize last use of the environment
When you declare a soap struct pointer as a data member in a class, you can overload the >> operator to parse and deserialize a class instance from a stream:
istream &operator>>(istream &i, myClass &e) {
if (!e.soap)
... error: need soap struct to deserialize (could use global struct)... istream *is = e.soap->is;
e.soap->is = &i;
if (soap begin recv(e.soap) || e.in(e.soap, NULL, NULL) || soap end recv(e.soap)) ... error ...
e.soap->is = is; return i; }
8.4.3 Example
As an example, consider the following data type declarations:
// Contents of file ”person.h”: typedef char *xsd string; typedef char *xsd Name;
typedef unsigned int xsd unsignedInt; enum ns Gender{male, female}; class ns Address { public: xsd string street; xsd unsignedInt number; xsd string city; }; class ns Person { public: xsd Name name;
enum ns Gender gender; ns Address address; ns Person *mother; ns Person *father; };
The following program uses these data types to write to standard output a data structure that contains the data of a person named ”John” living at Downing st. 10 in Londen. He has a mother ”Mary” and a father ”Stuart”. After initialization, the class instance for ”John” is serialized and encoded in XML to the standard output stream using gzip compression (requires the Zlib library, compile sources with -DWITH GZIP):
// Contents of file ”person.cpp”: #include ”soapH.h”
int main() {
struct soap soap;
ns Person mother, father, john; mother.name = "Mary"; mother.gender = female; mother.address.street = "Downing st."; mother.address.number = 10; mother.address.city = "London"; mother.mother = NULL; mother.father = NULL; father.name = "Stuart"; father.gender = male; father.address.street = "Main st."; father.address.number = 5; father.address.city = "London"; father.mother = NULL; father.father = NULL; john.name = "John"; john.gender = male; john.address = mother.address; john.mother = &mother; john.father = &father; soap init(&soap);
soap omode(&soap, SOAP ENC ZLIB|SOAP XML GRAPH); // see 9.12 soap begin(&soap);
soap begin send(&soap); john.soap serialize(&soap);
john.soap put(&soap, "johnnie", NULL); soap end send(&soap);
soap end(&soap); soap done(&soap); }
struct Namespace namespaces[] = {
{”SOAP-ENV”, ”http://schemas.xmlsoap.org/soap/envelope/”}, {”SOAP-ENC”,”http://schemas.xmlsoap.org/soap/encoding/”}, {”xsi”, ”http://www.w3.org/2001/XMLSchema-instance”}, {”xsd”, ”http://www.w3.org/2001/XMLSchema”},
{”ns”, ”urn:person”}, // Namespace URI of the “Person” data type {NULL, NULL}
};
The header file is processed and the application compiled on Linux/Unix with:
soapcpp2 person.h
g++ -DWITH GZIP -o person person.cpp soapC.cpp stdsoap2.cpp -lsocket -lxnet -lnsl -lz
(Depending on your system configuration, the libraries libsocket.a, libxnet.a, libnsl.a are required. Compiling on Linux typically does not require the inclusion of those libraries.) See 17.25 for details on compression with gSOAP.
<johnnie xsi:type="ns:Person" 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:ns="urn:person" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <name xsi:type="xsd:Name">John</name> <gender xsi:type="ns:Gender">male</gender> <address xsi:type="ns:Address">
<street id="3" xsi:type="xsd:string">Dowling st.</street> <number xsi:type="unsignedInt">10</number>
<city id="4" xsi:type="xsd:string">London</city> </address> <mother xsi:type="ns:Person"> <name xsi:type="xsd:Name">Mary</name> <gender xsi:type="ns:Gender">female</gender> <address xsi:type="ns:Address"> <street href="#3"/> <number xsi:type="unsignedInt">5</number> <city href="#4"/> </address> </mother> <father xsi:type="ns:Person"> <name xsi:type="xsd:Name">Stuart</name> <gender xsi:type="ns:Gender">male</gender> <address xsi:type="ns:Address">
<street xsi:type="xsd:string">Main st.</street> <number xsi:type="unsignedInt">13</number> <city href="#4"/>
</address> </father> </johnnie>
The following program fragment decodes this content from standard input and reconstructs the original data structure on the heap:
#include ”soapH.h” int main()
{
struct soap soap;
ns Person *mother, *father, *john = NULL; soap init(&soap);
soap imode(&soap, SOAP ENC ZLIB); // optional: gzip is detected automatically soap begin(&soap);
soap begin recv(&soap);
if (soap get ns Person(&soap, john, ”johnnie”, NULL)) ... error ...
mother = john->mother; father = john->father; ...
soap end recv(&soap);
soap free(&soap); // Clean up temporary data but keep deserialized data }
struct Namespace namespaces[] = { {”SOAP-ENV”, ”http://schemas.xmlsoap.org/soap/envelope/”}, {”SOAP-ENC”,”http://schemas.xmlsoap.org/soap/encoding/”}, {”xsi”, ”http://www.w3.org/2001/XMLSchema-instance”}, {”xsd”, ”http://www.w3.org/2001/XMLSchema”},
{”ns”, ”urn:person”}, // Namespace URI of the “Person” data type {NULL, NULL}
};
It is REQUIRED to either passNULLto the soap getroutine, or a valid pointer to a data structure that can hold the decoded content. The following example explicitly passes NULL:
john = soap get ns Person(&soap, NULL, ”johnnie”, NULL);
Note: the secondNULLparameter indicates that the schema type attribute of the receiving message can be ignored. The deserializer stores the SOAP contents on the heap, and returns the address. The allocated storage is released with thesoap endcall, which removes all temporary and deserialized data from the heap, or with thesoap free call, which removes all temporary data only.
Alternatively, the XML content can be decoded within an existing allocated data structure. The following program fragment decodes the SOAP content in astruct ns Personallocated on the stack:
#include ”soapH.h” main()
{
struct soap soap;
ns Person *mother, *father, john; soap init(&soap);
soap imode(&soap, SOAP ENC ZLIB); // optional soap begin(&soap);
soap begin recv(&soap);
soap default ns Person(&soap, &john);
if (soap get ns Person(&soap, &john, ”johnnie”, NULL)) ... error ...
... }
struct Namespace namespaces[] = ...
Note the use of soap default ns Person. This routine is generated by the gSOAP stub and skeleton compiler and assigns default values to the fields ofjohn.