# XML Processing

> Load XML files with DTD and CSS into a Windows Forms TextControl, handle XmlInvalid, edit elements with GetXmlElements and the ButtonBar, and save XML and CSS.

- **Product:** TX Text Control .NET for Windows Forms
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for Windows Forms > Document Processing > XML Processing
- **4091 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/xml/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/xml/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/xml/llms-full.txt

---

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](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/overview/editions/llms-full.txt) 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](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/data-sources/json-xml/llms-full.txt).

### How XML, DTD and CSS Work Together

Three files are involved. The XML file names its stylesheet and its DTD in its first lines:

```xml
<?xml version="1.0"?>
<?XML:stylesheet type="text/css" href="address.css"?>

<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:

```text
<!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:

```css
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:

![The XML address list loaded into a TextControl and shown as a table with one row per address, as the CSS file defines.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/xml-addresses-css-table.764e3827.webp)

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:

```css
name { display: block; font-size: 14pt; color: blue }
street, city, email { display: list-item; font-size: 11pt }
```

![The same XML address list shown with another CSS file: each name as a blue heading, followed by the street, city and email as a bulleted list.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/xml-addresses-css-list.15644677.webp)

### Load an XML File

An XML file is loaded like any other document, with [StreamType](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/streamtype/enumeration/llms-full.txt) `XMLFormat`:

```csharp
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](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/xmleditmode-property/llms-full.txt) is `Validate`.
- **Invalid.** The file breaks a rule of the DTD. [XmlInvalid](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/xmlinvalid-event/llms-full.txt) occurs, and the document is still loaded, but as a normal document without validation.
- **Not well-formed.** The file contains invalid XML syntax. [XmlNotWellFormed](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/xmlnotwellformed-event/llms-full.txt) occurs, and the document is not loaded.

Both events pass an [XmlErrorEventArgs](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlerroreventargs/llms-full.txt) with the [Reason](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlerroreventargs/reason-property/llms-full.txt), the [LineNumber](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlerroreventargs/linenumber-property/llms-full.txt), the [LinePosition](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlerroreventargs/lineposition-property/llms-full.txt), the [FilePosition](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlerroreventargs/fileposition-property/llms-full.txt) and the [URL](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlerroreventargs/url-property/llms-full.txt) 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](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/formattingstylesdialog-method/llms-full.txt) and the [InlineStyles](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/inlinestyles-property/llms-full.txt) and [ParagraphStyles](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/paragraphstyles-property/llms-full.txt) 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.Load` and `Selection.Save` don'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](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/buttonbar/llms-full.txt) has three combo boxes for XML documents, which your application adds to it through [ButtonPositions](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/buttonbar/buttonpositions-property/llms-full.txt): `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:

```csharp
private void Form1_Shown(object sender, EventArgs e)
{
    buttonBar1.ButtonPositions = new TXTextControl.Button[] {
        TXTextControl.Button.StyleComboBox,
        TXTextControl.Button.XMLAddElementComboBox,
        TXTextControl.Button.XMLRemoveElementComboBox };
}
```

![A TextControl with an XML address list and a button bar whose second combo box lists the elements address_record, street and city that can be inserted.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/xml-insert-element.a53c073a.webp)

### Read and Change Elements in Code

[GetXmlElements](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/getxmlelements-method/llms-full.txt) returns an [XmlElementCollection](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlelementcollection/llms-full.txt) with all elements of one name, as [XmlElement](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlelement/llms-full.txt) 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*:

```csharp
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](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlelementcollection/getitem-method/llms-full.txt) takes a one-based index and returns `null` if there is no such element. Without a parameter, it returns the element at the input position. Instead of `foreach`, a loop can count from 1 to [Count](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlelementcollection/count-property/llms-full.txt) and call `GetItem(i)`.
- [XmlElement.Text](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlelement/text-property/llms-full.txt) gets or sets the text. For an element with sub-elements, the new text needs one line per sub-element.
- The [XmlElement constructor](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlelement/constructor/llms-full.txt) takes the element name and, optionally, its text.
- [XmlElementCollection.Add](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlelementcollection/add-method/llms-full.txt) 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 `false` and raises `XmlInvalid` if the document would become invalid.

[XmlElementCollection.Remove](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlelementcollection/remove-method/llms-full.txt) removes the element with a one-based index, and 0 the one at the input position. [XmlElement.AddChild](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlelement/addchild-method/llms-full.txt), [GetChildItem](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlelement/getchilditem-method/llms-full.txt) and [RemoveChild](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/xmlelement/removechild-method/llms-full.txt) 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`:

```csharp
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](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/stylesheets/llms-full.txt): the formatting styles that XML documents use.
- [Loading Documents](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/loading/llms-full.txt): the other formats `Load` reads.
- [JSON and XML](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/data-sources/json-xml/llms-full.txt): use XML as data for a mail merge.
- [Toolbars and Mini Toolbars](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/ribbon-ui/toolbars/llms-full.txt): the button bar and its buttons.

---

## Nearby

- **Previous:** [Comments and Tracked Changes](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/comments-changes/llms-full.txt)
- **Next:** [Printing](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-processing/printing/llms-full.txt)
