Thursday, January 21, 2010

Read and Write logs in XML file

If you dont want to use a DB, but still want to store, read data in a structured way, then xml is the best option. Its also used to send data over the internet.

Lets take a look at how we can create, format, read, and write data into xml file. You need to add using System.xml class with your file

1. Create an xml file:

XmlTextWriter xmltr = new XmlTextWriter(filePath, System.Text.Encoding.UTF8);
xmltr.Flush();
xmltr.Formatting = Formatting.Indented;
xmltr.WriteProcessingInstruction("xml", "version='1.0' encoding='UTF-8'");
xmltr.WriteStartElement("ComponentLog");
xmltr.Close();

We are using XmlTextWriter class to create the file. ComponentLog is the parent node in the xml file. An xml file can contain only 1 parent node.

2. Set format of the xml file:

XmlDocument doc = new XmlDocument();
doc.Load(filePath);
XmlNode node = doc.GetElementsByTagName("*")[0];

XmlAttribute xmlatr = doc.CreateAttribute("xmlns", "xsi", "http://www.w3.org/2000/xmlns/");
xmlatr.InnerText = "http://www.w3.org/2001/XMLSchema-instance";
XmlAttribute xmlatr2 = doc.CreateAttribute("xmlns", "xsd", "http://www.w3.org/2000/xmlns/");
xmlatr2.InnerText = "http://www.w3.org/2001/XMLSchema";

node.Attributes.Append(xmlatr);
node.Attributes.Append(xmlatr2);

XmlNode SQLnode = doc.CreateElement(ComponentType.SQLServer.ToString(), null);
XmlNode IndesignNode = doc.CreateElement(ComponentType.IndesignServer.ToString(), null);
XmlNode FSNode = doc.CreateElement(ComponentType.FS.ToString(), null);
node.AppendChild(SQLnode);
node.AppendChild(IndesignNode);
node.AppendChild(FSNode);
doc.AppendChild(node);
doc.Save(filePath);

filepath is a string contains the full path of the xml file including filename and extension. We use XmlDocument to read the file first, then format it. It would obviously get only 1 node which we created earlier named "ComponentLog". Then we have added 2 attributes with this parent node. Next with this parent ode "ComponentLog" we have added 3 child nodes. We are storing 3 types of log information in the xml file. They are: SQL, Indesign, and FileSystem. That completed our formatting with the xml file.

3. Write log data into xml file:

public static void WriteXmlLog(ComponentType CType, int CStatus, string userId, string userName, string email, DateTime lastMailSent,string culturecode)
{
try
{
if (!File.Exists(filePath))
{
CreateXmlFile();
}

XmlDocument doc = new XmlDocument();

doc.Load(filePath);
XmlNodeList baseNodes = doc.GetElementsByTagName(CType.ToString());

XmlNode node = doc.CreateNode(XmlNodeType.Element, CType.ToString() + "Log", null);

XmlNode UserId = doc.CreateElement("UserId");
UserId.InnerText = userId;

XmlNode UserName = doc.CreateElement("UserName");
UserName.InnerText = userName;

XmlNode Email = doc.CreateElement("Email");
Email.InnerText = email;

XmlNode LastMailSent = doc.CreateElement("LastMailSent");
LastMailSent.InnerText = lastMailSent.ToString();

XmlNode ComponentStatus = doc.CreateElement("ComponentStatus");
ComponentStatus.InnerText = CStatus.ToString();

XmlNode Culturecode = doc.CreateElement("culturecode");
Culturecode.InnerText = culturecode;

// add children to father
node.AppendChild(UserId);
node.AppendChild(UserName);
node.AppendChild(Email);
node.AppendChild(LastMailSent);
node.AppendChild(ComponentStatus);
node.AppendChild(Culturecode);

// append the new node
baseNodes[0].AppendChild(node);

// save the file
doc.Save(filePath);
}
catch (Exception ex)
{

}
}

First, we check whether a file already exists in that path or not. If not, then we create a new one. Then, we get the node that defines type of our log. CType is the enum that defines the type of log data we will write (FS, Indesign, or SQL).
XmlNodeList baseNodes = doc.GetElementsByTagName(CType.ToString()); returns nodes that have same tagname. baseNodes[0] (Lets call this as the "typeRoot" node) will return the topmost node of that type, which is added with the parent node "ComponentLog". with the typeRoot node, we want to add log data. So basically, we have created a node named "node", created respective nodes to store info such as userId, userName, email, lastMailSent, culturecode. Then we have added this info nodes under the newly created node "node", then added "node" under the "typeRoot" node. Under the 'typeRoot" node there will be multiple entries of "node". Their tag name is same to their "typeRoot" node, just the extra "log" string is added to the end of their name. Then we save (overwrite) the existing doc file. The xml file looks like this (using IE):


4. Read from xml file:

public static DataTable ReadXML(ComponentType ctype)
{
DataSet ds = new DataSet();
DataTable dt = new DataTable();
try
{
ds.ReadXml(filePath);
if (ds != null)
{
if (ctype.ToString() == ComponentType.SQLServer.ToString())
{
dt = ds.Tables[ComponentType.SQLServer.ToString() + "Log"];
}
else if (ctype.ToString() == ComponentType.IndesignServer.ToString())
{
dt = ds.Tables[ComponentType.IndesignServer.ToString() + "Log"];
}
else if (ctype.ToString() == ComponentType.FS.ToString())
{
dt = ds.Tables[ComponentType.FS.ToString() + "Log"];
}
}
}
catch
{
dt = null;
}
return dt;
}

DataSet.ReadXml("FilePath") directly reads the whole xml file in form of a dataset. Then, from the dataset we get our desired type of node collection if form of table. All the info node automatically created a column and their values created rows of the table. Thats how we read info from xml file.