# Standard XML Module

The Standard XML module is an original implementation of the XML markup language. The module provides the necessary objects for parsing a xml description as well as manipulating the parsed tree. The module can be extended to a service as a mean to act as a XML processor. The module also provides the support for a simple model which enable the quick parsing of documents with a relaxed rule checking approach.

## XML tree representation

A xml document is represented with a tree. At the top of the tree is the `XmlRoot` object. The root object is not part of the document, but acts as the primary container for other objects. A xml document starts with a root node and all other child elements are `XmlNode` objects.

### Node base object

The xml tree is built with the `XmlNode` object. The node object has different derivation depending on the required representation. For example, the `XmlRoot` object is derived from the `XmlNode` object. A node object can have child object unless the node is marked as an empty node. Trying to add node to an empty node results in an exception. A node can also be marked empty by the user. This situation typically arises with tag node which are used alone such like the <br/> xhtml empty tag or an empty paragraph <p/>. Although a xml node cannot be constructed directly, there is a predicate `node-p` that can be used to assert the node type.

# check a node assert true (afnix:xml:node-p node)

The `add-child` method adds a child node to the calling node. If the calling node is marked empty, an exception is raised when attempting to add the node. There is no limit for the number of nodes to add. In particular, when a text is to be added, care should be taken that there is no markup within that text. In doubt, the `parse` method should be used.

# parse a text and add 3 child nodes p:parse "The quick brown <b>fox</b> jumps over the lazy dog"

In the previous example, the first child node is a `XmlText` node with the value The quick brown . The second node is a `XmlTag` node with name b. Finally, the third node is also a `XmlText` node with the value jumps over the lazy dog. It should be noted that the tag node has a child `XmlText` node with the value fox. This example also illustrates the power of the `parse` method which considerably simplify the creation of a xml tree. Finally, there is a subtle subject to be treated later which concerns the use of character reference with the `parse` method. Like any other xml parser, character references are evaluated during the parsing phase, thus providing no mechanism to create such reference. For this reason, a special class called `XmlCref` is provided in the module.

### Tag object

The `XmlTag` class is one of the most important class as it holds most of the xml constructs. A tag is defined by a name, a set of attributes and eventually a content. In its simplest form, a tag is created by name. With an additional boolean parameter, the tag can be marked as an empty node.

# create an empty paragraph tag const p (afnix:xml:XmlTag "p" true)

Adding attributes to a tag is imply a matter of method call. The `add-attribute` method operates with a `Property` object while the `set-attribute` operates with a name and a literal value. As a matter of fact, the attributes are stored internally as a property list.

# <p class="text"> # create a paragraph tag const p (afnix:xml:XmlTag "p") # set the class attribute p:set-attribute "class" "text"

The node empty flag determines whether or not there is a end tag associated with a tag. If the empty flag is false, the node can have children nodes and is associated with a end tag. With the empty flag set, there is no child nodes. Such situation corresponds to the xml /> notation.

# <br/> # create a br empty tag const br (afnix:xml:XmlTag "br" true)

### Text objects

The xml module provides two types of xml text node. The basic object is the `XmlText` node which is designed to hold some text without markup. It is this kind of nodes which is automatically instantiated by the `parse` method, as described earlier. The other object is the `XmlData` which corresponds to the xml CDATA special markup. With a character data node, the characters are not interpreted, including those that indicate markup starts like < or end like >. The `XmlData` is particularly used to store scripts or other program text inside a xml description. As an example, it is recommended to use a character data node inside a script tag with xhtml.

## Document reading

A xml document is read by scanning an input stream an building a representation of the xml tree.

### The document object

The `XmlDocument` object is a special object is designed to ease the reading process of an xml document. The process of creating a xml document consists of creating a document object, then binding a xml reader, parsing the input stream and finally storing the root node. When the operation is completed, the root node is available in the document object.

# create a xml document const xdoc (afnix:xml:XmlDocument "example.xml") # get the root node const rppt (xdoc:get-root)

### The root node content

When a document is parsed, the root node holds all the elements and markup sequentially. At this stage, it shall be noted that the element data are not expanded. Unlike a normal XML reader, the parameter entity are kept in the node data, are expended later by the XML processor.

## Node tree operations

The class `XneTree` provides a single framework to operate on a node and its associated tree. Since a node always carries a sub-tree, the node tree term will be used to reference it.

### Creating a node tree

A node tree is created either from a node at construction or with the help of the `set-node` method.

# create a node tree at construction const tree (afnix:xml:XneTree root) # change the node tree tree:set-node node

Once a tree is created, various methods are provided to operate on the whole tree. The `depth` method returns the depth of the node tree. The `get-node` methods returns the the node associated with the tree.

# get the tree depth println (tree:depth)

### Namespace operations

The concept of namespace is an extension to the xml standard. Unlike other programming language, the concept of namespace is designed to establish a binding between a name and an uri. Such binding permits to establish a scope for tags without too much burden. In the xml namespace terminology, an expanded name is composed of a prefix and a local name. The basic operations provided at the tree level is the prefix cancellation and the tree prefix setting.

# clear the prefix for the whole tree tree:clear-prefix # set a prefix for the whole tree tree:set-prefix "afnix"

The `set-prefix` changes the prefix for the whole tree. It is not necessary to clear first the prefix.

### Attribute operations

Each node in the node tree can have its attribute list modified in a single operation. The first operation is to clear all attributes for all nodes. Although this operation might be useful, it should be carried with caution. The attributes can also cleared more selectively by using the tag name as a filter. For more complex operation, the `clear-attribute` method of the `XmlTag` is the definitive answer.

# clear all attributes tree:clear-attribute # clear all attributes by tag name tree:clear-attribute "p"

The `set-attribute` method sets an attribute to the whole tree. The first argument is the attribute name and the second is a literal value. For more selective operations, the `set-attribute` method can be also called at the tag level.

# clear all attributes tree:set-attribute "class" "text"

When it comes to set attributes, there is a special operation related to the "id" attribute. Such attribute is supposed to be unique for the whole tree. For this reason, the `generate-id` generates a unique id for each node and assign the id attribute. The attribute is unique at the time of the call. If the tree is modified, and in particular, if new node are added, the method must be called again to regenerate the node id.

# set a unique id for all nodes tree:generate-id

## Node location and searching

The node location is the ability to locate one or several nodes in a xml tree. A node is generally located by name, path or id. Once a node has been located, it can be processed. Note that the node locator operates operates almost exclusively with `XmlTag` node, although it might not be always the case.

### Node selection

The process of finding a child node is obtained with the help of the `XneCond` class combined with the `select` method of the `XneTree` Object. The `select` method traverses the whole tree and attempts to match a condition for each node. If the condition is evaluated successfully for a node, the node is added in the result vector. Note that the tree can be traversed entirely or with only the first layer of children.

# creating a condition node const xcnd (afnix:xml:XneCond) # create a tree with a root node const tree (afnix:xml:XneTree root) # select all nodes for that condition trans result (tree:select xcnd)

In the previous example, the condition object is empty. This means that there is no condition, and thus works for all nodes. This previous example will return all nodes in the tree.

### Node condition

The `XmlCond` class provides several method to add a conditions. The `add` method is the method of choice to add a condition. The method operates with a condition type and a literal. Note that the object can contain several conditions.

# creating a condition node const xcnd (afnix:xml:XneCond) # add a condition by name xcnd:add afnix:xml:xne:NAME "p"

In the previous example, a condition is designed to operate with a tag name. Upon a call to the `select` method with this condition, all nodes in the tree that have the tag name p will be selected.

# creating a condition node const xcnd (afnix:xml:XneCond) # add a condition by name xcnd:add afnix:xml:xne:NAME "p" # add an index condition xcnd:add afnix:xml:xne:INDEX 0

In the previous example, a condition is designed to operate with a tag name and index. Upon a call to the `select` method with this condition, all nodes in the tree that have the tag name p and those child index is 0 will be selected.

### Selection result

The node selection operates by default on the whole tree. The `select` method, when called with a second boolean argument can restrict the search to the child nodes.

# creating a condition node const xcnd (afnix:xml:XneCond) # create a tree with a root node const tree (afnix:xml:XneTree root) # select all nodes for that condition trans result (tree:select xcnd false)

The selection results is stored in a vector object. The node order corresponds to the tree order obtained with a depth first search approach.

## Simple model node

The XML simple model is designed to simplify the interpretation of a general sgml document such like, html or xhtml document. In the simple model approach, there is no tree. Instead, a vector of simple nodes is built, and a document interface can be used to access the nodes. Therefore, this simple model should be considered as a mean to quickly parse document, but should not be used when tree operations come into play. In such case, the xml model is by far more appropriate. The simple model can be used to parse a html document for instance. Note also that the simple model is a relaxed model in terms of parsing rules. For example, the tag start/end consistency is not checked and the attribute parsing is not aggressive as it can be found generally in poorly written html document.

In the simple model, a `XsmNode` is just a text place holder. The node transports its type which can be either text, tag, reference of end node. For the tag node, a subtype that identifies reserved nodes versus normal type is also available.

### Creating a node

A xsm node is created by name or byte and name. In the first case, the node is a text node. In the second case, the node subtype is automatically detected for tag node.

# create a xsm text node const ntxt (afnix:xml:XsmNode "afnix"> # create a xsm tag node const ntag ( afnix:xml:XsmNode afnix:xml:XsmNode:TAG "afnix">

Note that the text corresponds to the node content. For example, the string "!-- example --" might corresponds to a comment in html which is to say a reserved tag when the type is tag or a simple text if the type is a text node. A reserved tag is defined by a string which start either with the '!' character or the '[' character.

# create a reserved tag const rtag ( afnix:xml:XsmNode afnix:xml:XsmNode:TAG "!-- example --")

### Node representation

The xsm node is a literal node. This means that the `to-string` and `to-literal` methods are available. When the `to-literal` method is called, the node text is automatically formatted to reflect the node type.

# create a reserved tag const rtag ( afnix:xml:XsmNode afnix:xml:XsmNode:TAG "!-- example --") # print the node literal rtag:to-literal # <!-- example -->

If the node is a reference node, the node literal is represented with the original definition while the `to-string` method will produce the corresponding character if it known.

### Node information

With a xsm node, the operation are a limited number of node information operations. The `get-name` method returns the first name found in a node. If the node is a normal tag, the `get-name` will return the tag name. For the other node, the method will return the first available string. This also means, that the method will behave correctly with end tag node.

# create a tag node const ntag ( afnix:xml:XsmNode afnix:xml:XsmNode:TAG "afnix"> # get the tag name ntag:get-name

There is a predicate for all types. For example, the `text-p` predicate returns true if the node is a text node. The `tag-p` predicate returns true if the node is a normal or reserved tag.

## Document reading

A document is read in a way similar to the `XmlDocument` with the help of the `XsmDocument` object. Once created, the document holds a vector of nodes.

### The document object

The `XsmDocument` object is a special xsm object designed to ease the reading process of a document. The process of creating a document consists of creating a document object, then binding a xsm reader, parsing the input stream and storing the nodes in a vector. When the operation is completed, the vector can be accessed by index.

# create a xms document const xdoc (afnix:xml:XsmDocument "example.htm") # get the document length xdoc:length

### Node information object

The `XsoInfo` object is a node information object designed to hold a node name, an attributes list and eventually a text associated with the node. For example, if a html document contains a anchor node, the associated information node, will have the anchoring text stored as the node information text.

# create a xso node by name and text const info (afnix:xml:XsoInfo "a" "click here")

### Simple model operations

The `XsmDocument` is designed to perform simple operations such like searching all nodes that matches a particular name. While this operation can be done easily, it is done in such a way that a vector of node information is returned instead of a vector of nodes which can always be constructed with a simple loop.

# create a xsm document const xdoc (afnix:xml:XsmDocument "example.htm") # get all node named "a" - forcing lower case xdoc:get-info-vector "a" true