Raised This Month: $51 Target: $400
 12% 

[EXTENSION] TinyXml Wrapper


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Thrawn2
Veteran Member
Join Date: Apr 2009
Old 07-28-2010 , 09:26   [EXTENSION] TinyXml Wrapper
Reply With Quote #1

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

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

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.
__________________
einmal mit profis arbeiten. einmal.

Last edited by Thrawn2; 02-17-2012 at 23:09. Reason: Added Linux binary; small text changes.
Thrawn2 is offline
Thrawn2
Veteran Member
Join Date: Apr 2009
Old 07-28-2010 , 09:26   Re: [EXTENSION] TinyXml Wrapper (alpha)
Reply With Quote #2

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");

__________________
einmal mit profis arbeiten. einmal.

Last edited by Thrawn2; 08-06-2010 at 17:09. Reason: Added missing CloseHandle() calls
Thrawn2 is offline
Thrawn2
Veteran Member
Join Date: Apr 2009
Old 07-31-2010 , 06:10   Re: [EXTENSION] TinyXml Wrapper (alpha)
Reply With Quote #3

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);

Attached Files
File Type: txt items_game.xml.txt (149.5 KB, 456 views)
__________________
einmal mit profis arbeiten. einmal.

Last edited by Thrawn2; 08-06-2010 at 17:04. Reason: CloseHandle() fixes
Thrawn2 is offline
Thrawn2
Veteran Member
Join Date: Apr 2009
Old 08-06-2010 , 12:01   Re: [EXTENSION] TinyXml Wrapper (alpha)
Reply With Quote #4

a linux binary is available now. (download)
__________________
einmal mit profis arbeiten. einmal.

Last edited by Thrawn2; 08-06-2010 at 16:27. Reason: lower case letters...
Thrawn2 is offline
Afronanny
Veteran Member
Join Date: Aug 2009
Old 08-06-2010 , 13:31   Re: [EXTENSION] TinyXml Wrapper (alpha)
Reply With Quote #5

Quote:
Originally Posted by [AAA] Thrawn View Post
a linux binary is available now. (download)
Are the bugs with the handles worked out yet?
Afronanny is offline
Thrawn2
Veteran Member
Join Date: Apr 2009
Old 08-06-2010 , 16:59   Re: [EXTENSION] TinyXml Wrapper (alpha)
Reply With Quote #6

Quote:
Originally Posted by Afronanny View Post
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.
__________________
einmal mit profis arbeiten. einmal.

Last edited by Thrawn2; 08-06-2010 at 17:10.
Thrawn2 is offline
TnTSCS
AlliedModders Donor
Join Date: Oct 2010
Location: Undisclosed...
Old 02-17-2012 , 21:32   Re: [EXTENSION] TinyXml Wrapper
Reply With Quote #7

says http://github.com/thraaawn/SMTinyXml/raw/master/bin/ is 404 not found
__________________
View my Plugins | Donate
TnTSCS is offline
Thrawn2
Veteran Member
Join Date: Apr 2009
Old 02-17-2012 , 23:10   Re: [EXTENSION] TinyXml Wrapper
Reply With Quote #8

thx. fixed.
__________________
einmal mit profis arbeiten. einmal.
Thrawn2 is offline
Blowst
Senior Member
Join Date: Feb 2011
Location: Korea, Republic of
Old 02-19-2012 , 10:25   Re: [EXTENSION] TinyXml Wrapper
Reply With Quote #9

When creates a XML file,

automatically saved with UTF-8 encode

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


Sorry for my badddddd English
__________________
Sorry about my poor English

Blowst is offline
Grognak
SourceMod Donor
Join Date: Jan 2012
Old 04-07-2012 , 20:13   Re: [EXTENSION] TinyXml Wrapper
Reply With Quote #10

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.

Last edited by Grognak; 04-07-2012 at 20:15. Reason: edited out client id
Grognak is offline
Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 19:04.


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