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:
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.<unit> <name>Doggie</name> <damage>3</damage> <distance>5</distance> <description>Woof woof.</description> <image>demo/units/doggie.bmp</image> </unit>
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:
Server status 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>
The demo provides code for displaying data from these DAoC files.<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>
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:
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 name="Laser pistol">
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.<weapon>
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:
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"></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.<weapon name="Laser pistol"> <ammunition name="energy pack" damage="3"></ammunition> </weapon>
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:
Now there is no need for a whole closing tag, since you've already told the parser that this element stops here.<ammunition name="energy pack" damage="3" />
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: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></b></i>
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.<b><i></i></b>
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:An XML file or string can only have one root element. Multiple elements at the top level are illegal.<weapons> <weapon name="Laser pistol"> <ammunition name="energy pack" damage="3" /> </weapon> <weapon name="Gooifier"> <ammunition name="goo gunk" damage="2" /> </weapon> </weapons>
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, usexmlRootFromFile()
, like so:
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, usingvar/XML/Element/root = xmlRootFromFile("myfile.xml")
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.var/XML/Element/root = xmlRootFromPath()
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:
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.var/XML/Element/root = \ xmlRootFromString("<weapons><weapon name="Crowbar"/></weapons>")
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, useDescendants()
:
That does through every element in the document to find everything named "spell".var/XML/Element/root = xmlRootFromPath() var/list/spells = root.Descendants("spell")
Once you have an element, you can query it with procs like Attribute()
and Text()
:
Often you can save a line or two by usingvar/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()
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 useDescendants()
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()
:
If you want all the child elements regardless of their name, just call it without an argument:var/XML/Element/root = xmlRootFromPath() var/list/spells = root.ChildElements("spell")
Very similar tovar/XML/Element/root = xmlRootFromPath() var/list/children = root.ChildElements()
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()
:
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()
Descendantsvar/XML/Element/root = xmlRootFromPath() var/XML/Element/spellbook = root.FirstChildElement("spellbook")
To get the first element anywhere inside the parent with a certain name, use
Descendant()
:
To get all elements inside a parent with a certain name, usevar/XML/Element/root = xmlRootFromPath() var/XML/Element/first_spell = root.Descendant("spell")
Descendants()
:
Or, if you'd like every descendant regardless of name, call it without an argument.var/XML/Element/root = xmlRootFromPath() var/list/spells = root.Descendants("spell")
If the element you are looking for might be any element including the parent, then use DescendantsOrSelf()
:
Parents and ancestorsvar/XML/Element/root = xmlRootFromFile("spellbook.xml") var/list/spellbooks = root.DescendantsOrSelf("spellbook")
To get the direct parent of an element, use
Parent()
:
To get a parent or ancestor of a particular name, pass a name argument tovar/XML/Element/root = xmlRootFromPath() var/XML/Element/first_spell = root.Descendant("spell") var/XML/Element/spellbook = first_spell.Parent()
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
xmlRootFromFilexmlRootFromFile(file)Parses the file and returns the root element object.
Returns:
AnXML/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:
AnXML/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:
AnXML/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.NewNew(tag, xml)The optional parameters allow you to specify the contents of the element on creation.
Returns:
AnXML/Element
object.Parameters:
tag - An optional parameter that specifies the name of the element; equivalent to callingsetTag()
.
xml - An optional parameter specifying the xml text of the element; equivalent to callingsetXML()
.Discussion:
If you are just reading XML, you will never need to create anXML/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>")
AddChildAddChild(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)
AddSiblingAddSibling(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)
AttributeAttribute(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")
AttributesAttributes()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]"
ChildElementsChildElements(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 thanChildren()
. If a name is provided, only children with that name are included.See Also:
Children()
,FirstChild()
,FirstChildElement()
Example:var/list/spells = spellBook.ChildElements()
ChildrenChildren(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 useChildElements()
instead.See Also:
ChildElements()
,FirstChild()
,FirstChildElement()
Example:var/list/spells = spellBook.Children("spell")
DescendantDescendant(name)Returns a descendant belonging to this element.
Returns:
AnXML/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. UnlikeFirstChild()
, 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")
DescendantsDescendants(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")
DescendantsOrSelfDescendantsOrSelf(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")
FirstChildFirstChild(name)Returns the first child, regardless of what kind of element it is.
Returns:
AnXML/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")
FirstChildElementFirstChildElement(name)Returns the first child that is a regular element.
Returns:
AnXML/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()
FirstChildTextFirstChildText(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 callFirstChild()
to get an element and then callText()
on it. This proc callsFirstChild()
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!"
ParentParent(name)Returns the element's parent.
Returns:
AnXML/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")
RemoveChildRemoveChild(child)Remove the child from the element.
Returns:
Nothing.Parameters:
child - An XML/Element.See Also:
RemoveChildren()
,AddChild()
,setChildren()
Example:spellBook.RemoveChild(fireball)
RemoveChildrenRemoveChildren()Remove all children from the element.
Returns:
Nothing.See Also:
RemoveChild()
,AddChild()
,setChildren()
Example:spellBook.RemoveChildren()
setAttributesetAttribute(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")
setAttributessetAttributes(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)
setChildsetChild(child)Replaces any existing children with this element.
Returns:
Nothing.Parameters:
child - AnXML/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)
setChildrensetChildren(children)Set the element's children to these, replacing any existing children.
Returns:
Nothing.Parameters:
children - A list ofXML/Element
objects.Discussion:
CallsAddChild()
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)
setTagsetTag(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 toNew()
.See Also:
Tag()
Example:var/XML/Element/spellBook = \ new() spellBook.setTag("spellBook")
setTextsetText(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 & Alice are <dating>...". If you useText()
to access the text later, the entities are "unescaped" so that you get the text back in the original form. In general if you usesetText()
andText()
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")
setXMLsetXML(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>")
StringString()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()
TagTag()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]"
TextText(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 useFirstChildText()
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, <>.
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!"
WriteToFileWriteToFile(file)Write the XML for this element to the specified file.
Returns:
Nothing.Parameters:
file - The name of the file.Discussion:
CallsXML()
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")
XMLXML()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 (<>), 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()