|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
PrerequisitesA knowledge of ATL, ADO and XML is a must. IntroductionThis is an article about XML and one of the ways that you can generate XML. I had this project where the design was in the form of an 'n' tier and the application demanded that, the data should be displayed using XSLT. The input the XSLT is XML Data. All the Data for the project was stored in SQL Server 7.0 and we were supposed to retrive the data convert the data to XML and give it for further processing in the form of XSLT Transformation. We had to give out put in various level of hirearchy. The DatabaseThe Database used for the demo is the good old pubs database, one of the standard databases installed with SQL Server. You would have to change the location of the your database server name in the demo. It is a constant defined in the stdafx.h. The line to change is as follows: #define CONNECTION_STRING L"Provider=sqloledb;Data Source=[your database server name here];Initial Catalog=pubs;"
The ClassNow about the class. The name of the class is The whole class is encapsulated by an ATL Object because of the project design. It has a member variable, a few static functions and other virtual functions so as to facilitate the XML generation, it is far more flexible this way. All the datatypes are Automation compatible so as the facilitate the scripting languages to call upon these objects. This class uses a helper class/structure called Both the member variables are of type List of all the members of the class are as follows : 1. Member VariableThere is only one member variable which private to the class and is used to store DWORD m_lParam;
2. Static FunctionThe function defenitions are as follows: BSTR CreateElement(BSTR strElementName,ATTRIBUTE * AttributeList, BOOL bHasValue, BSTR strElementValue);
The above mentioned function is used to actually create the Element in an XML Document. First parameter is the Name of the element to be created, second is the List of attributes that the attribute can have. Iif there are no attributes required for the element then this value has to be The third parameter is used to check whether the Element is has any value of not. If this parameter is passed false then the last parameter is ignored and the element is self ended or empty tag. Else if the third parameter is true then the last parameter is taken as the value for the element and then the tag is ended with the element name. For e.g. While the same function if called with
3. Virtual FunctionList of function virtual in nature are as follows:
The code for the Fuction is as given below.
BSTR CXMLGenerator::GenerateXML(_RecordsetPtr RS, BSTR strRootNode, BSTR strChildNode, DWORD lParam)
{
CEnBSTR *strFieldName;
_bstr_t strNode;
_bstr_t strFinalString = _bstr_t("");
if(SysStringLen(strRootNode) != 0)
{
// Append RootNode in the String
strFinalString = "<";
strFinalString += strRootNode;
strFinalString += ">";
// Get the RootNodeName from whole string with Attributes.
strNode = GetNodeName(strRootNode);
}
// store the Param in member variable
m_lParam = lParam;
// Give one chance to AfterStart Function
strFinalString += AfterStart();
long nFldCount = RS->Fields->GetCount();
strFieldName = new CEnBSTR[nFldCount];
// Store all the FieldName in an Array.
for(long i=0; i < nFldCount; i++)
{
strFieldName[i] = RS->Fields->Item[i]->Name;
strFieldName[i].lower();
}
// Contains Final Element
_bstr_t strFinalElement;
// For each Record in in the RecordSet here each record means eg. Author
while(!RS->ADOEOF)
{
strFinalElement = "";
// Get the Attribute of the Child Node.
ATTRIBUTE * ChildAttribute = GetAttributeList(strChildNode,RS);
// Give a Chance to PreContent
strFinalElement = PreContent(RS);
// Now for each Element in ChildNode e.g Cycle Get the Name and Attribute List
for(long i=0; i < nFldCount; i++)
{
_bstr_t strElement = GetElementName(strFieldName[i]);
if(SysStringLen(strElement) != 0)
{
_variant_t temp1, temp2;
// Get the Attribute List fpr Elements.
ATTRIBUTE * EleAttribute = GetAttributeList(strElement,RS);
temp1 = RS->Fields->GetItem(i)->Value;
_bstr_t strElementValue;
if(temp1.vt != VT_NULL)
{
HRESULT hr = VariantChangeType (&temp2,&temp1, VARIANT_NOUSEROVERRIDE | VARIANT_ALPHABOOL,VT_BSTR); if (FAILED(hr))
{
return _bstr_t ("");
}
strElementValue = temp2.bstrVal ;
}
else
strElementValue = _bstr_t("");
BOOL bHasValue = HasValue(strElement,strElementValue);
if(bHasValue)
{
strElementValue = GetValue(strElement,strElementValue);
}
// Add to Final String
strFinalElement += CreateElement(strElement,EleAttribute,bHasValue,strElementValue);
if (EleAttribute)
delete [] EleAttribute;
}
}
// Give a Chance to PostContent
strFinalElement += PostContent(RS);
// Create the Child Node & add it in Final XML String
strFinalString += CreateElement(strChildNode,ChildAttribute,SysStringLen(strFinalElement) ? TRUE : FALSE, strFinalElement);
if (ChildAttribute)
delete [] ChildAttribute;
RS->MoveNext();
}
// Give a chance to BeforeEnd.
strFinalString += BeforeEnd();
if(SysStringLen(strRootNode) != 0)
{
// Append the Closing RootNode.
strFinalString += "<!- ;
strFinalString += strNode;
strFinalString += ">";
}
return strFinalString;
}
I would like the thank Morten Abrahamsen for the wrapper class CEnBSTR of This class by itself will generate a very simple form of XML. But for a complex hirearchy you will have to derive from this class and override the methods as required. I have used two such classes in the demo project. The code will execute except for the database server name which I have mentioned earlier. Any comments and suggestions are always welcome. Happy XML Generating.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||