XML Processing
An XML file holds structured data without any formatting: an address list, a catalog, a set of records. TX Text Control loads such a file together with its document type definition (DTD), which defines the allowed elements, and a CSS stylesheet, which defines how the elements look. The TextControl then shows the data formatted as a document, lets users edit it while every change is checked against the DTD, and your code reads and changes the elements by name.
XML editing is part of the Enterprise edition, as Editions shows. The examples are handlers in Form1.cs with the TextControl named textControl1. This page is about XML documents edited as XML; XML as a data source for a mail merge is covered in JSON and XML.
How XML, DTD and CSS Work Together
Three files are involved. The XML file names its stylesheet and its DTD in its first lines:
<address>
<address_record>
<name>Paul</name>
<street>Baker Street</street>
<city>London</city>
<email>paul@hotmail.com</email>
</address_record>
<address_record>
<name>George</name>
<email>george@hotmail.com</email>
</address_record>
</address>
The DTD, address.dtd, says that an address consists of one or more records, each with a name, an optional street and city and an email address:
<!ELEMENT address ( address_record+ )>
<!ELEMENT address_record ( name, street?, city?, email )>
<!ELEMENT name (#PCDATA )>
<!ELEMENT street (#PCDATA )>
<!ELEMENT city (#PCDATA )>
<!ELEMENT email (#PCDATA )>
The DTD can also be contained inline, in the XML file itself, instead of in a file of its own. The examples on this page use the separate file.
The stylesheet, address.css, shows each record as a table row:
address { display: table }
address_record { display: table-row }
name, street, city, email { display: table-cell; border: 1px; font-size: 11pt }
Loaded into the TextControl, the addresses appear as a table:

Another stylesheet shows the same data differently. With the name as a blue heading and the other elements as list items, the file looks like this:
name { display: block; font-size: 14pt; color: blue }
street, city, email { display: list-item; font-size: 11pt }

Load an XML File
An XML file is loaded like any other document, with StreamType XMLFormat:
private void Form1_Load(object sender, EventArgs e)
{
textControl1.XmlInvalid += TextControl1_XmlInvalid;
textControl1.XmlNotWellFormed += TextControl1_XmlNotWellFormed;
}
private void openXmlButton_Click(object sender, EventArgs e)
{
textControl1.Load("address.xml", TXTextControl.StreamType.XMLFormat);
statusLabel.Text = textControl1.XmlEditMode == TXTextControl.XmlEditMode.Validate
? "Valid XML: changes are checked against the DTD"
: "Not validated";
}
private void TextControl1_XmlInvalid(object sender, TXTextControl.XmlErrorEventArgs e)
{
MessageBox.Show($"The document doesn't match its DTD: {e.Reason} (line {e.LineNumber}, position {e.LinePosition})");
}
private void TextControl1_XmlNotWellFormed(object sender, TXTextControl.XmlErrorEventArgs e)
{
MessageBox.Show($"The file isn't well-formed XML: {e.Reason} (line {e.LineNumber})");
}
What happens on loading depends on the file:
- Valid. The file matches its DTD. TX Text Control loads the text, applies the styles of the CSS file and switches to the XML editor mode: XmlEditMode is
Validate. - Invalid. The file breaks a rule of the DTD. XmlInvalid occurs, and the document is still loaded, but as a normal document without validation.
- Not well-formed. The file contains invalid XML syntax. XmlNotWellFormed occurs, and the document is not loaded.
Both events pass an XmlErrorEventArgs with the Reason, the LineNumber, the LinePosition, the FilePosition and the URL of the file; a value of 0 or an empty string means that the information isn't available. Connect Form1_Load to the Load event of the form, and add a Label named statusLabel.
textControl1.Load(TXTextControl.StreamType.XMLFormat) without a file name opens the Open dialog box with XML files only.
Edit in the XML Editor Mode
In the XML editor mode, TX Text Control keeps the document valid:
- Text only in text elements. Users type and delete text as in any document, but only in elements that hold text. A selection can't span several elements; it grows to the complete text of one element. TAB and SHIFT+TAB select the text of the next and the previous element, as in a table.
- Formatting through styles. XML has no formatting of its own, so formatting commands change the style of the current element. FormattingStylesDialog and the InlineStyles and ParagraphStyles collections change the styles in code.
- Pasted text is inserted without formatting.
- No partial loading. An XML document can't be inserted into another document, so
Selection.LoadandSelection.Savedon't work with XML.
Setting XmlEditMode to NoValidate turns validation off and makes the TextControl a normal editor. The document can then become invalid, so it can no longer be saved as XML. Validate can't be set; it is switched on by loading a valid XML file.
The ButtonBar has three combo boxes for XML documents, which your application adds to it through ButtonPositions: StyleComboBox shows the style of the current element, XMLAddElementComboBox inserts an element and XMLRemoveElementComboBox deletes one. Each insertion and deletion is checked against the DTD, so an element the DTD doesn't allow at the input position isn't inserted:
private void Form1_Shown(object sender, EventArgs e)
{
buttonBar1.ButtonPositions = new TXTextControl.Button[] {
TXTextControl.Button.StyleComboBox,
TXTextControl.Button.XMLAddElementComboBox,
TXTextControl.Button.XMLRemoveElementComboBox };
}

Read and Change Elements in Code
GetXmlElements returns an XmlElementCollection with all elements of one name, as XmlElement objects. The text of an element with sub-elements is the text of all sub-elements, separated by line feed characters (\n). The following handler lists all names, changes the second record and adds a new one; it needs using System.Text; at the top of Form1.cs:
private void editElementsButton_Click(object sender, EventArgs e)
{
// All name elements, in the order of the document
StringBuilder names = new StringBuilder();
foreach (TXTextControl.XmlElement name in textControl1.GetXmlElements("name"))
{
names.AppendLine(name.Text);
}
MessageBox.Show(names.ToString());
// Replace the text of the second record; its sub-elements are separated by \n
TXTextControl.XmlElementCollection records = textControl1.GetXmlElements("address_record");
records.GetItem(2).Text = "George\ngeorge@textcontrol.com";
// Insert a record after the second one; false if the DTD doesn't allow it
TXTextControl.XmlElement newRecord = new TXTextControl.XmlElement("address_record", "Ringo\nAbbey Road\nLondon\nringo@hotmail.com");
if (!records.Add(newRecord, -1, 2))
{
MessageBox.Show("The record couldn't be added.");
}
}
The code works as follows:
- XmlElementCollection.GetItem takes a one-based index and returns
nullif there is no such element. Without a parameter, it returns the element at the input position. Instead offoreach, a loop can count from 1 to Count and callGetItem(i). - XmlElement.Text gets or sets the text. For an element with sub-elements, the new text needs one line per sub-element.
- The XmlElement constructor takes the element name and, optionally, its text.
- XmlElementCollection.Add takes the element and a before and an after position in the collection; -1 ignores a position, 0 means the element at the input position. It returns
falseand raisesXmlInvalidif the document would become invalid.
XmlElementCollection.Remove removes the element with a one-based index, and 0 the one at the input position. XmlElement.AddChild, GetChildItem and RemoveChild work on the sub-elements of an element, and the DTD decides where a new sub-element goes. Like Add, these methods fail when the result would break the DTD, for example when the last required element would be removed.
Save the XML File and Its Styles
Save with StreamType.XMLFormat writes the text and the elements, but no formatting. The styles go into the CSS file in a second call, with StreamType.CascadingStylesheet:
private void saveXmlButton_Click(object sender, EventArgs e)
{
textControl1.Save("address.xml", TXTextControl.StreamType.XMLFormat);
// Formatting that users changed is saved in the stylesheet
textControl1.Save("address.css", TXTextControl.StreamType.CascadingStylesheet);
}
TX Text Control doesn't change or save the DTD, and it doesn't create new XML documents: it edits existing XML files that have a DTD.
Next Steps
- Stylesheets: the formatting styles that XML documents use.
- Loading Documents: the other formats
Loadreads. - JSON and XML: use XML as data for a mail merge.
- Toolbars and Mini Toolbars: the button bar and its buttons.