AlliedModders

AlliedModders (https://forums.alliedmods.net/index.php)
-   Extensions (https://forums.alliedmods.net/forumdisplay.php?f=134)
-   -   [EXTENSION] TinyXml Wrapper (https://forums.alliedmods.net/showthread.php?t=133735)

Thrawn2 07-28-2010 09:26

[EXTENSION] TinyXml Wrapper
 
This extension provides a basic interface to reading/writing XML files.

This is my first try at writing an extension.
Also today is the second day i've ever coded something in c++. Installed VisualStudio yesterday...
so please bear with me :crab:

I needed a fast way to parse and create xml files. I didnt want to do it with sourcepawn. And there are many good XML parser for c++ out there - no need to reinvent the wheel.
So i started wrapping TinyXml (Online Documentation).
I'm at the very beginning of this - still learning everything about c++.
But i'm at a point where this is usable - probably not the best idea to use this in a productive environment though :3

The resulting include file looks like this.


Binaries
Changelog
Sources

Everything wrong with my extension or things i can do better, please elaborate - i'm totally new at this.

Thrawn2 07-28-2010 09:26

Re: [EXTENSION] TinyXml Wrapper (alpha)
 
Some examples.

Creating a XML file
PHP Code:

#pragma semicolon 1
#include <sourcemod>
#include <tinyxml>

public OnPluginStart() {
    
CreateTestXML();
}

stock CreateTestXML() {
    
//Create XML Document
    
new Handle:hTxDoc TinyXml_CreateDocument();

    
//Create and add declaration
    
new Handle:hTxDecl TinyXml_CreateDeclaration("1.0","","");
    
TinyXml_LinkEndChild(hTxDochTxDecl);

    
//Create element with value "Hello"
    
new Handle:hTxEle TinyXml_CreateElement("Hello");

    
//Create comment and add it to the element
    
new Handle:hTxCmt TinyXml_CreateComment("This is a comment");
    
TinyXml_LinkEndChild(hTxElehTxCmt);

    
//Create element, give it some text and add it to the element
    
new Handle:hTxEleSub TinyXml_CreateElement("Sublevel");
    new 
Handle:hTxText TinyXml_CreateText("HEEEEEEEEELO WORLD");
    
TinyXml_LinkEndChild(hTxEleSubhTxText);
    
TinyXml_LinkEndChild(hTxElehTxEleSub);

    
//Add element to the document
    
TinyXml_LinkEndChild(hTxDochTxEle);

    
//Save the document to a file
    
TinyXml_SaveFile(hTxDoc"./helloworld.xml");

    
CloseHandle(hTxText);
    
CloseHandle(hTxEleSub);
    
CloseHandle(hTxCmt);
    
CloseHandle(hTxEle);
    
CloseHandle(hTxDecl);
    
CloseHandle(hTxDoc);


results in:
Code:

<?xml version="1.0" ?>
<Hello>
    <!--This is a comment-->
    <Sublevel>HEEEEEEEEELO WORLD</Sublevel>
</Hello>

Reading a RSS file
PHP Code:

#pragma semicolon 1
#include <sourcemod>
#include <tinyxml>

public OnPluginStart() {
    
ReadTestRSS();
}

stock ReadTestRSS() {
    
//Create new document and fill it from a file
    
new Handle:hDoc TinyXml_CreateDocument();
    
TinyXml_LoadFile(hDoc"./rss.xml");

    
//Get the <root> element
    
new Handle:hRoot TinyXml_RootElement(hDoc);

    
//Todo: check rss version and read the xml accordingly
    //    for this example we just do atom feeds (rss 2.0)

    //Get the <channel> element
    
new Handle:hChannel TinyXml_FirstChildElement(hRoot);

    
//Get the first child <item> element
    
new Handle:hNode TinyXml_FirstChildElement(hChannel"item");

    
//Iterate over each <item> element
    
while(hNode != INVALID_HANDLE) {
        
ExtractItem(hNode);
        
hNode TinyXml_NextSiblingElement(hNode"item");
    }

    
CloseHandle(hNode);
    
CloseHandle(hChannel);
    
CloseHandle(hRoot);
    
CloseHandle(hDoc);
}

stock ExtractItem(Handle:hItem) {
    new 
String:sBufferK[2048];
    new 
String:sBufferV[2048];

    new 
Handle:hNode TinyXml_FirstChildElement(hItem);

    while(
hNode != INVALID_HANDLE) {
        
TinyXml_Value(hNodesBufferKsizeof(sBufferK));

        if(
StrEqual(sBufferK,"title")) {
            
TinyXml_GetText(hNodesBufferVsizeof(sBufferV));
            
LogMessage("Title: %s (%i)"sBufferVTinyXml_Type(hNode));
        }

        if(
StrEqual(sBufferK,"description")) {
            
TinyXml_GetText(hNodesBufferVsizeof(sBufferV));
            
LogMessage("Desc: %s"sBufferV);
        }

        if(
StrEqual(sBufferK,"link")) {
            
TinyXml_GetText(hNodesBufferVsizeof(sBufferV));
            
LogMessage("Link: %s"sBufferV);
        }

        
hNode TinyXml_NextSiblingElement(hNode);
    }

    
CloseHandle(hNode);


Dumping a xml file recursively
PHP Code:

#pragma semicolon 1
#include <sourcemod>
#include <tinyxml>

public OnPluginStart() {
    new 
Handle:hTxDoc TinyXml_CreateDocument();
    
TinyXml_LoadFile(hTxDoc"./example4.xml");

    
RecursiveDump(hTxDoc);
    
CloseHandle(hTxDoc);
}

stock RecursiveDump(Handle:hNodelevel 0) {
    new 
String:padding[32];
    for(new 
0leveli++) {
        
StrCat(paddingsizeof(padding), "  ");
    }

    while(
hNode != INVALID_HANDLE) {
        new 
NodeType:iType NodeType:TinyXml_Type(hNode);
        new 
String:sType[16];
        
TypeToString(iTypesTypesizeof(sType));

        new 
String:sValue[64];

        if(
iType == TINYXML_ELEMENT) {
            
TinyXml_Value(hNodesValuesizeof(sValue));
            
LogMessage("%s%s: %s"paddingsTypesValue);
            
DumpAttributes(hNodelevel+1);
            new 
Handle:firstChild TinyXml_FirstChild(hNode);
            
RecursiveDump(firstChildlevel+1);
            
CloseHandle(firstChild);
        }

        if(
iType == TINYXML_TEXT) {
            
TinyXml_Value(hNodesValuesizeof(sValue));
            
LogMessage("%s%s: %s"paddingsTypesValue);
        }

        if(
iType == TINYXML_DOCUMENT) {
            new 
Handle:root TinyXml_RootElement(hNode);
            
RecursiveDump(root);
            
CloseHandle(root);
        }

        if(
iType == TINYXML_COMMENT) {
            
TinyXml_Value(hNodesValuesizeof(sValue));
            
LogMessage("%s%s: %s"paddingsTypesValue);
        }

        
hNode TinyXml_NextSibling(hNode);
    }

    
CloseHandle(hNode);
}

stock DumpAttributes(Handle:hElementlevel 0) {
    new 
String:padding[32];
    for(new 
0leveli++) {
        
StrCat(paddingsizeof(padding), "  ");
    }

    new 
Handle:hAttribute TinyXml_FirstAttribute(hElement);

    while(
hAttribute != INVALID_HANDLE) {
        new 
String:sName[64];
        new 
String:sValue[64];

        
TinyXml_AttributeName(hAttributesNamesizeof(sName));
        
TinyXml_AttributeValue(hAttributesValuesizeof(sValue));

        
LogMessage("%s%s: %s"paddingsNamesValue);

        
hAttribute TinyXml_NextAttribute(hAttribute);
    }

    
CloseHandle(hAttribute);
}

stock TypeToString(NodeType:iTypeString:buff[], sizebuff) {
    if(
iType == TINYXML_DOCUMENT)
        
strcopy(buff,sizebuff"Document");
    else if(
iType == TINYXML_ELEMENT)
        
strcopy(buff,sizebuff"Element");
    else if(
iType == TINYXML_COMMENT)
        
strcopy(buff,sizebuff"Comment");
    else if(
iType == TINYXML_UNKNOWN)
        
strcopy(buff,sizebuff"Unknown");
    else if(
iType == TINYXML_TEXT)
        
strcopy(buff,sizebuff"Text");
    else if(
iType == TINYXML_DECLARATION)
        
strcopy(buff,sizebuff"Declaration");
    else if(
iType == TINYXML_TYPECOUNT)
        
strcopy(buff,sizebuff"Typecount");



Thrawn2 07-31-2010 06:10

Re: [EXTENSION] TinyXml Wrapper (alpha)
 
1 Attachment(s)
Conversion between XML and KeyValues
  • xml to keyvalues: this does not always work satisfying. xml can and often has element with the same value at the same sublevel - take rss for example, it has a lot of <item> elements under <items>. But a keyvalues file doesnt allow twin elements, so your resulting keyvalues structure would only hold one of those items.
  • keyvalues to xml: this is mostly no problem at all, except for one case. XML elements cant be numeric-only, keyvalues nodes can. Take items_game.txt for example, it has a lot of numeric elements - those arent allowed in well-formed xml. It still works and the result is a 25kb smaller file and nothing gets left out, but it's not guaranteed your xml-parser will be happy with it (Internet Explorer isnt..., tinyxml itself doesnt care at all). Btw converting the items_games.txt (about the largest keyvalues structure i could find) to xml takes less than a second from within a sourcemod plugin.

Now some usage examples:
Reading admins.cfg. Saving as admins.xml
PHP Code:

#pragma semicolon 1
#include <sourcemod>
#include <tinyxml>

public OnMapStart() {
    new 
Handle:kv CreateKeyValues("");

    
decl String:path[256];
    
BuildPath(Path_SMpathsizeof(path), "configs/admins.cfg");
    
FileToKeyValues(kvpath);

    
decl String:out[256];
    
BuildPath(Path_SMoutsizeof(out), "configs/admins.xml");

    
//TODO: Fix path prefix in extension! Make it act like SM does.
    //this line will break this stock as soon as the above is fixed!
    
Format(outsizeof(out), "./tf/%s"out);

    
//Set the third parameter to true, if you want pairs be to be attributes
    //instead of elements.
    
KeyValuesToXML(kvoutfalse);
    
CloseHandle(kv);


Reading XML, saving as keyvalues
PHP Code:

#pragma semicolon 1
#include <sourcemod>
#include <tinyxml>

public OnMapStart() {
    new 
Handle:hTxDoc TinyXml_CreateDocument();
    
TinyXml_LoadFile(hTxDoc"./admins.xml");

    new 
Handle:kv;
    
RecursiveDump(hTxDockv);

    
decl String:path[256];
    
BuildPath(Path_SMpathsizeof(path), "configs/admins_fromxml.cfg");
    
KeyValuesToFile(kvpath);

    
CloseHandle(kv);
    
CloseHandle(hTxDoc);
}

stock RecursiveDump(Handle:hNode, &Handle:kv) {

    while(
hNode != INVALID_HANDLE) {
        new 
NodeType:iType NodeType:TinyXml_Type(hNode);

        new 
String:sValue[64];

        if(
iType == TINYXML_ELEMENT) {
            
TinyXml_Value(hNodesValuesizeof(sValue));
            
KvJumpToKey(kvsValuetrue);
            
DumpAttributes(hNodekv);

            new 
Handle:firstChild TinyXml_FirstChild(hNode);
            
RecursiveDump(firstChildkv);
            
CloseHandle(firstChild);
            
KvGoBack(kv);

            new 
String:sText[64];
            
TinyXml_GetText(hNodesTextsizeof(sText));
            
KvSetString(kvsValuesText);
        }

        if(
iType == TINYXML_DOCUMENT) {
            new 
Handle:root TinyXml_RootElement(hNode);
            
TinyXml_Value(rootsValuesizeof(sValue));
            
kv CreateKeyValues(sValue);
            
RecursiveDump(TinyXml_FirstChild(root), kv);
            
CloseHandle(root);
        }

        if(
iType == TINYXML_COMMENT) {
            
TinyXml_Value(hNodesValuesizeof(sValue));
            
//LogMessage("%s%s: %s", padding, sType, sValue);
        
}

        
hNode TinyXml_NextSibling(hNode);
    }

    
CloseHandle(hNode);
}

stock DumpAttributes(&Handle:hElement, &Handle:kv) {
    new 
Handle:hAttribute TinyXml_FirstAttribute(hElement);

    while(
hAttribute != INVALID_HANDLE) {
        new 
String:sName[64];
        new 
String:sValue[64];

        
TinyXml_AttributeName(hAttributesNamesizeof(sName));
        
TinyXml_AttributeValue(hAttributesValuesizeof(sValue));

        
KvSetString(kvsNamesValue);

        
hAttribute TinyXml_NextAttribute(hAttribute);
    }

    
CloseHandle(hAttribute);



Thrawn2 08-06-2010 12:01

Re: [EXTENSION] TinyXml Wrapper (alpha)
 
a linux binary is available now. (download)

Afronanny 08-06-2010 13:31

Re: [EXTENSION] TinyXml Wrapper (alpha)
 
Quote:

Originally Posted by [AAA] Thrawn (Post 1263344)
a linux binary is available now. (download)

Are the bugs with the handles worked out yet?

Thrawn2 08-06-2010 16:59

Re: [EXTENSION] TinyXml Wrapper (alpha)
 
Quote:

Originally Posted by Afronanny (Post 1263440)
Are the bugs with the handles worked out yet?

i think so. i ran 3000 items_game.txt to xml conversions and had an increased memory usage of ~4mb.

TnTSCS 02-17-2012 21:32

Re: [EXTENSION] TinyXml Wrapper
 
says http://github.com/thraaawn/SMTinyXml/raw/master/bin/ is 404 not found :(

Thrawn2 02-17-2012 23:10

Re: [EXTENSION] TinyXml Wrapper
 
thx. fixed.

Blowst 02-19-2012 10:25

Re: [EXTENSION] TinyXml Wrapper
 
When creates a XML file,

automatically saved with UTF-8 encode

how i change document's encoding (in plugin)?


Sorry for my badddddd English

Grognak 04-07-2012 20:13

Re: [EXTENSION] TinyXml Wrapper
 
Hi, is this still supported?

I have the following code below, to try to extract the value of a tag in an XML file.

Code:

stock String:GetTrackValue(String:tag[])
{
        new String:sBufferK[2048];
        new String:sBufferV[2048] = "0";
       
        new Handle:hDoc = TinyXml_CreateDocument();
        TinyXml_LoadFile(hDoc, "./tf/data.xml");

        new Handle:hRoot = TinyXml_RootElement(hDoc); // <tracks>

        if (_:hRoot == 0)
                return sBufferV;

        PrintToAll("hRoot Value: %i", _:hRoot); // debug
       
        new Handle:hTrack = TinyXml_FirstChildElement(hRoot); // <track>

        while (hTrack != INVALID_HANDLE)
        {
                TinyXml_Value(hTrack, sBufferK, sizeof(sBufferK));

                if(StrEqual(sBufferK, tag))
                {
                        TinyXml_GetText(hTrack, sBufferV, sizeof(sBufferV));
                        //return sBufferV;
                        break;
                }

                hTrack = TinyXml_NextSiblingElement(hTrack);       
        }

        return sBufferV;
}

I'm using this in tandem with the socket extension, which downloads the xml file in the first place. In notepad, the xml file appears like this:

Code:

<?xml version="1.0" encoding="UTF-8"?>
<tracks next-href="http://api.soundcloud.com/tracks.xml?client_id=x&amp;limit=1&amp;offset=1&amp;q=%27the+national+exile+vilify%27" type="array">
  <track>
    <id type="integer">18713529</id>
    <created-at type="datetime">2011-07-09T18:12:14Z</created-at>
    <user-id type="integer">5728473</user-id>
    <duration type="integer">285235</duration>
    <commentable type="boolean">true</commentable>
    <state>finished</state>
    <original-content-size type="integer">8138218</original-content-size>
    <sharing>public</sharing>
    <tag-list></tag-list>
    <permalink>the-national-exile-vilify</permalink>
    <description></description>
    <streamable type="boolean">true</streamable>
    <downloadable type="boolean">false</downloadable>
    <genre></genre>
    <release></release>
    <purchase-url nil="true"></purchase-url>
    <purchase-title nil="true"></purchase-title>
    <label-id nil="true"></label-id>
    <label-name></label-name>
    <isrc></isrc>
    <video-url nil="true"></video-url>
    <track-type></track-type>
    <key-signature></key-signature>
    <bpm nil="true"></bpm>
    <title>The National  - Exile Vilify</title>
    <release-year nil="true"></release-year>
    <release-month nil="true"></release-month>
    <release-day nil="true"></release-day>
    <original-format>mp3</original-format>
    <license>all-rights-reserved</license>
    <uri>http://api.soundcloud.com/tracks/18713529</uri>
    <permalink-url>http://soundcloud.com/ramseyyoyoyo/the-national-exile-vilify</permalink-url>
    <artwork-url nil="true"></artwork-url>
    <waveform-url>http://w1.sndcdn.com/GcLJpDDSZaTM_m.png</waveform-url>
    <user>
      <id type="integer">5728473</id>
      <permalink>ramseyyoyoyo</permalink>
      <username>Ramsey_</username>
      <uri>http://api.soundcloud.com/users/5728473</uri>
      <permalink-url>http://soundcloud.com/ramseyyoyoyo</permalink-url>
      <avatar-url>http://i1.sndcdn.com/avatars-000004545157-enjuak-large.jpg?b9f92e9</avatar-url>
    </user>
    <stream-url>http://api.soundcloud.com/tracks/18713529/stream</stream-url>
    <playback-count type="integer">1478</playback-count>
    <download-count type="integer">0</download-count>
    <favoritings-count type="integer">12</favoritings-count>
    <comment-count type="integer">1</comment-count>
    <attachments-uri>http://api.soundcloud.com/tracks/18713529/attachments</attachments-uri>
  </track>
</tracks>

Thank you.


All times are GMT -4. The time now is 16:07.

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