Monday, January 5, 2009

Xmlawy - XML Framework-C# freindly





Introduction



This framework provides an easy way to access XML files with support for inserting,
updating, deleting, and selecting by querying the XML like querying SQL.



Using the code



I'll start by writing simple lines of code that demonstrate the operations of inserting,
updating, deleting, and selecting, and then show the results in an XML file.



Here is how we create an XML file and access an object:


static void Main(string[] args)
{
BaseDataAccess access =
new BaseDataAccess("D:/xmltest.xml", "Objects");
}


Simple inserting



The Insert method takes an object of type BaseDataObject
as a parameter, which contains the name of the node, the value, the attributes,
and a list of children which are of the same type as well.


access.Insert(new BaseDataObject("type", "human")).Execute();
access.Insert(new BaseDataObject("type", "animal")).Execute();


2.png



Simple selecting



You can query the XML to select specific nodes:


List<BaseDataObject> dataList = access.Select("type").
Where("type").
IsEqualTo("animal").
ExecuteSelect<BaseDataObject>();

for (int i = 0; i < dataList.Count; i++)
{
Console.WriteLine(dataList[i].Name + " : " + dataList[i].Value);
}


3.png



Updating



It is also easy to update specific nodes:


access.Update("type").Set("type").EqualTo("animal").
Where("type").IsEqualTo("human").Execute();


4.png



Deleting



And here is how we delete:


access.Delete("type").Where("type").IsEqualTo("animal").Execute();


6.png



Advanced inserting



The way to insert children of children is to make a list of BaseDataObjects
and insert them in the list of the children of another BaseDataObject.
(The best way to do this is recursively.) The following code inserts three levels
of children in depth:


static void Main(string[] args)
{
// ACCESS
BaseDataAccess access =
new BaseDataAccess("test.xml", "objects");

// INSERTING 3 LEVELS IN DEPTH
List<BaseDataObject> parents = new List<BaseDataObject>();
for (int i = 0; i < 5; i++)
{
parents.Add(new BaseDataObject("Parent", MakeChilds(5)));
}
BaseDataObject parentOfParents =
new BaseDataObject("GrandParent", parents);
access.Insert(parentOfParents).Execute();

Console.WriteLine(access.XmlString);

Console.ReadLine();
}

private static List<BaseDataObject> MakeChilds(int count)
{
List<BaseDataObject> childs = new List<BaseDataObject>();
for (int i = 0; i < count; i++)
{
childs.Add(new BaseDataObject("N" + i.ToString(),
"V " + i.ToString()));
}
return childs;
}


7.png



Advanced selecting



Here is how we select any child in the selected objects, recursively, with the method
PrintObject(obj):


static void Main(string[] args)
{
// ACCESS
BaseDataAccess access = new BaseDataAccess("test.xml", "objects");

// INSERTING 3 LEVELS IN DEPTH
List<BaseDataObject> parents = new List<BaseDataObject>();
for (int i = 0; i < 5; i++)
{
parents.Add(new BaseDataObject("Parent", MakeChilds(5)));
}
BaseDataObject parentOfParents = new BaseDataObject("GrandParent", parents);
access.Insert(parentOfParents).Execute();

// SELECTING
List<BaseDataObject> objects =
access.Select("GrandParent").ExecuteSelect<BaseDataObject>();
for (int i = 0; i < objects.Count; i++)
{
PrintObject(objects[i]);
}

Console.ReadLine();
}

private static List<BaseDataObject> MakeChilds(int count)
{
List<BaseDataObject> childs = new List<BaseDataObject>();
for (int i = 0; i < count; i++)
{
childs.Add(new BaseDataObject("N" + i.ToString(),
" V" + i.ToString() + " "));
}
return childs;
}

private static void PrintObject(BaseDataObject obj)
{
if (obj.Childs.Count > 0)
{
Console.WriteLine(obj.Name + " >");
for (int i = 0; i < obj.Childs.Count; i++)
{
PrintObject(obj.Childs[i]);
}
}
else
{
Console.WriteLine(obj.Name + " : " + obj.Value);
}
}


8.png



Inserting simple objects



If you want to quickly save the properties of an object in XML (simple serialization),
there is another generic Insert method which takes any object as a
parameter and inserts all the properties of type string or
int in the XML file.


class MyClass
{
public MyClass()
{
Age = 20;
FirstName = "Islam";
LastName = "Eldemery";
Address = "Egypt, Cairo, bla bla bla";
}

public int Age { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }

}

class Program
{
static void Main(string[] args)
{
MyClass obj = new MyClass();

// ACCESS
BaseDataAccess access = new BaseDataAccess("test.xml", "objects");

// INSERT
access.Insert<MyClass>(obj).Execute();

Console.WriteLine(access.XmlString);

Console.ReadLine();
}
}


9.png



So far so good, let's dig deeper..



Overriding the virtual methods in the base class



Imagine you want to encrypt the XML after inserting, and decrypt it before selecting.
This can be easily done by overriding the base methods as follows:


class XmlAccess : BaseDataAccess
{
XMLEncryptor encryptor;

public XmlAccess(string path, string rootElement)
: base(path, rootElement)
{
encryptor = new XMLEncryptor(path);
}

public override bool Execute()
{
bool executed = base.Execute();

///////////////////////////////////////////////////
// ENCRYPTOR GOES HERE
encryptor.Encrypt(base._objectToInsert.Name, "myKey");
///////////////////////////////////////////////////

return executed;
}

public override List<T> ExecuteSelect<T>()
{
///////////////////////////////////////////////////
// ENCRYPTOR GOES HERE
encryptor.Decrypt("myKey");
///////////////////////////////////////////////////

return base.ExecuteSelect<T>();
}
}


Select From




// ACCESS
// True will delete the file if exist (for debugging purposes)
BaseDataAccess access = new BaseDataAccess(@"test4.xml", "doc", true);

// Initialize 6 childs
List<BaseDataObject> childs = new List<BaseDataObject>();
for (int i = 0; i < 6; i++)
{
childs.Add(new BaseDataObject("Name" + i.ToString(), "Value" + i.ToString()));
}

// Insert
access.Insert(new BaseDataObject("Human", childs)).Execute();
access.Insert(new BaseDataObject("Animal", childs)).Execute();

// Select
List<BaseDataObject> selected = access.Select("Human").Where("Name2").IsEqualTo("Value2").ExecuteSelect<BaseDataObject>();
// (Prints 1)
Console.WriteLine(selected.Count);
// selected[0] is the Human osbject and holds 6 childs objects

// Select
List<BaseDataObject> selectedN = access.Select("Name2").From("Human").Where("Name3").IsEqualTo("Value3").ExecuteSelect<BaseDataObject>();
// (Prints 1)
Console.WriteLine(selectedN.Count);
// selected[0] is the child osbject


Select all nodes



You can also select all the nodes in the root node with all children and children
of children, in one line of code:


List<BaseDataObject> objects = access.SelectAll<BaseDataObject>();


And again, this is to loop on them recursively:


static void Main(string[] args)
{
// ACCESS
BaseDataAccess access =
new BaseDataAccess(@"D:\XmlFiles\StructureMap.xml",
"doesntMatter");

// SELECTING
List<BaseDataObject> objects = access.SelectAll<BaseDataObject>();

// DISPLAYING
for (int i = 0; i < objects.Count; i++)
PrintObject(objects[i]);

Console.ReadLine();
}

private static void PrintObject(BaseDataObject obj)
{
if (obj.Childs.Count > 0)
{
Console.WriteLine(obj.Name + " >");

for (int i = 0; i < obj.Childs.Count; i++)
PrintObject(obj.Childs[i]);
}
else
Console.WriteLine(obj.Name + " : " + obj.Value);
}


History



The code in the library is fully commented. This is version 1. I hope we can add
more and more features in the future.



9 comments:

Anonymous said...

hi islam, can you please post a short example of how to encrpyt the data? great peace of code!

thanks

Islam Eldemery said...

Hi, I have already provided a sample code in the article to encrypt and decrypt the data.
(Notice that the class XMLEncryptor (which I found somewhere on the internet) is in the ConsoleTest project in the attached solution.

All you need to do is to derive from BaseDataAccess class and override the base methods which insert and select the data, encrypt the data after inserting and decrypt it before selecting, then always use your new class that is derived from BaseDataAccess class to insert and select, and it will encrypt and decrypt the data automatically.

Anonymous said...

Amazing piece of work, people like yourself help make c# a wonderful language to program in and what better method for XML than to use an SQL, well thought of, I look forward to implementing this in my work, Thank you.

Anonymous said...

Wow! what an idea ! What a concept ! Beautiful .. Amazing …

Anonymous said...

Well I assent to but I dream the collection should prepare more info then it has.

Anonymous said...

Good dispatch and this enter helped me alot in my college assignement. Thank you on your information.

Anonymous said...

I will not acquiesce in on it. I think nice post. Expressly the designation attracted me to read the whole story.

Anonymous said...

Your blog keeps getting better and better! Your older articles are not as good as newer ones you have a lot more creativity and originality now keep it up!

Anonymous said...

Amiable dispatch and this post helped me alot in my college assignement. Thanks you for your information.