XML

by Deadron
Reads and writes XML files, letting you access the contents as an object tree.
ID:36895
 
(The library itself is available at this link: http://developer.byond.com/hub/Deadron/XML)

Deadron's XML Library for BYOND


A convenient library for parsing XML files or creating and manipulating XML on the fly.

Contents

Why XML?
     XML != web
     Document as a database
     Using XML in games
        Making your games data-driven
        Providing data to fans
     What about savefiles?
The Rules of XML
     The anatomy of an element
        Opening tag
        Closing tag
     Nested elements
     Root element
Getting Started
     Getting the root element
     Querying the tree
     Navigating the tree
        Children
        Descendants
        Parents and ancestors
Reference
     Functions
        xmlRootFromFile
        xmlRootFromPath
        xmlRootFromString
     Classes
        XML/Element
           Procs
              New
              AddChild
              AddSibling
              Attribute
              Attributes
              ChildElements
              Children
              Descendant
              Descendants
              DescendantsOrSelf
              FirstChild
              FirstChildElement
              FirstChildText
              Parent
              RemoveChild
              RemoveChildren
              setAttribute
              setAttributes
              setChild
              setChildren
              setTag
              setText
              setXML
              String
              Tag
              Text
              WriteToFile
              XML

Why XML?

XML is the simplest idea ever to change the world. It is one of the few cases in human history where a committee set out to do something, and to do it fast, and succeeded brilliantly. Not only that, this was a committee actually obsessed with keeping things as simple as possible. Unheard of!

Yet for all their success in creating XML, the committee also failed. Or at least failed their original vision, at this point in history anyway. They failed because they created XML to be the new format for web pages, something that could replace HTML. And yet XML has done everything but replace HTML. It has quickly become the interchange format of choice for software engineers. Preference files, data streams, billing records...almost any information read into a computer program is now being turned into XML.

This seems odd for an ASCII format that doesn't have the wizzy speed or compactness of binary data. Why not just leave everything binary? The answer is simple: Because engineers were spending large chunks of their lives creating and parsing and bug-fixing new data formats, and companies were spending big chunks of their money paying for it. Nearly every application or utility had to create its own data format from scratch at some point or another, and indeed might actually have many proprietary data formats for different parts of the program. Most likely no other program knew how to read those formats, and any program that did want to read another program's binary formats had to do a lot of custom coding. Worse yet, the formats were often not flexible enough to be automatically expanded; if you added a new type of data to the format, every application that needed to read the format now had to be upgraded in order to read the upgraded data files, or else they would simply error out when encountering a file with the new kind of data.

XML offers a way out of that morass of data formats.

XML != web

Many people confuse XML with the web, thinking the only reason to use it is for stylesheets or displaying web pages. But for our purposes, XML has nothing to do with the web! Get any such thoughts out of your head.

We're dealing with XML as a data format. A way to store and manipulate data for your games. For BYOND, XML is simply an alternative or a companion to savefiles, and no one would confuse a savefile with a web page.

Document as a database

The biggest benefit of XML is that it turns a document into a simple database you can query. In fact, for our purposes, it's probably best not to think in terms of documents, but to think of data files and databases. This is commonly referred to as the Document Object Model (DOM), which refers to turning the XML into an object tree that you can query and manipulate.

Using XML in games

The demo provided with the XML library shows multiple ways to use XML for your games, with complete code.

Making your games data-driven
When people love a game, they want to change the game. (Fortunately, this often works out better with games than it does with people.) For years now strategy games have defined their units and rules in external human-readable files, to allow players to add their own units or tweak the rules for the game. In the past, these data files have been custom formats, but in the future it's quite likely that data files like this will use XML as their format of choice.

The demo takes the approach of reading in all XML files found anywhere under the demo directory, and putting together the game based on what it finds. In this case, the units the player can choose are based on whatever "unit" elements are found in the XML. Even the unit's graphic is specified there. The XML for a typical unit looks like:

<unit>
        <name>Doggie</name>
        <damage>3</damage>
        <distance>5</distance>

        <description>Woof woof.</description>
        <image>demo/units/doggie.bmp</image>
</unit>
The player can add or change units however they like by manipulating the XML. The "Getting Started" section shows some ways to access the information in XML like this, and the "Reference" describes all the functions available. See the demo code for complete examples.

Providing data to fans
Breaking with the tight-lipped "we don't tell the players nothing about anything" tradition of MMORPGs, in which even basic data about how spells work is kept a "secret", Dark Age of Camelot takes an interesting approach to their game data: They publish it on their website in XML files, updated hourly. This includes full spell data (damage, duration, etc) and updates about what is happening in the game world, such as server status, which guild has taken over which keep, and what realm has stolen the stat-boosting relics. Information about this is available on the DAoC XML page.

This turns out to be a brilliant idea. With the information freely available, and in easily parsable XML, fan sites put together sophisticated websites, and even Java applications for putting together character templates. DAoC has found a way to strengthen their community ties by providing information, but if they'd just put it out in boring old unstructured HTML, nobody could have done much with it. By making it XML, they sparked a fan revolution.

A typical DAoC spell looks like this:

<spell name="Minor Shield of Magma"
desc="Creates a field that damages anyone who attacks the target in melee. "
id="22" target="Realm">
<level>1</level>
<range>1000</range>
<damage>0.7</damage>
<damage_type>Matter</damage_type>

<duration>600</duration>
<power>2</power>
<cast_time>4</cast_time>
</spell>
Server status looks like this:
<server name="Pendragon" type="Test"
lastguildupdate="2003-05-10 12:05:13" lastcharupdate="2003-04-18 05:20:53">
<population>336</population>
<status>Up</status>
<relic name="Scabbard of Excalibur" type="Melee" realm="Albion">
   <owner>Albion</owner>

</relic>
<keep name="Nottmoor Faste" realm="Midgard">
   <owner>Midgard</owner>
<claimant>No Innocent Victims</claimant>
</keep>
</server>
The demo provides code for displaying data from these DAoC files.

What about savefiles?

Since XML has been compared to savefiles in this discussion, why not just use savefiles?

It's a good question. In many cases savefiles are definitely the way to go. In particular, if you want to store the current state of a player mob including anything they are carrying and their customized icon, then savefiles will do the trick and XML would be a poor substitute. Savefiles are great at quickly writing and restoring entire objects and object trees with no hard work on your part.

XML is useful when you want an easy way to customize your game, since the source is in an easily editable and human-readable text format. It's also useful when you want to archive your data, since XML is appropriate for CVS and other source control systems (you can write a savefile out as plain text, but that's not as convenient).

Probably the biggest benefit of XML over savefiles is when you want rich ways to query the data. In a savefile you can move up and down the directory tree, but you can't quickly find out questions like "How many weapons are stored in this file?" or "Which weapons use energy packs as ammunition?"

Savefiles are a convenient, simple solution for storing and retrieving game objects. XML is a convenient, simple solution for manipulating and querying data.

You may want to use savefiles and XML together. There's no reason you can't store a parsed XML tree in a savefile, giving you the convenience and speed of savefiles with the querying capability of XML.

The Rules of XML

XML is amazingly simple. You don't need any special tools to create it (this document is a reasonably large XML document, which I'm editing in a typical text editor before using the XML library to parse it to HTML), and you only need to know a few rules to start creating your own XML files.

The anatomy of an element

As in HTML, text in XML documents is surrounded by "elements". An element works just like it does in HTML, except you aren't restricted in what element names you can use.

Opening tag
A typical element's opening tag looks like this:

<weapon name="Laser pistol">
The word after the opening bracket is the tag's name. Tags are always enclosed in angle brackets (< and >). A starting tag can be as simple as opening bracket, tag name, closing bracket, such as:
<weapon>
But the weapon listed in the previous paragraph had more: it also had an attribute (name="Laser pistol"). An attribute is additional information that can come along with an element.

Closing tag
That's the opening (or starting) tag. Now pay attention to this next part, because this is the thing about XML that changed the world: An element in XML must be explicitly closed. Got that? Brilliant, isn't it?

What does it mean exactly? Well, unlike in HTML where you can have an opening tag like <br> or <p> that just sits there by itself, in XML you must have a closing tag also, which is the same tag name preceded by a slash character (/). So to have a complete weapon element we need:

<weapon name="Laser pistol"></weapon>
Why is that such a big deal? Because without a closing element, an XML parser can't know when the element stops. For the weapon element so far that doesn't seem important: it's opened then it's closed. Nothing significant. However, the weapon could have child elements that belong to it:
<weapon name="Laser pistol">
     <ammunition name="energy pack" damage="3"></ammunition>
</weapon>
Knowing when an element stops turns out to be critical to making parsing simple and flexible. Amazingly enough for such a simple concept, until XML was introduced some of the smartest programmers in the world were still creating formats without closing tags, which meant that their parsers couldn't process a document that had an opening tag that wasn't hardcoded into the parser. This happened all the time, but no more.

You might have noticed that it's a rather awkward waste of space to have a whole closing tag when there's nothing actually inside the element. To make this a bit more elegant, XML allows for one of the only little "tricks" in the format: You can have an opening tag be "self-closing" by placing a slash at the end of the tag, like so:

<ammunition name="energy pack" damage="3" />
Now there is no need for a whole closing tag, since you've already told the parser that this element stops here.

Nested elements

Another simple rule that vastly simplifies the parsing process: You can't open an element inside one element and close it inside another. In other words, this kind of HTML frequently allowed in browsers is completely illegal in XML:
<b><i></b></i>
The italics element starts out inside the bold element, and ends outside the bold element. Bad! As in dating, you leave the party with the same element you walked in with. In XML, elements are always "nested", always completely inside the element they started in:
<b><i></i></b>
This rule was technically true in HTML also, but in a misguided attempt to be "flexible", the browsers would allow breaches like this and guess at what the author intended. Not so for XML parsers! They will yell at you and refuse to go any further. It's tough love, and it's what you need.

Root element

Implicit in the nested elements rule is that an XML document is contained within a single root element. The root element encloses all other elements in the document. So if you have an XML file that defines all the weapons for our game, you might have a weapons root element:
<weapons>
    <weapon name="Laser pistol">
        <ammunition name="energy pack" damage="3" />
    </weapon>
    <weapon name="Gooifier">
        <ammunition name="goo gunk" damage="2" />

    </weapon>
</weapons>
An XML file or string can only have one root element. Multiple elements at the top level are illegal.

Getting Started

Navigating and manipulating XML is very simple. Think of the XML as a tree, with a single parent (the root element) at the top, which has child elements who might have their own children, etc. You can walk up and down the tree looking for things, or you can get a flat list of all the elements that match your criteria and operate on them.

When the library parses XML, it turns each element into an XML/Element object. These objects know their parent and their children, so from any element you can reach the entire tree.

The library provides a rich set of XML editing functions, which should be pretty self-explanatory, so this section just focuses on getting you up and running with navigating XML. When you are ready to start creating and editing XML programmatically, check out procs like New(), setXML(), AddChild(), setChildren(), and WriteToFile().

Getting the root element

The key to accessing the XML is to get your hands on the root element. The library provides several convenient functions for doing this, depending on how the XML is stored. If the XML is in a known file location, use xmlRootFromFile(), like so:
var/XML/Element/root = xmlRootFromFile("myfile.xml")
If there are a bunch of files you may need to read (or if you can't know ahead of time what files you need to read), then an interesting approach is to simply read all the XML files in your game directory into a single XML tree, using xmlRootFromPath():
var/XML/Element/root = xmlRootFromPath()
The function creates a root element, <root>, and adds the contents of each XML file it finds as a child of the root object. Then you just ask for the elements you need (as described in the next section) without regard to what file they were stored in. This is quite a flexible approach, and something you should consider using to simplify the process.

Finally, if you happen to have the XML string around, or want to quickly create an XML document in memory, xmlRootFromString() is the way to go:

var/XML/Element/root = \
xmlRootFromString("<weapons><weapon name="Crowbar"/></weapons>")
Once you have the root object, the fun begins. You have two approaches to getting at the data, which you can combine as necessary: querying and navigating. Querying lets you ask for what you want and get it right away; navigating lets you move up and down the tree looking for what you want.

Querying the tree

Navigating is fun (and covered next), but you can often considerably simplify your code by simply asking for the elements you want up front. For example, if you want all the spell elements in any XML file under your game directory, use Descendants():
var/XML/Element/root = xmlRootFromPath()
var/list/spells = root.Descendants("spell")
That does through every element in the document to find everything named "spell".

Once you have an element, you can query it with procs like Attribute() and Text():

var/XML/Element/root = xmlRootFromPath()
for (var/XML/Element/spell in root.Descendants("spell"))
    var/spell_name = spell.Attribute("name")
    var/desc_element = spell.FirstChild("description")
    var/spell_desc = desc_element.Text()
Often you can save a line or two by using FirstChildText() instead of Text():
var/XML/Element/root = xmlRootFromPath()
for (var/XML/Element/spell in root.Descendants("spell"))
    var/spell_name = spell.Attribute("name")
    var/spell_desc = spell.FirstChildText("description"))

Navigating the tree

All elements except the root have one parent, and all elements can have zero or more children. In some cases you may want to navigate to a portion of the tree. For example, if you have a large XML document it may be too time consuming to use Descendants() on the entire document. In other cases once you've gotten to the parent element you need, you want to check for particular children of that element.

It's important to understand the difference between children and descendants. A child belongs directly to its parent, with nothing else in between. A descendant can be a child or a grandchild or any other element inside the parent. Ask for a child when you know it belongs directly to the parent; ask for a descendant when you aren't sure where it will be inside the parent.

Children
There are several ways to access an element's children. If you want all of the children that match a certain name, you can use ChildElements():

var/XML/Element/root = xmlRootFromPath()
var/list/spells = root.ChildElements("spell")
If you want all the child elements regardless of their name, just call it without an argument:
var/XML/Element/root = xmlRootFromPath()
var/list/children = root.ChildElements()
Very similar to ChildElements() is Children(); in fact, if called with a name argument, they act exactly the same. There are a couple of procs that have two versions like this (FirstChild() and FirstChildElement() is another case); the difference comes when they are called without an argument: Children() and FirstChild() may return special elements you might not be expecting, such as raw text, comments, or processing instructions. Those procs tend to be used internally by the library, and you'll usually want to stick with the "Element" version of the procs, which only return the kind of element you are probably expecting.

To get the first child of an element, use FirstChildElement():

var/XML/Element/root = xmlRootFromPath()
var/XML/Element/spellbook = root.FirstChildElement()
It's a bit dangerous to just grab the first child, though...are you sure it's the element you expect? Maybe something else slipped in there on you. To be safer, if you know the name of the element you want, pass it as an argument and you'll get the first child found with that name:
var/XML/Element/root = xmlRootFromPath()
var/XML/Element/spellbook = root.FirstChildElement("spellbook")
Descendants
To get the first element anywhere inside the parent with a certain name, use Descendant():
var/XML/Element/root = xmlRootFromPath()
var/XML/Element/first_spell = root.Descendant("spell")
To get all elements inside a parent with a certain name, use Descendants():
var/XML/Element/root = xmlRootFromPath()
var/list/spells = root.Descendants("spell")
Or, if you'd like every descendant regardless of name, call it without an argument.

If the element you are looking for might be any element including the parent, then use DescendantsOrSelf():

var/XML/Element/root = xmlRootFromFile("spellbook.xml")
var/list/spellbooks = root.DescendantsOrSelf("spellbook")
Parents and ancestors
To get the direct parent of an element, use Parent():
var/XML/Element/root = xmlRootFromPath()
var/XML/Element/first_spell = root.Descendant("spell")
var/XML/Element/spellbook = first_spell.Parent()
To get a parent or ancestor of a particular name, pass a name argument to Parent():
var/XML/Element/root = xmlRootFromPath()
var/XML/Element/first_spell = root.Descendant("spell")
var/XML/Element/spell_library = first_spell.Parent("spell_library")

Reference

Functions

xmlRootFromFile
xmlRootFromFile(file)

Parses the file and returns the root element object.

Returns:
An XML/Element object that is the root element for the XML tree.

Parameters:
file - The file to parse, as a path or file object.

Example:

var/XML/Element/root = \
xmlRootFromFile("myfile.xml")

xmlRootFromPath
xmlRootFromPath(path)

Reads all XML files anywhere in the path into a tree and returns the root element.

Returns:
An XML/Element object that is the root element for the XML tree.

Parameters:
path - The path to search for XML files.

Discussion:
Parses all .xml files found in the path and its subdirectories into one XML tree with a root element called "root". Each file is treated as a child of the root. The children are given an "filepath" attribute indicating what file they were read from. If no path is specified, uses the top level path of the game.

Example:

// Read all XML files from the game directory and its sub-directories.
var/XML/Element/root = xmlRootFromPath()

xmlRootFromString
xmlRootFromString(text)

Parses the string and returns the root element object.

Returns:
An XML/Element object that is the root element for the XML tree.

Parameters:
file - The string to parse.

Example:

var/XML/Element/root = xmlRootFromString("<book><title>My life in a nutshell.</title></book>")

Classes

XML/Element

Representing an XML element, this is the primary class for accessing and manipulating XML.

Procs

New
New(tag, xml)

The optional parameters allow you to specify the contents of the element on creation.

Returns:
An XML/Element object.

Parameters:
tag - An optional parameter that specifies the name of the element; equivalent to calling setTag().
xml - An optional parameter specifying the xml text of the element; equivalent to calling setXML().

Discussion:
If you are just reading XML, you will never need to create an XML/Element directly. The only time you need to create an element is if you are creating or editing an XML tree programmatically.

See Also:
setTag(), setXML()

Example:

var/XML/Element/spell = \
new("spell", "<name>Magic Missile</name><damage>1</damage><distance>5</distance>")

AddChild
AddChild(child, position)

Add a child element at the specified position.

Returns:
Nothing.

Parameters:
child - An XML/Element.
position - An optional parameter specifying where the child should be placed. Defaults to LAST_CHILD.

Discussion:
position can be set to FIRST_CHILD or LAST_CHILD.

This proc removes the child from any previous parent.

If you want to add children without having to create XML/Element objects first, use setXML().

See Also:
AddSibling(), RemoveChild()

Example:

var/XML/Element/spellBook = \
new("spellbook")
var/XML/Element/fireball = \
new("spell", "<name>Fireball</name>")

spellBook.AddChild(fireball, FIRST_CHILD)

AddSibling
AddSibling(sibling, position)

Add a sibling next to this element.

Returns:
Nothing.

Parameters:
sibling - An XML/Element.
position - An optional parameter specifying where the sibling should be placed. Defaults to AFTER.

Discussion:
position can be set to BEFORE or AFTER.

Removes the sibling from any previous parent. If this element does not have a parent (as the root element does not), an error message occurs since there is nowhere to put the sibling.

See Also:
AddChild()

Example:

var/XML/Element/spellBook = \
new("spellbook", "<spell><name>Fireball</name></spell>")
var/XML/Element/fireball = spellBook.FirstChild("spell")
var/XML/Element/iceblast = \
new("spell", "<name>Ice Blast</name>")

fireball.AddSibling(iceblast, BEFORE)

Attribute
Attribute(name)

Returns the value for the specified attribute.

Returns:
A text string.

Parameters:
name - The name of the desired attribute.

Discussion:
An attribute is extra information next to the element tag, like so: <spellbook cover="leather">. In this example, the spellbook has a cover attribute.

XML designers are forever arguing over when things should be stored as attributes versus as child elements.

See Also:
setAttribute(), Attributes(), setAttributes()

Example:

var/cover_style = spellBook.Attribute("cover")

Attributes
Attributes()

Returns an associated list of attribute names and their values.

Returns:
A list.

Discussion:
The list contains all the attributes for this element, with the attribute names as the keys.

See Also:
setAttributes(), Attribute()

Example:

var/list/attributes = spellBook.Attributes()
for (var/name in attributes)
    var/value = attributes[name]
    world << "found attribute [name] = [value]"

ChildElements
ChildElements(name)

Returns a list of direct children that are regular elements.

Returns:
A list.

Parameters:
name - An optional parameter to get only the children with this name.

Discussion:
This skips special elements, like raw text, comments, and processing instructions. In most cases you want to use this rather than Children(). If a name is provided, only children with that name are included.

See Also:
Children(), FirstChild(), FirstChildElement()

Example:

var/list/spells = spellBook.ChildElements()

Children
Children(name)

Returns a list of direct children.

Returns:
A list.

Parameters:
name - An optional parameter to get only the children with this name.

Discussion:
If no name is provided, this returns all direct children of any type, including raw text, comments, and processing instructions. In most cases you want to use ChildElements() instead.

See Also:
ChildElements(), FirstChild(), FirstChildElement()

Example:

var/list/spells = spellBook.Children("spell")

Descendant
Descendant(name)

Returns a descendant belonging to this element.

Returns:
An XML/Element or null.

Parameters:
name - An optional parameter to get the descendant with this name.

Discussion:
By default returns the element's first child. If name is provided, returns the first element found anywhere inside this element with that name, or null if there is no descendant with that name. Unlike FirstChild(), which only checks the direct children, Descendant() searches all levels below this element.

See Also:
Descendants(), FirstChild(), FirstChildElement()

Example:

var/XML/Element/firstspell = spellBook.Descendant("spell")

Descendants
Descendants(name)

Returns a list of all elements anywhere inside this element.

Returns:
A list.

Parameters:
name - An optional parameter to get only the descendants with this name.

See Also:
DescendantsOrSelf(), Descendant(), Children(), ChildElements()

Example:

var/list/all_spells = spellBook.Descendants("spell")

DescendantsOrSelf
DescendantsOrSelf(name)

Returns a list of all elements anywhere inside this element, including this element.

Returns:
A list.

Parameters:
name - An optional parameter to get only the elements with this name.

See Also:
Descendants(), Descendant(), Children(), ChildElements()

Example:

var/list/all_spellbooks = spellBook.DescendantsOrSelf("spellbook")

FirstChild
FirstChild(name)

Returns the first child, regardless of what kind of element it is.

Returns:
An XML/Element or null.

Parameters:
name - An optional parameter to get the first child found with this name.

Discussion:
If no name is provided, returns the first child, which might be a regular element or a special element, such as raw text, a comment, or a processing instruction. Child elements are those elements that are directly underneath this element (so grandchildren and further down are not considered). If a name is provided, returns the first child found with that name.

Often if you use this proc without specifying a name, you will unwittingly end up with a text element representing white space between two regular elements or somesuch; in most cases you want to use FirstChildElement().

See Also:
FirstChildElement(), FirstChildText(), Descendant(), Children(), ChildElements()

Example:

var/XML/Element/firstspell = spellBook.FirstChild("spell")

FirstChildElement
FirstChildElement(name)

Returns the first child that is a regular element.

Returns:
An XML/Element or null.

Parameters:
name - An optional parameter to get the first child found with this name.

Discussion:
If no name is provided, returns the first "regular" child element. Child elements are those elements that are directly underneath this element (so grandchildren and further down are not considered). Internally, raw text, comments, and processing instructions are wrapped in special elements to simplify processing; those special elements are skipped by this proc, so that you always get elements like <spellbook> and <spell>. If a name is provided, the first child found with that name is returned.

You usually want to use this proc rather than FirstChild().

See Also:
FirstChild(), FirstChildText(), Descendant(), Children(), ChildElements()

Example:

var/XML/Element/firstspell = spellBook.FirstChildElement()

FirstChildText
FirstChildText(name)

Returns the text of the first child, with any internal element tags removed.

Returns:
A text string or null.

Parameters:
name - An optional parameter to get the text of the first child found with this name.

Discussion:
This is a convenience proc to keep you from having to call FirstChild() to get an element and then call Text() on it. This proc calls FirstChild() to get the child element, which might be a special element (raw text, comment, etc). It's safest if you always provide a name so you know you are getting what you want.

See Also:
FirstChild(), FirstChildElement(), Text()

Example:

var/XML/Element/spellBook = \
new("spellbook", "<spell><name>Fireball</name><damage>1</damage></spell>")
var/XML/Element/spell = spellBook.FirstChild("spell")

var/name = spell.FirstChildText("name")
var/damage = spell.FirstChildText("damage")

world << "You were hit by a [name] spell for [damage] damage!"

Parent
Parent(name)

Returns the element's parent.

Returns:
An XML/Element or null.

Parameters:
name - An optional parameter to get the parent or ancestor with this name.

Discussion:
By default returns the element's direct parent. If name is provided, returns the parent or ancestor with that name, or null if there is no ancestor with that name.

See Also:
FirstChild(), Descendant(), Children(), ChildElements()

Example:

var/XML/Element/spellBook = spell.Parent("spellbook")

RemoveChild
RemoveChild(child)

Remove the child from the element.

Returns:
Nothing.

Parameters:
child - An XML/Element.

See Also:
RemoveChildren(), AddChild(), setChildren()

Example:

spellBook.RemoveChild(fireball)

RemoveChildren
RemoveChildren()

Remove all children from the element.

Returns:
Nothing.

See Also:
RemoveChild(), AddChild(), setChildren()

Example:

spellBook.RemoveChildren()

setAttribute
setAttribute(name, value)

Returns the value for the specified attribute.

Returns:
A text string.

Parameters:
name - Name of the attribute being set.
value - Value to set the attribute to.

See Also:
Attribute(), setAttributes()

Example:

spellBook.setAttribute("cover", "latex")

setAttributes
setAttributes(associated_list)

Sets the attribute list to the specified associated_list.

Returns:
Nothing.

Parameters:
associated_list - An associated list with attribute names as the keys.

See Also:
Attributes(), setAttribute()

Example:

var/XML/Element/spellBook = \
new("spellBook")
var/list/attributes = new()
attributes["cover"] = "leather"
attributes["title"] = "Big Book of Spells"

spellBook.setAttributes(attributes)

setChild
setChild(child)

Replaces any existing children with this element.

Returns:
Nothing.

Parameters:
child - An XML/Element object.

Discussion:
Removes the child from any existing parent.

See Also:
setChildren(), AddChild()

Example:

var/XML/Element/spellBook = \
new("spellBook")
var/XML/Element/spell = new("spell")

spellBook.setChild(spell)

setChildren
setChildren(children)

Set the element's children to these, replacing any existing children.

Returns:
Nothing.

Parameters:
children - A list of XML/Element objects.

Discussion:
Calls AddChild() for each child in the list.

See Also:
setChild(), AddChild()

Example:

var/XML/Element/spellBook = \
new("spellBook")

var/XML/Element/fireball = \
new("spell", "<name>Fireball</name><damage>1</damage>")
var/XML/Element/iceblast = \
new("spell", "<name>Ice Blast</name><damage>2</damage>")
var/list/spells = list(fireball, iceblast)

spellBook.setChildren(spells)


setTag
setTag(tag)

Specify the name of the element.

Returns:
Nothing.

Parameters:
tag - The name for the element.

Discussion:
In most cases you'll want to set the tag when you create the element, as an argument to New().

See Also:
Tag()

Example:

var/XML/Element/spellBook = \
new()
spellBook.setTag("spellBook")

setText
setText(text)

Specify the content of the element as raw text.

Returns:
Nothing.

Parameters:
text - The text.

Discussion:
This treats text as a raw text string (rather than as XML) and sets the contents of the element to that text. To support player-entered text, and to make sure the XML represents the text as it is presented, any illegal characters for XML are "escaped". This means they are changed to their entity equivalent, so that "Ted & Alice are <dating>..." becomes "Ted &amp; Alice are &lt;dating&gt;...". If you use Text() to access the text later, the entities are "unescaped" so that you get the text back in the original form. In general if you use setText() and Text() you won't need to think about this entity stuff, it'll just do the right thing.

If you want your text treated as parsable XML, use setXML().

See Also:
Text(), setXML()

Example:

var/XML/Element/spellBook = \
new("<title></title>")
var/XML/Element/title = spellBook.FirstChild("title")
title.setText("Spells & Spells & More Spells")

setXML
setXML(text)

Specify the content of the element.

Returns:
Nothing.

Parameters:
text - The text to parse.

Discussion:
This treats text as an XML string and parses it to determine the contents of this element. text can be pure text ("The sky was blue today.") or can represent a set of elements ("<sky><color>blue</color></sky>"). Any existing children are replaced.

In many cases you'll want to set the XML when you create the element, as an argument to New().

If you want your text treated as raw text (not parsed as XML), use setText().

See Also:
XML(), setText()

Example:

var/XML/Element/spellBook = \
new()
spellBook.setXML("<spell><name>fireball</name></spell>")

String
String()

Returns text including nested element tags, but without the enclosing tags.

Returns:
A text string.

Discussion:
A spellBook element would return everything but the tags for the spellbook itself: "<spell><name>fireball</name></spell>".

See Also:
XML(), Text()

Example:

var/spell_text = spellBook.String()

Tag
Tag()

The name of the element.

Returns:
A text string.

Discussion:
If the element is <booktitle>, then the tag is "booktitle". In Document Object Model (DOM) terminology, the tag is also known as the "generic identifier", but we don't use such ugly language around here.

See Also:
setTag()

Example:

for (var/XML/Element/child in spellBook.ChildElements())
    var/child_tag = child.Tag()
    world << "Found [child_tag]"

Text
Text(escaped)

Returns all text, removing any element tags.

Returns:
A text string.

Parameters:
escaped - An optional parameter indicating whether entities should be escaped.

Discussion:
This is often useful if you want to display XML text to a player without worrying about showing them any internal tags. It often saves some code to use FirstChildText() instead.

By default the text returned does not have entities escaped. That is, characters like <> are returned as themselves, <>. If escaped is set to 1, then characters like <> are returned in their entity form, as they are be stored in the XML, &lt;&gt;.

See Also:
setText(), XML(), String()

Example:

var/XML/Element/spellBook = \
new("spellbook", "<spell><name>Fireball</name><damage>1</damage></spell>")
var/XML/Element/spell = spellBook.FirstChild("spell")

var/XML/Element/name = spell.FirstChild("name")
var/XML/Element/damage = spell.FirstChild("damage")

world << "You were hit by a [name.Text()] spell for [damage.Text()] damage!"

WriteToFile
WriteToFile(file)

Write the XML for this element to the specified file.

Returns:
Nothing.

Parameters:
file - The name of the file.

Discussion:
Calls XML() and writes the results to the specified file. Deletes any file already existing at that location.

Call this on the root element to write out the entire XML document.

See Also:
XML()

Example:

var/XML/Element/spellBook = \
new("<spell><name>fireball</name></spell>")
spellBook.WriteToFile("spellbook.xml")

XML
XML()

Returns all text including enclosing tags and nested element tags.

Returns:
A text string.

Discussion:
Use this to get the complete XML string from the element. A spellBook element might return "<spellbook><spell><name>fireball</name></spell></spellbook>". Entities (characters like <>) are returned in their entity form (&lt;&gt;), since that is required for the XML to be legal.

Call XML() on the root element to get the entire document.

See Also:
setXML(), Text(), String()

Example:

var/xml_text = spellBook.XML()

dude how do u type so much >.< in just a short period of time. o.o
This library is an absolute necessity. I include it first thing in all my projects, and all of them make heavy usage of xml. I can't recommend it any more highly.
Shorty241 wrote:
dude how do u type so much >.< in just a short period of time. o.o

This library has been around for a while now. Dream Makers is starting to get all the tuts and guides from BYONDScape to make it the ultimate place for DM tuts/guides.
Kakashi24142 wrote:
Dream Makers is starting to get all the tuts and guides from BYONDScape to make it the ultimate place for DM tuts/guides.

Correctamundo!