Team LiB
Previous Section Next Section

Working with the DOM

The XML Document Object Model (DOM) is a programming interface for XML documents. It defines the way an XML document can be accessed and manipulated and is designed to be used with any programming language or operating system. The XML DOM enables you to create and navigate an XML document. In addition, it makes it possible for you to add, modify, and delete elements from the document.

TIP

Because the XML DOM stores documents in memory, it can consume a lot of resources when manipulating a large XML document. In addition, you should persist this document after creating it.


The Microsoft XML DOM implementation supports all the necessary functions needed to traverse the node tree, access nodes and their attributes, insert and delete nodes, and convert from the node tree back to XML. In addition, it includes the following classes for building and representing XML: XmlDocument, XmlElement, XmlAttribute, XmlNode, XmlNodeList, and XmlComment. All these classes are located in the System.Xml namespace.

TIP

There are two main classes that make up the core of the XML DOM implementation: XmlNode and XmlNodeList. The first class, XmlNode, is an abstract class that represents an XML document. The second class, XmlModeList, is an ordered list of nodes. All other classes, such as the XmlDocument, XmlElement, XmlAttribute, XmlComment, and XmlDocumentFragment, are inherited from the XmlNode class.


NOTE

Although this chapter shows the primary ways in which to use the XML DOM in .NET, it does not contain detailed information about every class that is declared in the System.Xml namespace. However, many resources that contain this information are available on the Internet and should be used to gain more knowledge on the implementation of the XML DOM.


Listing 8.1 shows you how to create an XML document, work with XML nodes, elements, attributes, and store a document.

Listing 8.1. XML DOM Demonstration Sample
using System;
using System.Xml;
using System.Collections;

namespace SAMS.VisualCSharpDotNetUnleashed.Chapter8
{
        public abstract class CustomFactory
        {
                public static XmlDocument GetDocument(ICustomElement customElement)
                {
                        XmlDocument document = new XmlDocument();
                        document.AppendChild(GetNodeInternal(customElement, document));
                        return document;
                }

                private static XmlNode GetNodeInternal(
                                        ICustomElement customElement,
                                        XmlDocument document)
                {
                        if (customElement != null)
                        {
                                XmlNode node = GetElementInternal(customElement, document);
                                for (int i = 0; i < customElement.GetChildren().Count; i++)
                                {
                                        XmlNode childNode =
                                                GetNodeInternal(
                                                        customElement.GetChildren()[i] as
 ICustomElement, document
                                                );

                                        if (childNode != null)
                                        {
                                                node.AppendChild(document.CreateWhitespace
("\r\n"));
                                                node.AppendChild(childNode);
                                                node.AppendChild(document.CreateWhitespace
("\r\n"));
                                        }
                                }
                                return node;
                        }
                        else
                        {
                                return null;
                        }
                }

                private static XmlElement GetElementInternal(
ICustomElement customElement,
XmlDocument document)
                {
                        XmlElement element =
                                document.CreateElement(customElement.GetElementName());

                        if (customElement.GetElementAttributes() != null)
                        {
                                IEnumerator e =
                                        customElement.GetElementAttributes().Keys
.GetEnumerator();
                                while (e.MoveNext())
                                {
                                        XmlAttribute attribute =

document.CreateAttribute(e.Current.ToString());
                                        attribute.Value =
        customElement.GetElementAttributes()[e.Current].ToString();
                                        element.Attributes.Append(attribute);
                                }
                        }
                        if (customElement.GetElementInnerText() != "")
                        {
                                element.InnerText = customElement.GetElementInnerText();
                        }
                        return element;
                }
        }

        public interface ICustomElement
        {
                string GetElementName();
                IDictionary GetElementAttributes();
                string GetElementInnerText();
                IList GetChildren ();
                void AddChild (ICustomElement customElement);
        }

        public abstract class CustomElement : ICustomElement
        {
                public abstract string GetElementName();
                public virtual IDictionary GetElementAttributes()
                {
                        return null;
                }
                public virtual string GetElementInnerText()
                {
                        return "";
                }
                public IList GetChildren ()
                {
                        return _customElements;
                }
                public void AddChild (ICustomElement customElement)
                {
                        if (customElement != null)
                        {
                                _customElements.Add(customElement);
                        }
                }
                private IList _customElements = new ArrayList();
        }

        public class Companies : CustomElement, ICustomElement
        {
                public override string GetElementName()
                {
                        return "companies";
                }
        }

        public class Company : CustomElement, ICustomElement
        {
                public Company (string name)
                {
                        _name = name;
                }

                public override string GetElementName()
                {
                        return "company";
                }

                public override IDictionary GetElementAttributes()
                {
                        IDictionary attributes = new Hashtable();
                        attributes.Add("name", _name);
                        return attributes;
                }

                private string _name;
        }

        public class CellPhones : CustomElement, ICustomElement
        {
                public override string GetElementName()
                {
                        return "cell-phones";
                }
        }

        public class CellPhone : CustomElement, ICustomElement
        {
                public CellPhone (string name, int year) : this(name, year, "")
                {
                }

                public CellPhone (string name, int year, string description)
                {
                        _name = name;
                        _year = year;
                        _description = description;
                }

                public override string GetElementName()
                {
                        return "cell-phone";
                }

                public override IDictionary GetElementAttributes()
                {
                        IDictionary attributes = new Hashtable();
                        attributes.Add("name", _name);
                        attributes.Add("year", _year);
                        return attributes;
                }

                public override string GetElementInnerText()
                {
                        return _description;
                }

                private string _name, _description;
                private int _year;
        }

        public class DOMSample
        {
                [STAThread]
                static void Main(string[] args)
                {
                        XmlDocument document = CustomFactory.GetDocument(GetCompanies());
                        Console.WriteLine(document.OuterXml);
                }

                private static ICustomElement GetCompanies ()
                {
                        Companies companies = new Companies();
                        Company company = new Company("Siemens");
                        CellPhones cellPhones = new CellPhones();
                        CellPhone cellPhone =
                                new CellPhone("MC-60", 2003, "Some Description of
MC-60 cell phone");
                        cellPhones.AddChild(cellPhone);
                        company.AddChild(cellPhones);
                        companies.AddChild(company);
                        return companies;
                }
        }
}

The preceding example is based on the XML structure shown in Listing 8.2, which enables you to build XML structures that contain only four tags: companies, company, cell-phones, and cell-phone. This XML structure defines a set of companies that sell different models of cell phones. (The company and cell-phone tags have additional attributes, such as name, year, and so forth.)

Listing 8.2. XML Sample
<companies>
        <company name = "Siemens">
                <cell-phones>
                      <cell-phone name="MC60" year="2003">Some description of phone
                </cell-phone>
                </cell-phones>
        </company>
</companies>

Creating an XML Document

As you can see, all XML elements (such as comments, nodes, attributes, and so on) can be created only in the context of the XML document. For example, you cannot create an instance of the XmlAttribute class by using its constructor. Instead, you must use the CreateAttribute method of the XmlDocument class and pass to it the name of the attribute. Because this attribute is available only in the context of the document that created it, it is not possible to add this attribute to an element that has been created in another document.

The following code snippet demonstrates how to create an XML document:

XmlDocument document = new XmlDocument();

After the XML document has been created, you can populate it manually (as shown in Listing 8.1) or load a prepared XML from a string or file. The following list shows the most commonly used methods that can be used to create XML manually.

  • CreateAttribute Creates an XmlAttribute with the specified name

  • CreateComment Creates an XmlComment containing the specified data

  • CreateElement Creates an element with the specified name

  • CreateNode Creates an XmlNode with the specified node type, Name, and NamespaceURI

  • CreateCDataSection Creates an XmlCDataSection containing the specified data

  • CreateWhitespace Creates an XmlWhitespace node

After you have created one of these XML elements, you can assign it to another element (add it to the children list). By using the Create() and AppendChild() methods, you can create XML that is located in memory. After this XML has been created, you could browse this XML, search for elements, or remove elements. In addition, you could also save this XML to a file or any other data storage medium.

To load XML into XmlDocument from a string, you should use the XmlDocument.LoadXml() method. This method takes as its only parameter the string containing the XML. By default, the LoadXml() method does not preserve either white space or significant white space. Also, this method does not perform data type definition (DTD) or schema validation. If you need this validation to occur, use the Load method and pass it an XmlValidatingReader.

By using the XmlDocument.Load() method, you can load an XML document from a file, stream, URL, Textreader, or XmlReader and always preserve significant white space.

Working with XML Nodes, Elements, and Attributes

The XmlNode, XmlElement, and XmlAttribute classes are some of the most important in the XML DOM. Both the XmlElement and XmlAttribute classes are inherited from the XmlNode class. The XmlElement class can contain the following child node types: Element, Text, Comment, ProcessingInstruction, CDATA, and EntityReference. In addition, it can be the child of a Document, DocumentFragment, EntityReference, or Element nodes. This class enables you to add and remove children and attributes, traverse and search child nodes, get and set inner text, and more.

The XmlAttribute class can contain either the Text or EntityReference nodes. Because it is not considered a child node, the Attribute node does not appear as the child node of any other node type. The XmlAttribute node enables you to perform all actions defined in the XmlNode class; however, with only a limited set of node types. For example, you cannot add XmlDeclaration as a child to the attribute.

Earlier in this chapter, Listing 8.1 showed you how to work with the XmlAttribute, XmlNode, and XmlElement classes. This was demonstrated in the methods CustomFactory.GetNodeInternal and CustomFactory.GetElementInternal.

Persisting the DOM

The simplest way to persist XML is to save it to a file on a disk. You can accomplish this by invoking the XmlDocument.Save() method. For example:

document.Save("c:\some.xml");

You can also use both the WriteTo() and WriteContentTo() methods to store XML. The main difference between these methods is that the WriteTo() method saves the whole element into the destination, whereas the WriteContentTo() method saves only the children of the element for which the WriteContentTo() method was invoked.

Both of these methods enable you to store XML into an instance of an XmlWriter, which allows you to store information into a file, TextWriter, or stream. The following code snippet demonstrates how to use the WriteTo() method:

XmlDocument document = new XmlDocument();
XmlTextWriter writer = new XmlTextWriter(Console.Out);
document.WriteTo(writer);

NOTE

Because the WriteTo() method is defined in the XmlNode class, it is supported by all XML elements. In contrast, the Save() method is available only in the XmlDocument class.


    Team LiB
    Previous Section Next Section