IntelliSense and Validation of Design-Time XML

I had an XML file that controlled much of my application and I wanted to be able to validate it and get some Intellisense to making edits a lot easier.  I  used XSD validation which works great for my design-time needs, but note that the Silverlight libraries don’t have the code to validate it at runtime.  This is fine for my current situation, but may be a problem later.

Here is how I got it working:

1. Add an XSD to the project (Add New Item -> XML Schema)

2. Visual Studio 2010 has a lot of tools for visualizing and reporting on the schema, but I found it easiest just to go to the editor by clicking "Use the XML Editor to view and edit the underlying XML schema file"

3. Build the XSD. Since I was new to XSD, a couple sites were pretty helpful. http://www.learn-xml-schema-tutorial.com/ and http://www.w3schools.com/Schema/ Below is a very simplistic XSD that requires the XML have a list of customers. Each customer will have a customerType attribute that has to be "internal" or "external", an optional firstName, and a required lastName.

Code Snippet
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <xs:schema id="MySchema"
  3.     targetNamespace="http://tempuri.org/MySchema.xsd"
  4.     elementFormDefault="qualified"
  5.     xmlns="http://tempuri.org/MySchema.xsd"
  6.     xmlns:mstns="http://tempuri.org/MySchema.xsd"
  7.     xmlns:xs="http://www.w3.org/2001/XMLSchema"
  8. >
  9.   <xs:element name="customers">
  10.     <xs:complexType>
  11.       <xs:sequence>
  12.         <xs:element name="customer" minOccurs="0" maxOccurs="unbounded">
  13.           <xs:complexType>
  14.             <xs:attribute name="customerType" use="required">
  15.               <xs:simpleType>
  16.                 <xs:restriction base="xs:string">
  17.                   <xs:enumeration value="internal" />
  18.                   <xs:enumeration value="external" />
  19.                 </xs:restriction>
  20.               </xs:simpleType>
  21.             </xs:attribute>
  22.             <xs:attribute name="firstName" use="optional" />
  23.             <xs:attribute name="lastName" use="required" />
  24.           </xs:complexType>
  25.           
  26.         </xs:element>
  27.       </xs:sequence>
  28.     </xs:complexType>
  29.     
  30.   </xs:element>
  31. </xs:schema>

4. On your XML file, go to the Properties window and edit Schemas.  You’ll need to browse to where your XSD is to associate it.

image

5.  Edit the root node of the XML file to use the right default namespace

<?xml version="1.0" encoding="utf-8" ?>
<customers xmlns="http://tempuri.org/MySchema.xsd">
</customers>

6.  Now Intellisense will work and help you enter the right values.  You’ll get compiler warnings if your XML does not conform to the schema

image

7.  There’s one complication with this – if you want to read the XML file in as an XDocument, you’ll now have to include the namespace when referencing the Nodes.  For example,  doc.Descendents(XName.Get(“customers”,”http://tempuri.org/MySchema.xsd”)).  To avoid this, I used some code from http://www.everydayinternetstuff.com/2009/12/default-namespace-for-linq-to-xml-query/ that will just strip the namespace info from the XML. 

Code Snippet
  1. /// <summary>
  2. /// Removes any namespaces prefixes from elements so we don't have
  3. /// to worry about them when querying.  The namespace is there for XSD validation before
  4. /// coming to us, but we really don't care about it.
  5. /// </summary>
  6. /// <param name="xdoc"></param>
  7. private void RemoveNamespace(XDocument xdoc)
  8. {
  9.     foreach (XElement e in xdoc.Root.DescendantsAndSelf())
  10.     {
  11.         if (e.Name.Namespace != XNamespace.None)
  12.         {
  13.             e.Name = XNamespace.None.GetName(e.Name.LocalName);
  14.         }
  15.  
  16.         if (e.Attributes().Where(a => a.IsNamespaceDeclaration || a.Name.Namespace != XNamespace.None).Any())
  17.         {
  18.             e.ReplaceAttributes(e.Attributes().Select
  19.                 (a => a.IsNamespaceDeclaration ? null : a.Name.Namespace != XNamespace.None ? new XAttribute(XNamespace.None.GetName(a.Name.LocalName), a.Value) : a));
  20.         }
  21.     }
  22.  
  23. }
Advertisements

3 thoughts on “IntelliSense and Validation of Design-Time XML

  1. Is there any way to go a step further than this and have the property grid (or some other mechanism) offer an equivalent to a UITypeEditor? For example imagine one of the attributes in the XML should contain a colour – I’d like a colour picker to pop up.

    I kind of thought vs:builder=”color” (from the intellisense namespace) might give possibilities, but that seems to be tied (as far as I can tell) to components.

    Any suggestions of alternatives approaches welcome?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s