Click here to Skip to main content
15,889,281 members
Articles / Programming Languages / C#
Article

KeyValues

Rate me:
Please Sign up or sign in to vote.
3.00/5 (2 votes)
7 Apr 2009CPOL3 min read 23.7K   387   8   4
Powerfull XML Alternative

Introduction

This library is inspired on "Source Engine" (HL2SDK) KeyValues Class
http://developer.valvesoftware.com/wiki/KeyValues_class (SourceSDK KeyValues Class)
It was used to save data and for send data to a entity.
It can have unlimited keys and subkeys inside a KeyValue
SourceSDK KeyValues metods: View [^]
Diferences:

   More Metods
   More easy to loop all keys
   Easy to update or add features

I decide make this library because i need something like that but XML was hard to me read in C#.
So i have make as alternative to XML, this is a easy to use library and very powerfull.
This also can be used as small databases, i have used KeyValues in "Counter-Strike Source" in my zombie mod to save each player status such:
damage taken, damage given, bullets spent, kills, deaths, name, steamid, and many others.

KeyValues Explorer:

This is a simple Application i do for explore, manage keyvalues, this also can generate source code for you use in your application.

kvExplorer.png (109 KB)
Screenshot of KeyValues Explorer App

Background 

This is my first project realease on CodeProject, so i wait people helpme improve article information and makeit clean and nice.
That class contain very metods and usefull things, fell free to explore it.

How its KeyValues file struct in disk?

"KeyValue Name"<br />
{<br />
    "key" "value"<br />
    "other key" "other Value"<br />
    "many other key" "value to key :P"<br />
    // A comment to next SubKey or KeyValue ...<br />
    "an subkey name"<br />
    {<br />
        "key" "value"<br />
        "my key" "my value"<br />
        "2key" "2value"<br />
        NoSpaceKey WithoutQuotes<br />
        UsingNoQuotes ASpaceWillDetermineNextValue<br />
        // Lets load this file and addit as subkey to that KV<br />
        #include "C:\test_include.txt"<br />
        "Look An Other SubKey"<br />
        {<br />
            "my parent was" "an subkey name"<br />
        }<br />
    }<br />
}<br />

Help wanted

My english is not very good, so if any one wants help, can fix some english in my class and fix XML documentation for each metod, and create summary for missing metods.
Thanks if you can help

Using the Code

A brief description of how to use the article or code. The class names, the methods and properties, any tricks or tips.

Creating a simple KeyValue, and save it to disk:

C#
// Creating KeyValue
KeyValues kv = new KeyValues("namespace");
kv.Comment = "Testing comments (Optional)";
kv.SetString("my_dinner", "chiken");

// Get my dinner and print to console
Console.WriteLine("My Dinner Was: {0}", kv.GetValue("my_dinner"));

// Now lets create a sub key for our KeyValue
// And lets use constructor to SetString, same as: subKV.SetString("best", "CodeProject.com");
KeyValues subKV = new KeyValues("my_friends", "best", "CodeProject.com", null);
kv.AddSubKey(subKV); // Add subkv to main KeyValue
// Now lets save our class to Disk
kv.SaveToFile(@"C:\kv_test.txt");

Load last KeyValue from Disk and read thier values:

C#
if (!kv.LoadFromFile(@"C:\kv_test.txt")) return; // Fail on load
// retriving subkv
KeyValues subkv = kv.FindKey("my_friends");
if (subkv == null) return; // Subkey not exists!

// Print Data
Console.WriteLine("My Dinner Was: {0} And my best friend is: {1}", kv.GetValue("my_dinner"), subkv.GetValue("best"));

// Set an extra value to know last time KV was been loaded
kv.SetDateTime("lastLoadedTime", DateTime.Now);

Loop all Key, Values and SubKeys:

C#
// Metod 1, use While
void foreachKVMetod1(KeyValues kv)
{
    KeyValues fkv;
    KeyValuesData kvData;
    // Loop all Keys and Values
    while ((kvData = kv.GetNextKeyValue()) != null)
    {
        if (!string.IsNullOrEmpty(kvData.Comment)) // Print comment if not null
            Console.WriteLine("// {0}", kvData.Comment);
        Console.WriteLine("[{0}] = {1}", kvData.Key, kvData.Value);
    }
    // Loop all SubKeys
    while ((fkv = kv.GetNextSubKey()) != null)
    {
        if (!string.IsNullOrEmpty(fkv.Comment)) // Print comment if not null
            Console.WriteLine("// {0}", fkv.Comment);
        Console.WriteLine("\"{0}\"", fkv.Name);
        Console.WriteLine("{");
        foreachKVMetod1(fkv); // Continue foreach all subkeys inside
    }
    Console.WriteLine("}");
}

// Metod 2, use for
void foreachKVMetod2(KeyValues kv)
{
    for (int i = 0; i < kv.KeyNameValues.Count; i++)
    {
        if (!string.IsNullOrEmpty(kv.KeyNameValues[i].Comment)) // Print comment if not null
            Console.WriteLine("// {0}", kv.KeyNameValues[i].Comment);
        Console.WriteLine("[{0}] = {1}", kv.KeyNameValues[i].Key, kv.KeyNameValues[i].Value);
    }
    // Loop all SubKeys
    for (int i = 0; i < kv.KeyChilds.Count; i++)
    {
        if (!string.IsNullOrEmpty(kv.KeyChilds[i].Comment)) // Print comment if not null
            Console.WriteLine("// {0}", kv.KeyChilds[i].Comment);
        Console.WriteLine("\"{0}\"", kv.KeyChilds[i].Name);
        Console.WriteLine("{");
        foreachKVMetod1(kv.KeyChilds[i]); // Continue foreach all subkeys inside
    }
    Console.WriteLine("}");
}

foreachKVMetod1(kv);
foreachKVMetod2(kv);

Variable or class names should be wrapped in <code> tags like this.

Points of Interest

Math Operators in KeyValues:

kv += kv1 This will AddSubKey kv1 to Main kv
kv -= kv1 This will RemoveSubKey kv1 from Main kv
kv += "string" This will AddSubKey string_name to Main kv
kv -= "string" This will RemoveSubKey string_name from Main kv
kv += KeyValuesData This will Set KeyValuesData key and value to Main kv
kv -= KeyValuesData This will Remove KeyValuesData key and value from Main kv

Inside a file for load using KeyValues library you can include other keyvalues files:

"Root"<br />
{<br />
    // Lets load a SubKv into "Root" KeyValue<br />
    #include "C:/filename.txt"<br /><br />
    "me"		"you :P"<br />
    "bool test"		"True"<br />
    "byte test"		"1"<br />
    "char test"		"A"<br />
    "decimal test"		"10,1"<br />
    "double test"		"10,1"<br />
    "float test"		"10,1"<br />
    "short test"		"5000"<br />
    "int test"		"500000000"<br />
    "long test"		"5000000000000000000"<br />
    "date test"		"25-03-2009 1:16:31"<br />
}

History

v1.0.0.0:

First Realease 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Portugal Portugal
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionLoading this as an Assembly in 3ds Max Pin
Shawn Olson22-Jan-13 7:51
Shawn Olson22-Jan-13 7:51 
AnswerRe: Loading this as an Assembly in 3ds Max Pin
Shawn Olson22-Jan-13 9:51
Shawn Olson22-Jan-13 9:51 
Generalgood first article Pin
Donsw12-May-09 4:39
Donsw12-May-09 4:39 
GeneralCongrats Pin
Neville Franks7-Apr-09 19:39
Neville Franks7-Apr-09 19:39 
Congratulations on your first article here at CP. Another option to consider for i/o of key value pairs is JSON - see http://www.json.org/[^] JSON handles objects and arrays and typed values. It is widely used and becoming more so by the day.

There are articles here on CP about JSON and various C and C++ JSON parsers available including YAJL http://lloydforge.org/projects/yajl/[^] which I contributed a C++ wrapper to.

Neville Franks, Author of Surfulater www.surfulater.com "Save what you Surf" and ED for Windows www.getsoft.com


General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.