---
title: Creating form controls with XML values
related:
  - https://docs.kentico.com/13/custom-development/extending-the-administration-interface/developing-form-controls.md
  - https://docs.kentico.com/13/custom-development/extending-the-administration-interface/developing-form-controls/example-developing-custom-form-controls.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

When developing complex [form controls](https://docs.kentico.com/13/custom-development/extending-the-administration-interface/developing-form-controls.md) consisting of multiple input elements, you can use values in [XML](http://en.wikipedia.org/wiki/XML) format to save the resulting data into form fields. XML allows you to store structured data that can be processed by APIs and is also readable by humans.

Xperience provides the following recommendations and API methods to help you correctly create form controls with XML values:

- When adding XML elements manually (for example via the [XmlDocument.CreateElement](https://msdn.microsoft.com/en-us/library/fw1ys7w6%28v=vs.100%29.aspx), [XmlElement.AppendChild](https://msdn.microsoft.com/en-us/library/system.xml.xmlnode.appendchild%28v=vs.100%29.aspx) or [PrependChild](https://msdn.microsoft.com/en-us/library/system.xml.xmlnode.prependchild%28v=vs.100%29.aspx) methods), make sure that the _**element order is always consistent**_ in the resulting XML document.
- To add attributes to elements, call the **XmlElement.AddAttributes** extension method, which ensures that all attributes are always in alphabetical order (based on the attribute names).
- When creating child elements based on dynamic data, prepare an _IDictionary_ collection containing the required values, and call the **XmlElement.AddChildElements** extension method. The method ensures that the child elements are ordered alphabetically based on their element names.
- Call the **XmlDocument.ToFormattedXmlString** extension method on the resulting XML document to convert the XML data to a string that can be saved as the form control's value. The method provides whitespace formatting, including line breaking and indentation for each XML element.
- Once the form control is developed and registered in the system, use the **Long text** data type for form fields where you plan to use the control.

> **Note:** **Note**: The _XmlElement.AddAttributes_, _XmlElement.AddChildElements_ and _XmlDocument.ToFormattedXmlString_ extension methods are provided within the **CMS.Helpers** library.

The steps above ensure that the XML data is formatted correctly and has consistent order. Consistency is important to allow easy comparison and change tracking in object data, particularly when objects containing fields with values provided by the form control are serialized (for example during [Export](https://docs.kentico.com/13/deploying-websites/exporting-and-importing-sites/exporting-objects.md), [Staging](https://docs.kentico.com/13/deploying-websites/content-staging.md) or [Object versioning](https://docs.kentico.com/13/configuring-xperience/working-with-object-versioning.md)).

> **Info:** **Other data formats**
>
> If your form control saves its value in a different structured data format than XML (for example JSON), you need to ensure the consistency of the data manually.

## Example

The following example demonstrates how to create a [form control](https://docs.kentico.com/13/custom-development/extending-the-administration-interface/developing-form-controls.md) that consists of multiple internal controls and saves the resulting data into an XML value. The sample control allows users to:

- Select an animal type from a list of predefined options
- Enter a species name
- Mark continents that the animal inhabits

> **Info:** **Form control implementation options**
>
> This example implements the custom form control as a Web user control (.ascx file) within the Xperience administration project. You can alternatively create form controls by adding a control class to a separate assembly (the class must also inherit from the _FormEngineUserControl_ base class).

> **Note:** **Note**: For the sake of simplicity, the example only provides the most basic implementation (without sufficient input validation, error handling, etc.).

1. Open your web project in Visual Studio (using the **WebApp.sln** file).
2. Right-click the **CMSFormControls** folder and choose **Add -> Add New Item**.
3. Create a new **Web User Control**, for example named _CustomAnimals.ascx_.
4. Add the following input controls into the user control's markup:

   ```xml

   <asp:DropDownList ID="drpAnimalType" runat="server"></asp:DropDownList>
   <asp:TextBox ID="txtSpecies" runat="server"></asp:TextBox>
   <asp:CheckBoxList ID="checkContinents" runat="server"></asp:CheckBoxList>

   ```
5. Switch to the code behind, add the following _using_ statements, and adjust the class declaration so that the control inherits from **FormEngineUserControl**:

   ```csharp

   using System;
   using System.Collections.Generic;
   using System.Web;
   using System.Xml;
   using System.Web.UI;
   using System.Web.UI.WebControls;

   using CMS.FormEngine.Web.UI;
   using CMS.Helpers;

   public partial class CMSFormControls_CustomAnimals : FormEngineUserControl
   {
   }

   ```
6. Add the following members into the class:

   ```csharp

   /// <summary>
   /// Gets or sets the value of the field, in this case XML data stored in string format.
   /// </summary>
   public override object Value
   {
       get
       {
           // Gets XML data in string format based on the values of the internal controls
           return GetXmlString();
       }
       set
       {
           // Gets the field's value as a string
           string strValue = ValidationHelper.GetString(value, string.Empty);

           // Sets up the drop-down and checkbox items of the control (occurs for new forms when attempting to set the default field value)
           EnsureItems();

           if (!string.IsNullOrEmpty(strValue))
           {
               // Creates an XmlDocument based on the field's value
               XmlDocument xmlValue = new XmlDocument();
               xmlValue.LoadXml(strValue);  

               // Sets values for the internal controls based on the XML data
               SetValuesFromXml(xmlValue);
           }
       }
   }    

   /// <summary>
   /// Sets up the items of the internal drop-down list and checkboxes.
   /// </summary>
   private void EnsureItems()
   {        
       if (drpAnimalType.Items.Count == 0)
       {
           drpAnimalType.Items.Add(new ListItem("Birds", "Birds"));
           drpAnimalType.Items.Add(new ListItem("Bees", "Bees"));
           drpAnimalType.Items.Add(new ListItem("Marsupials", "Marsupials"));
       }

       if (checkContinents.Items.Count == 0)
       {
           checkContinents.Items.Add(new ListItem("Africa"));
           checkContinents.Items.Add(new ListItem("North America"));
           checkContinents.Items.Add(new ListItem("South America"));
           checkContinents.Items.Add(new ListItem("Asia"));
           checkContinents.Items.Add(new ListItem("Europe"));
           checkContinents.Items.Add(new ListItem("Australia"));
           checkContinents.Items.Add(new ListItem("Antarctica"));
       }
   }

   /// <summary>
   /// Returns a string containing XML data based on the values of the internal controls.
   /// </summary>
   private string GetXmlString()
   {
       // Creates a new XML document
       XmlDocument xmlDoc = new XmlDocument();

       // Creates an animal XML element
       XmlElement xmlAnimal = xmlDoc.CreateElement("animal");

       // Prepares attributes for the animal element
       var animalAttributes = new Dictionary<string, string>
       {
           {"type", drpAnimalType.SelectedValue},
           {"species", txtSpecies.Text}
       };

       // Adds the attributes to the animal element (ensures consistent alphabetical order)
       xmlAnimal.AddAttributes(animalAttributes);

       // Adds the animal element as the root of the XML document
       xmlDoc.AppendChild(xmlAnimal);

       // Prepares a dictionary of child elements
       var continentElements = new Dictionary<string, bool>();
       foreach (ListItem item in checkContinents.Items)
       {
           continentElements.Add(item.Text.Replace(" ", string.Empty), item.Selected);
       }

       // Creates child elements under the animal element
       xmlAnimal.AddChildElements(continentElements);

       // Ensures line breaks and indentation formatting for the XML text, omits the XML declaration
       return xmlDoc.ToFormattedXmlString(true);
   }

   /// <summary>
   /// Sets up the internal controls based on data from an XmlDocument.
   /// </summary>
   private void SetValuesFromXml(XmlDocument xmlValue)
   {
       // Sets the animal type value based on the type attribute of the animal element
       drpAnimalType.SelectedValue = System.Convert.ToString(xmlValue["animal"].Attributes["type"].Value);

       // Sets the species name based on the species attribute of the animal element (if it has a value)
       if (xmlValue["animal"].HasAttribute("species"))
       {
           txtSpecies.Text = System.Convert.ToString(xmlValue["animal"].Attributes["species"].Value);
       }

       // Sets the continent checkboxes based on the child elements under the animal element
       foreach (ListItem item in checkContinents.Items)
       {
           item.Selected = System.Convert.ToBoolean(xmlValue["animal"][item.Text.Replace(" ", string.Empty)].InnerText);
       }
   }

   ```
7. Save the control's files and **Rebuild** your solution.

To register the form control in the system:

1. Sign in to the Xperience administration interface.
2. Open the **Administration interface** application and switch to the **Form controls** tab.
3. Click **New form control**.
4. Enter the following values:
   - **Control source**: Web user control
   - **Display name**: Animals XML
   - **Code name**: Leave the _(automatic)_ value
   - **File name**: \~/CMSFormControls/CustomAnimals.ascx (you can click **Select** to choose the file)
5. Click **Save**.
6. On the **General** tab, set the **Control scope**:
   - Use control for: **Long text**
   - Show control in: Any required options
7. Click **Save**.

You can now assign the form control to form fields with the _Long text_ data type.

![The custom animal form control as it appears inside an editing form](https://docs.kentico.com/docsassets/13/creating-form-controls-with-xml-values/custom_xml_form_control.png "The custom animal form control as it appears inside an editing form")

The control saves the user input into XML data, and ensures consistent alphabetical order of attributes and child elements. For example, a field using the _Animals XML_ control would have the following value for the input shown in the screenshot above:

```xml

<animal species="Swallow" type="Birds">
  <Africa>True</Africa>
  <Antarctica>False</Antarctica>
  <Asia>True</Asia>
  <Australia>True</Australia>
  <Europe>True</Europe>
  <NorthAmerica>True</NorthAmerica>
  <SouthAmerica>True</SouthAmerica>
</animal>

```
