AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Scripting (https://forums.alliedmods.net/forumdisplay.php?f=107)
-   -   Parsing KeyValue File (https://forums.alliedmods.net/showthread.php?t=140361)

CrimsonGT 10-11-2010 08:10

Parsing KeyValue File
 
Is there any way to properly parse a key value structure such as the following? The amount of Key/Value lines per section will be varying, so I cannot simply call GetValueString() a set number of times. I cannot find anyway to loop through as it doesn't seem I can iterate over each key/value line. I have also tried just turning the values into sub-sections and reading them that way, but I would like to avoid forcing the user to place {} after every line. I would also like to avoid having to write an XML extension if possible.

In this case, the 'key' is irrelevant. I simply need to get the values, but to do so I must be able to iterate over each line in some manner.

Code:

"ROOT"
{
    "SECTION1"
    {
        "1"            "value1"
        "2"            "value2"
        "3"            "value3"
    }
    "SECTION2"
    {
        "1"            "value1"
        "2"            "value2"
        "3"            "value3"
    }
    "SECTION3"
    {
        "1"            "value1"
        "2"            "value2"
        "3"            "value3"
    }
}


Monkeys 10-11-2010 10:10

Re: Parsing KeyValue File
 
You coud use default properties for finding out if the value existed or not?

PHP Code:

new SectionC 1KeyC 1;
decl String:SectionBuffer[32], String:KeyBuffer[32];
new 
String:Output[32];

Format(SectionBuffersizeof(SectionBuffer), "Section%d"SectionC);
StringToInt(KeyCKeyBuffersizeof(KeyBuffer));

while(
KvJumpToKey(KeyValueHandleSectionBufferfalse))
{
    
KvGetString(KeyValueHandleKeyBufferOutputsizeof(Output), "N/A");
    while(!
StrEqual(Output"N/A"))
    {
        
/*
        Do what you need to do with the Output
        */
        
        
KeyC++;
        
StringToInt(KeyCKeyBuffersizeof(KeyBuffer));
        
KvGetString(KeyValueHandleKeyBufferOutputsizeof(Output), "N/A");
    }
    
KvGoBack(KeyValueHandle);
    
SectionC++;
    
Format(SectionBuffersizeof(SectionBuffer), "Section%d"SectionC);


^ Something like that should work if your names are all uniform.
But if they're not, you'll need to use http://wiki.alliedmods.net/KeyValues...erative_Lookup
(Unless that's what you tried already, ofcourse)

CrimsonGT 10-11-2010 13:25

Re: Parsing KeyValue File
 
I thought that was going to work, but ran into the same issue since the Section names are not uniform. Before posting I was looking at doing while(KvGetString()) but that didn't return a value. The KvJumpToKey() looked like a solid approach, but since my Section names aren't (and can't be) uniform, that won't work either.

The actual file looks like this...

Code:

"MapGroups"
{
    "Capture the Flag (CTF)"
    {
        "1"            "ctf_2fort"
        "2"            "ctf_doublecross"
        "3"            "ctf_sawmill"
    }
    "Control Point (CP)"
    {
        "1"            "cp_badlands"
        "2"            "cp_dustbowl"
        "3"            "cp_granary"
    }
    "Arena"
    {
        "1"            "arena_badlands"
        "2"            "arena_granary"
        "3"            "arena_lumberyard"
    }
    "Payload"
    {
        "1"            "pl_badwater"
        "2"            "pl_goldrush"
        "3"            "pl_hoodoo_final"
    }
    "King of the Hill (KoTH)"
    {
        "1"            "koth_nucleus"
        "2"            "koth_sawmill"
        "3"            "koth_viaduct"
    }
    "Territory Control (TC)"
    {
        "1"            "tc_hydro"
    }
}

Iterative lookup won't work either since since I don't know what the user may change the section names to. The section names are used as menu categories, and the key/value pairs are options. If I can't think of a better way to do this, I might just have to make the Section names uniform, make the first key/value pair of each section the menu title, and go from there.

CrimsonGT 10-11-2010 13:37

Re: Parsing KeyValue File
 
Actually, after thinking about it a bit more, I figured out another way to do it. I figured I would post it incase someone stumbles across this in the future and needs to do the same thing. It is not exactly optimal, but I rarely call this function so it isn't an issue.

I am still having a problem where it doesn't iterate the sections properly. It handles the first Section, gets all of the key/value pairs, then just ends. I am still trying to hunt that issue down, so don't use the code directly.

PHP Code:

    if(KvGotoFirstSubKey(kv))
    {
        
decl String:szGroupName[255], String:szMapName[64];

        do
        {
            
KvGetSectionName(kvszGroupNamesizeof(szGroupName)); //Capture the Flag (CTF)
            
PushArrayString(g_MapGroupListszGroupName);
            
PrintToServer("GroupName: %s"szGroupName);

            new 
iMapIndex 1;
            
decl String:szIndexBuffer[3];

            do
            {
                
Format(szIndexBuffersizeof(szIndexBuffer), "%d"iMapIndex);
                
KvGetString(kvszIndexBufferszMapNamesizeof(szMapName), "none");

                if(!
StrEqual(szMapName"none"))
                {
                    
PushArrayString(g_MapGroupFileszMapName);
                    
PrintToServer("KeyName: %s MapName: %s"szIndexBufferszMapName);
                    
iMapIndex++;
                }
            }
            while (!
StrEqual(szMapName"none"false));

            
KvGoBack(kv);
        }
        while (
KvGotoNextKey(kv));
    } 


psychonic 10-11-2010 13:41

Re: Parsing KeyValue File
 
Why not just use the SMC parser? It already reads iteratively and tells you all the section names and key names as it reads them rather than you having to know them.

Monkeys 10-11-2010 13:42

Re: Parsing KeyValue File
 
Oh, my bad. I linked to the wrong section.
Fully traversal should cover it all.
But you're best of using a hybrid suited for your ends.

Here's how I would do it (not garanteed to be the most efficient, but it should work, I guess) with a file like yours:

PHP Code:

new KeyC 1;
decl String:KeyBuffer[12];
new 
String:Output[32];

if(
KvGoToFirstSubKey(KeyValueHandle))
{
    do
    {
        
StringToInt(KeyCKeyBuffersizeof(KeyBuffer));
        
KvGetString(KeyValueHandleKeyBufferOutputsizeof(Output), "N/A");
        while(!
StrEqual(Output"N/A"))
        {
            
/*
            Do what you need to do with the Output
            */
            
            
KeyC++;
            
StringToInt(KeyCKeyBuffersizeof(KeyBuffer));
            
KvGetString(KeyValueHandleKeyBufferOutputsizeof(Output), "N/A");
        }
    }while(
KvGoToNextKey(KeyValueHandle));


Edit: I got ninja'd...


Edit2: But aha! I know how to fix your issue, I believe :p
Remove the KvGoBack(kv);
I do believe KvGoToNextKey already covers that.

CrimsonGT 10-11-2010 13:46

Re: Parsing KeyValue File
 
Quote:

Originally Posted by psychonic (Post 1322260)
Why not just use the SMC parser? It already reads iteratively and tells you all the section names and key names as it reads them rather than you having to know them.

Because since I had used KV files 100 times in the past (although it was quite a while ago) and I have never touched SMC, I figured I would just get in and get it done quick. Little did I remember the limitations that came along with KV files.

*Edit*

Okay, To be honest, I forgot about the SMC parser as well.

psychonic 10-11-2010 13:48

Re: Parsing KeyValue File
 
Quote:

Originally Posted by CrimsonGT (Post 1322271)
Because since I had used KV files 100 times in the past (although it was quite a while ago) and I have never touched SMC, I figured I would just get in and get it done quick. Little did I remember the limitations that came along with KV files.

YMMV, but I find it much easier to use/understand than the KV system, especially if you're just reading it all-at-once into memory anyway.

rhelgeby 10-12-2010 11:53

Re: Parsing KeyValue File
 
Does the SMC parser catch syntax errors like missing quotes or braces? That would really help, because Valve's parser just crash the server in some cases. :P


All times are GMT -4. The time now is 05:27.

Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.