Working with XML Files

Loading and Saving XML Files

TX Text Control offers several built-in features to edit and to manipulate XML files. XML files can be loaded and saved like all other files using the Load and Save methods.

When an XML file is loaded TX Text Control considers the corresponding document type description file (DTD) and checks the document for validity. If the document is invalid (which means that it does not fulfill the rules in the DTD), a TextControl.XmlInvalid event occurs. However, the document's text including its formatting styles is still loaded. The document can then be edited as a normal text document with all the editing features TX Text Control offers.

Otherwise, if the document is valid according to the corresponding DTD, Text Control loads the document's text and formatting styles and switches to a special XML editor mode which guarantees that the document remains valid during editing. This article describes how the XML editor mode works and how an application can manipulate an XML document. The TextControl.XmlEditMode property informs about the state of the XML editor.

If an XML document is not well-formed (which means that it contains invalid XML syntax) a TextControl.XmlNotWellFormed event occurs and the document is not loaded. Both the XmlInvalid and the XmlNotWellFormed event informs the application about the positon in the file where the error occurs and the cause of the error.

During loading, a Text Control looks for corresponding formatting styles contained in a CSS file. If such a file is found, the styles are loaded and all formatting attributes are displayed. All further editing and manipulation of the XML document can be performed in WYSIWYG mode.

Because an XML document becomes invalid if it is inserted into another existing document, XML documentscannot be loaded or saved with the Selection.Load and the Selection.Save methods.

If an XML document is saved using the TextControl.Save method, only the document's text is saved to the XML file. To save the document's formatting styles to the corresponding CSS file, a second call of the TextControl.Save method must be performed. Changing and saving the document's DTD is not supported. Neither is it supported to create completely new XML documents.

Editing XML Files

XML documents consist of elements. Some of these elements contain the document's text, other elements represent the document's structure. Consider the following XML document that contains a list of addresses:

<?xml version="1.0"?>
<?XML:stylesheet type="text/css" href="addresses.css"?>
<!DOCTYPE Addresses SYSTEM "addresses.dtd">
<Addresses>
   <DocumentHeadline>Addresses</DocumentHeadline>
   <AddressTable>
      <Address>
         <Name>Jack Miller</Name>
         <Street>Baker Street</Street>
         <City>New York</City>
      </Address>
      <Address>
         <Name>Tom Baker</Name>
         <Street>Miller Street</Street>
         <City>Los Angeles</City>
      </Address>
      <Address>
         <Name>Bill Taylor</Name>
         <Street>Old Street</Street>
         <City>Washington</City>
      </Address>
   </AddressTable>
</Addresses>

In this example, the elements DocumentHeadline, Name, Street and City contain the document's text, the other elements Addresses, AddressTable and Address are structural elements without any text. After this document has been loaded, a Text Control displays it WYSIWYG with the formatting styles found in the specified CSS file and automatically switches to the XML editor mode. In this mode, text can be inserted or deleted like in any other document. Text selections are possible only inside single XML elements. If a user tries to select more than one element, the selection is expanded to its maximum, which is the complete text of the single element.

Like in tables, the TAB (Shift TAB) key can be used to select the complete text of the next (previous) element. Clipboard operations are possible as in any other document, but if text is inserted from another document, it is inserted without any formatting attributes.

Because XML documents do not contain formatting attributes they can be changed only via formatting styles. Formatting via the Button Bar changes the attributes of the current style. Formatting via formatting functions is disabled in XML documents. To change formatting attributes either the built-in style dialog boxes available through the TextControl.FormattingStylesDialog method or the InlineStyle and the ParagraphStyle collections can be used. To make these changes permanent, the new attributes must explicitly be saved in the CSS file.

Programming XML Documents

TX Text Control exposes the elements of an XML document through collections of XmlElement objects. The TextControl.GetXmlElements property returns an element collection. There is one collection for each kind of elements. In the example document above there is a collection for all Address elements and another collection for all Name elements. The following line of code gets the collection of the Name elements:

XmlElementCollection nameElements = textControl1.GetXmlElements("Name");
Dim NameElements As XmlElementCollection
NameElements = TextControl1.GetXmlElements("Name")

The collection object has the XmlElementCollection.GetItem method to access a single element. With the XmlElement.Text method, the following line of code displays the content of the second Name element:

Console.WriteLine(nameElements.GetItem(2).Text);
Console.WriteLine(NameElements.GetItem(2).Text)

The contents of elements containing sub-elements is the complete text of all sub-elements separated through new line characters (character value 10). For example the line of code:

Console.WriteLine(textControl1.GetXmlElements("Address").GetItem(2).Text);
Console.WriteLine(TextControl1.GetXmlElements("Address").GetItem(2).Text)

in the example above displays:

Tom Baker
Miller Street
Los Angeles

To set a new text with the Text property, the specified text string must be separated through new line characters:

textControl1.GetXmlElements("Address").GetItem(2).Text
    = "Paul Baskerville
Jackson Street
London";
TextControl1.GetXmlElements("Address").GetItem(2).Text() _
    = "Paul Baskerville" + Chr(10) + "Jackson Street" + Chr(10) + "London"

With a For Each statement a program can iterate through an XML element collection. The following example displays all names:

foreach (XmlElement element in textControl1.GetXmlElements("Name")) {
    Console.WriteLine(element.Text);
}
Dim NameElement As XmlElement
For Each NameElement In TextControl1.GetXmlElements("Name")
   Console.WriteLine(NameElement.Text)
Next NameElement

This code is equivalent to the following code using the collection's Count property:

XmlElementCollection nameElements = textControl1.GetXmlElements("Name");
for (int i = 1; i <= nameElements.Count; i++) {
    Console.WriteLine(nameElements.GetItem(i).Text);
}
Dim I As Integer
Dim NameElements As XmlElementCollection
NameElements = TextControl1.GetXmlElements("Name")
For I = 1 To NameElements.Count
   Console.WriteLine(NameElements.GetItem(I).Text)
Next I

An XML element collection also has an Add and a Remove method to insert or delete elements. These are explained in the following section.

Inserting and Deleting XML Elements

The structure of an XML document is described through a document type description (DTD) either contained inline, in the XML file or in a separate DTD file. The following is an example of a DTD file belonging to the XML example above (addresses.dtd):

<!ELEMENT Addresses (DocumentHeadline, AddressTable)>
<!ELEMENT DocumentHeadline (#PCDATA)>
<!ELEMENT AddressTable (Address+)>
<!ELEMENT Address (Name, Street, City)>
<!ELEMENT Name (#PCDATA)>
<!ELEMENT Street (#PCDATA)>
<!ELEMENT City (#PCDATA)>

A DTD allows text only for elements with the #PCDATA statement. Furthermore, this DTD defines thatthe document must have a single document headline and a single address table. The address table can have one or more addresses and each address must have three sub-elements: Name Street and City.

With all of these instructions, inserting or removing elements is allowed only for complete addresses. Should a program try to insert or remove one of the other elements, an invalid document and an XmlInvalid event occurs.

To insert an address, first create a new XmlElement object, initialize it with a name and a text and then use the Address collection's Add method as shown in the following piece of code:

XmlElement newAddress =
    new XmlElement("Address", "Paul Baskerville
Jackson Street
London");
textControl1.GetXmlElements("Address").Add(newAddress, -1, 2);
Dim NewAddress As New XmlElement("Address", _
        "Paul Baskerville" + Chr(10) + "Jackson Street" + Chr(10) + "London")
TextControl1.GetXmlElements("Address").Add(NewAddress, -1, 2)

This code inserts the new address after the second address in the document. Using the Add method's before parameter an element can also be inserted before a certain element.

The following line of code removes the address just inserted:

textControl1.GetXmlElements("Address").Remove(3);
TextControl1.GetXmlElements("Address").Remove(3)

Because the DTD enforces at least one address, trying to remove the last address also results in an invalid document and an XmlInvalid event occurs.