Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

XML Generator

0.00/5 (No votes)
1 Apr 2001 2  
To Generate XML from any data source

Prerequisites

A knowledge of ATL, ADO and XML is a must.

Introduction

This 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 Database

The 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 Class

Now about the class. The name of the class is CXMLGenerator.

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 ATTRIBUTE which has 2 member variables by the name of strName and strValue.

Both the member variables are of type _bstr_t.

List of all the members of the class are as follows :

1. Member Variable

There is only one member variable which private to the class and is used to store DWORD type of data. This is useful in the generation of XML if we want the XML to be generated dependent on some condition.

DWORD m_lParam;

2. Static Function

The 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 NULL.

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. CreateElement ("author",NULL,false,"") will return <author/>.

While the same function if called with ATTRIBUTE of type strName = "ID" and strValue = "003" and the last parameter as "Shobha De", CreateElement ("author",attributeList, true,"Shobha De") then the output will look like this <author id="003">ShobhaDe</author>

BSTR XMLEncode(BSTR strEncode); is used to encode the data according to the XML standards.

3. Virtual Function

List of function virtual in nature are as follows:

BSTR PostContent(_RecordsetPtr RS); This function is used to do some post processing after the content of the XML Element is generated and before the element is closed.

BSTR PreContent(_RecordsetPtr RS); This function is used to do some pre processing befire the content of the XML Element is generated and after the element is defined.

BSTR BeforeEnd(); This function is used to add more XML data if required after the XML is generated for a given set of records.

BSTR AfterStart(); This function is used to add more XML data if required before the XML is generated for a given set of records.

BOOL HasValue(BSTR strElementName, BSTR strFieldValue); This function return true or false depending on whether the element should have a value or should the element be empty or self ending.

BSTR GetValue(BSTR strElementName, BSTR strFieldValue); This function provides the flexibility to change the value of the element if required else returns the value passed to the function.

ATTRIBUTE * GetAttributeList(BSTR ElementName, _RecordsetPtr RS); This function returns an array of ATTIRBUTE for the element if the attributes are required here. The attribute are in the form of Name Value pair.

BSTR GetElementName(BSTR FieldName); This function returns the name of the element if we want to change the name depending on the parameter passed.

BSTR GenerateXML(_RecordsetPtr RS,BSTR strRootNode, BSTR strChildNode, DWORD lParam) This function is the actual work horse of the XML Generation.

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 += "&lt!- ;
     strFinalString += strNode;
     strFinalString += ">";

   }
   return strFinalString;
}     

I would like the thank Morten Abrahamsen for the wrapper class CEnBSTR of _bstr_t which I have used for manipulating strings.

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here