PDA

View Full Version : [Tutorial] XML functions


Boylett
03-31-2009, 04:24 PM
XML functions
This tutorial will explain how to use the XML functions in VCO

If you need it, the XML functions are on the wiki here: http://wiki.gtagaming.com/XML_Functions

Now, lets get started. First things first, due to some bugs in the current XML system, you will have to put these new functions in your gamemode to help stop XML functions crashing your server.

http://vco.pastebin.com/f6f0fb475
-- Checks if a file exists, returns true if it does (and is readable), false otherwise
function fileExists(fileName)
local file = io.open(fileName,"r")
if file == nil then return false end
file:close(file)
return true
end

-- Creates a file and puts a root node in it
-- Returns true on success, false otherwise
function createXMLFile(fileName,rootNodeName)
if fileExists(fileName) then return false end
local file = io.open(fileName,"w")
if file == nil then return false end
file:write("<" .. rootNodeName .. ">\n</" .. rootNodeName .. ">")
file:close(file)
return true
end

-- Opens an XML file without crashing (returns nil if it doesn't exist)
function openXMLFile(fileName)
if fileExists(fileName) then
return XML.loadFile(fileName)
end
return nil
end

Incase you're interested, these functions workaround bugs in the functions XML.createFile(), XML.loadFile() and XML.fileExists(). loadFile() will crash if you try to open a non existant file, createFile() just doesn't work at all and fileExists() always returns true.

Now you have those functions, lets begin!

XML structure
XML files follow a structure similar to this:

<rootNode>
<someNode />
<anotherNode>Value here</anotherNode>
<fooNode attribute="something" blah=1.2 />
<baaNode hello=5>I love XML me!</baaNode>
<moreNodes>
<subNode />
</modeNodes>
</rootNode>

OK! So, each node is the bit in the <> characters, i.e. <thisBit>
Each node can have attributes, a value and sub nodes

If a node doesn't have a value, it doesnt have a closing node, instead, it closes itself, i.e. <node />
If it has a value, if uses a closing node, i.e. <node>with a value</node>

Attributes appear after the node names, as name=value, where value can be a string, number or float, e.g.:
mystring="hello"
mynum=5
myfloat=7.2

Sub nodes just go in their parents node space where the value goes, i.e.:
<node>
<subNode />
</node>

The parent nodes can still contain values, e.g.:
<node>Value here
<subNode />
</node>

Creating XML files
To create an XML file, you must use the function: createXMLFile() (note how it ISN'T prefixed with "XML." because it is a custom function)

It takes 2 arguments: file name and root node

Example:
if createXMLFile("files/text.xml","vco") then
outputConsole("XML file created successfully!")
else
outputConsole("XML file couldn't be created")
end

The function will typically fail if the file already exists, or it's directory isn't writeable

Modifying XML files
All the default functions work for this, so you can check the wiki if you need to.

Here is an example (with explanation)
-- This first step opens the XML file (check above for openXMLFile's parameters)
local rootNode = openXMLFile("files/test.xml")
if rootNode == nil then
outputConsole("File didn't open")
else
-- XML.getNodeTitle gets the title of the node (in this case rootNode), if you used the create code above, it should be "vco"
outputConsole("Loaded root node: " .. XML.getNodeTitle(rootNode))

-- Create a new node (this will go between the <vco></vco> tags (vco is our rootNode))
local testNode = XML.createNode(rootNode,"test")

-- Set the nodes value (this is the value between the tags, i.e. <tag>in here</tag>)
XML.setNodeValue(testNode,"Hello world")

-- Add a string attribute (attributes are like "extra" values you can have in a node)
-- This is an attribute: <tag attribute="value"></tag>
-- Attributes can hold strings, numbers and floats, just like normal values
XML.setNodeStringAttribute(testNode,"hello","world")

-- Add an integer attribute
XML.setNodeIntegerAttribute(testNode,"number",9)

-- Add a float attribute
XML.setNodeFloatAttribute(testNode,"floathere",1.2)

-- Ok, we're done, now we save the file
XML.saveFile(rootNode)
-- ALWAYS us the root node (what openXMLFile returned)
end

Reading XML files
Well, just read the comments in the code again:

local rootNode = openXMLFile("files/test.xml")
if rootNode == nil then
outputConsole("File didn't open")
else
outputConsole("Loaded root node: " .. XML.getNodeTitle(rootNode))

-- This opens the node we want to read
local testNode = XML.getNode(rootNode,"test")

-- XML.getNode returns nil if the node doesn't exist
if testNode == nil then
outputConsole("Test node doesn't exists")
else
-- Get the nodes value, i.e. <foo>The value here</foo>
outputConsole("Test node value: " .. XML.getNodeValue(testNode))

-- Get the nodes attributes, i.e <foo attribute="the value here"></foo>
outputConsole("Test node attribute 'hello': " .. XML.getNodeAttribute(testNode,"hello"))
outputConsole("Test node attribute 'number': " .. XML.getNodeAttribute(testNode,"number"))
outputConsole("Test node attribute 'floathere': " .. XML.getNodeAttribute(testNode,"floathere"))

-- XML.getNodeAttribute returns nil if the attribute doesn't exist
-- e.g. XML.getNodeAttribute(testNode,"nonexistantattribute") == nil
end
end

If you ran that code after running the code in the "Modifying XML files" and "Creating XML files" section, your server should output this:
[Mar-31-09 22:14:39] [CONSOLE] Loaded root node: vco
[Mar-31-09 22:14:39] [CONSOLE] Test node value: Hello world
[Mar-31-09 22:14:39] [CONSOLE] Test node attribute 'hello': value
[Mar-31-09 22:14:39] [CONSOLE] Test node attribute 'number': 9
[Mar-31-09 22:14:39] [CONSOLE] Test node attribute 'floathere': 1.2

Toiletduck
04-01-2009, 02:37 PM
Wow. This will be seriously helpful!
Thanks on behalf of many people I am sure.

Ettans
04-01-2009, 11:43 PM
Thanks a lot boylett, great job! ;)