Please refer to the samples xml_grid and xml_samp, available from the Rogue Wave Web site, as explained in Section 3.6.1, "Location of Sample Code," in the Stingray Studio Getting Started Guide.
The XML map which is the parsed version of the XML schema/DTD is represented using the following data structure:
class XML_ENTRY_MAP { ... /* The name of the node.*/ LPCTSTR pszName; // 1 /* Unique id assigned to this node. When an element appears in more than one part of a document, each occurence should usually have a different relative id.*/ ENTRYID dwID; // 2 /* The type of the node. Please refer to DOMNode type in the MSDN documentation.*/ DOMNodeType entryType; // 3 /*Qualifying namespace if any.*/ LPCTSTR pszNameSpace; // 4 /*List that holds nested nodes.*/ CXMLList listXMLMapEntries_p; // 5 }; |
This structure has all the essential elements that are needed to represent a node in the XML document. These are:
When the processing system reads this data structure, it can loop through the nodes and, depending on whether an XML read or write operation is taking place, call feedback interfaces. The purpose of these feedback interfaces varies between the read and write operation. Let us look at IXMLRResolver, the read feedback interface, first.
The IXMLRResolver interface is the primary interface that is used by the XML read code that processes XML_ENTRY_MAP structures when reading XML data streams.
Given below is the interface specification for this interface.
class IXMLRResolver { ... //@cmember /* Will be called when the system starts to read data from the XML data stream.*/ virtual void OnStartRead() = 0; //@cmember /* Will be called when the system completes reading from the stream*/ virtual void OnCompleteRead() = 0; //@cmember /* Will be called when read is started for a particular node type. */ virtual bool OnStartReadLoop(const XML_ENTRY_MAP* pEntry) = 0; //@cmember /* Will be called to give the value of a node (as the nodes are read out) */ virtual bool OnSetValue(const XML_ENTRY_MAP* pEntry, MSXML::IXMLDOMNode* pThisNode, XMLVALUE& xmlValue) = 0; }; |
When read() starts, the system calls OnStartRead(), and when read ends, the system calls OnCompleteRead(). This is pretty straightforward. You can perform any one-time initialization (and cleanup) when these calls are made. You usually do not have to implement these and the other IXMLRResolver methods, as they are implemented by macros which we shall see later.
OnStartReadLoop() requires a little explanation. This is called the first time a node with a particular ID is read. For example, consider the following XML snippet:
<address> <street>Pine drive</street> <apt>432</apt> </address> <address> <street>Oak drive</street> <apt>32</apt> </address> |
When this is read, if there is an handler for street (identified to the system by the unique id, say, idStreet), then OnStartReadLoop() will be called when this node is hit for the first time. This is useful if you have to perform any initialization to be able to read this data. When the actual element is read, OnSetValue() is called. This has parameters (the XML_ENTRY_MAP value and the node pointer) that identify the node in question. The value itself is stored in an XML_VALUE parameter. This can be used to initialize your data structures.
The write feedback interface is very similar.
class IXMLWResolver { ... // write feedback interface // @access public /* Will be called when write is started */ virtual void OnStartWrite() = 0; /* Will be called when write is completed */ virtual void OnCompleteWrite() = 0; /* Will be called when a value needs to be supplied (just before the write operation for a node takes place) */ virtual bool OnGetValue(const XML_ENTRY_MAP* pEntry, MSXML::IXMLDOMNode* pParentNode, XMLVALUE& xmlValue) = 0; /* Will be called when a node is to be written out for the first time. */ virtual bool OnStartWriteLoop(const XML_ENTRY_MAP* pEntry) = 0; // will be called when to check whether write needs to // be continued on a node type virtual bool OnCanContinueWriteLoop(const XML_ENTRY_MAP* pEntry, MSXML::IXMLDOMNode* pNodeAdded) = 0; // will be called when writing is stopped for a // particular node type virtual bool OnEndWriteLoop(const XML_ENTRY_MAP* pEntry) = 0; }; |
There are some differences from IXMLWResolver. OnGetValue() will be called to retrieve the value for the node that is being written. OnStartWriteLoop() will be called when the node is written for the first time (same as when the node is read for the first time). However, if this function returns true, it will be repeatedly called.
In addition, OnEndWriteLoop() will be called when the write process is complete for a loop. Also OnCanContinueLoop() will be called to check whether there is additional data to be written out. You can use this to control how many node instances get written out for a given ID. For example if you have a linked list of addresses, you could return false from this function when you have reached the end of the linked list in order to write the whole list.
Populating these structures can be automated in two ways:
Using macros
Using tools that can generate code based on input parameters
We have followed both these approaches in order to make development with the Stingray XML library easier.
Copyright © Rogue Wave Software, Inc. All Rights Reserved.
The Rogue Wave name and logo, and Stingray, are registered trademarks of Rogue Wave Software. All other trademarks are the property of their respective owners.
Provide feedback to Rogue Wave about its documentation.