XML Streams Module User’s Guide : Chapter 5 Performing Transformations : Transforming your XML Documents
Transforming your XML Documents
This section describes how to transform your XML documents.
Overview of the Transformation Process
The following sections illustrate how to perform both character-based and element-based transformations, using an object book.
The steps included in this section include:
adding serialization support (for more information, see Chapter 3)
creating a book object and serializing it to a file using an XML stream that applies a transformation to make the resulting XML more readable
reading the file back in and restoring the book object using an XML stream that applies a transformation to restore the original XML format
printing out both the original XML streams data for the book object and its more readable, transformed version
Adding Serialization Support
The object book holds an author name and a book title.
First, you will instantiate book, and add serialization support. This process is identical for both transformations.
 
class book
{
public:
book ();
book (const RWCString& title, const RWCString& author);
private:
RWCString title_;
RWCString author_;
};
As described in the example in Chapter 5, you must add macros to the header and implementation files to prepare the object for serialization.
To the header file, add the macro RW_DECLARE_VIRTUAL_STREAM_FNS(), which defines the streamContents() member function:
 
class book
{
RW_DECLARE_VIRTUAL_STREAM_FNS(book)
 
public:
book ();
book (const RWCString& title, const RWCString& author);
 
private:
RWCString title_;
RWCString author_;
};
Add to the header file:
// Add serialization support
RW_DECLARE_STREAMABLE_AS_SELF(book)
RW_DECLARE_STREAMABLE_POINTER(book)
 
To the implementation file, first add macros that define insertion and extraction operators for the class members:
 
// Define how book will be serialized
RW_BEGIN_STREAM_CONTENTS(book)
RW_STREAM_ATTR_MEMBER(title,title_)
RW_STREAM_ATTR_MEMBER(author,author_)
RW_END_STREAM_CONTENTS
Then add macros that allow the book object itself to be serialized as a pointer reference:
 
// Allow a reference to a book to be serialized
RW_DEFINE_STREAMABLE_POINTER(book)
RW_DEFINE_STREAMABLE_AS_SELF(book)
Serializing the book Object to a File
Next, you serialize your book object out to a file. Because the XML format generated by XML streams is difficult to read, transform the output stream into a more readable format.
Each of the following sections considers first a character-based C++ transformation, followed by an element-based C++ transformation.
For a Character-based C++ Transformation
 
int main()
{
using std::ofstream; //1
using std::ifstream;
using std::cout;
using std::endl;
 
book book1("To Love and Be Wise","Josephine Tey"); //2
book book2;
 
MyInStreamTransform inTransform; //3
MyOutStreamTransform outTransform; //4
 
{
ofstream fout("book.xml"); //5
 
RWObjectOutputStream out = //6
RWTTransformObjectOutputStreamImp<MyOutStreamTransform>
::make(fout,outTransform);
out << book1; //7
out.flush(); //8
}
//1 Indicates that certain variables refer to their counterparts in the STD namespace.
//2 Creates two book objects, one with data, one to hold the data when you restore the object later on.
//3 Initializes the input stream transformation engine. (For the full code example, see MyInStreamTransform.h and MyInStreamTransform.cpp at buildspace\examples\xmlstreams\transform\.)
//4 Initializes the output stream transformation engine (For the full code example, see MyOutStreamTransform.h and MyOutStreamTransform.cpp at buildspace\examples\xmlstreams\transform\.)
//5 Creates an ofstream for writing character data to a file.
//6 Sets up an XML output stream that includes support for a transformation.
//7 Serializes the book object to a file.
//8 Flushes the output buffer for the XML stream, transforming the XML in the process. You may perform this explicitly, as in this line, or you may let it happen implicitly when the destructor calls flush(), and the output stream goes out of scope.
For an Element-based C++ Transformation
 
int main()
{
using std::ofstream; //1
using std::ifstream;
using std::cout;
using std::endl;
 
book book1("To Love and Be Wise","Josephine Tey"); //2
book book2;
 
MyInParsedTransform inTransform; //3
MyOutParsedTransform outTransform; //4
 
{
ofstream fout("book.xml"); //5
 
RWObjectOutputStream out = //6
RWTParsedObjectOutputStreamImp<MyOutParsedTransform>
::make(fout,outTransform);
out << book1; //7
out.flush(); //8
}
//1 Indicates that certain variables refer to their counterparts in the STD namespace.
//2 Creates two book objects, one with data, one to hold the data when you restore the object later on.
//3 Initializes the parsed transformation input stream. (For the full code example, see MyInParsedTransform.h and MyInParsedTransform.cpp at buildspace\examples\xmlstreams\transform\.)
//4 Initializes the parsed transformation output stream. (For the full code example, see MyOutParsedTransform.h and MyOutParsedTransform.cpp at buildspace\examples\xmlstreams\transform\.)
//5 Creates an ofstream for writing character data to a file.
//6 Sets up an XML output stream that includes support for a transformation.
//7 Serializes the book object to a file.
//8 Flushes the output buffer for the XML stream, transforming the XML in the process. You may perform this explicitly, as in this line, or you may let it happen implicitly when the destructor calls flush(), and the output stream goes out of scope.
Restoring the book Object
At this point you have written the book object XML data to the file book.xml. Next you are ready to restore the object, which involves:
reading in the file book.xml
transforming the XML back to the form required by XML streams
restoring the object as book2
For a Character-based C++ Transformation
 
{
ifstream fin("book.xml"); //1
 
RWObjectInputStream in = //2
RWTTransformObjectInputStreamImp<MyInStreamTransform>
::make(fin,inTransform);
in >> book2; //3
}
//1 Creates an ifstream for reading in the object data.
//2 Sets up an XML input stream that includes support for a transformation.
//3 Restores the book object as the book2 instance created earlier, transforming the XML back to the expected XML format in the process.
For an Element-based C++ Transformation
 
{
ifstream fin("book.xml"); //1
 
RWObjectInputStream in = //2
RWTParsedObjectInputStreamImp<MyInParsedTransform>
::make(fin,inTransform);
in >> book2; //3
}
//1 Creates an ifstream for reading in the object data.
//2 Sets up an XML input stream that includes support for a transformation.
//3 Restores the book object as the book2 instance create earlier, transforming the XML back to the expected XML format in the process.
Examining the XML Output
Finally, the example writes to standard out two forms of the serialized object:
the transformed, more readable version
the form created by the XML serialization and expected by XML streams when the object is restored
For a Character-based C++ Transformation
{
RWObjectOutputStream out = //1
RWTTransformObjectOutputStreamImp<MyOutStreamTransform>
::make(cout,outTransform);
out << book2; //2
}
cout << endl;
{
RWObjectOutputStream out = //3
RWXmlObjectOutputStreamImp::make(cout);
out << book2; //4
}
return 0;
}
//1 Sets up an XML output stream that includes support for a transformation.
//2 Streams the transformed version of the book2 object to standard out.
//3 Sets up an XML output stream with no transformation support.
//4 Streams the standard XML streams version of the book2 object to standard out.
Here is the resulting output:
With transformation:
 
&lt;?xml version="1.0" encoding="UTF-8" standalone="yes"?&gt; &lt;rw:nested_object rw:class="book"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:rw="http://www.roguewave.com/xmlstream"&gt;
&lt;rw:member rw:name="title" xsi:type="xsd:string"&gt;To Love
and Be Wise&lt;/rw:member&gt;
&lt;rw:member rw:name="author" xsi:type="xsd:string"&gt;
Josephine Tey&lt;/rw:member&gt;&lt;/rw:nested_object&gt;
Without transformation:
 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<rw:nested_object rw:class="book"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:rw="http://www.roguewave.com/xmlstream">
<rw:member rw:name="title" xsi:type="xsd:string">To Love and Be
Wise</rw:member>
<rw:member rw:name="author" xsi:type="xsd:string">Josephine
Tey</rw:member></rw:nested_object>
For an Element-based C++ Transformation
 
{
RWObjectOutputStream out = //1
RWTParsedObjectOutputStreamImp<MyOutParsedTransform>
::make(cout,outTransform);
out << book2; //2
}
cout << endl;
{
RWObjectOutputStream out = //3
RWXmlObjectOutputStreamImp::make(cout);
out << book2; //4
}
return 0;
}
//1 Sets up an XML output stream that includes support for a transformation.
//2 Streams the transformed version of the book2 object to standard out.
//3 Sets up an XML output stream with no transformation support.
//4 Streams the standard XML streams version of the book2 object to standard out.
Here is the resulting output:
With transformation:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<book xmlns:rw="http://www.roguewave.com/xmlstream"
xsi:type="book"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance">
<title xsi:type="xsd:string">To Love and Be Wise</title>
<author xsi:type="xsd:string">Josephine Tey</author>
</book>
Without transformation:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>>
<rw:nested_object rw:class="book"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
xmlns:rw="http://www.roguewave.com/xmlstream">
<rw:member rw:name="title" xsi:type="xsd:string">To Love and Be
Wise</rw:member>
<rw:member rw:name="author" xsi:type="xsd:string">Josephine
Tey</rw:member></rw:nested_object>