Category Archives: XML

Changing a value within an XML document using F#

I needed to simulate some user interaction with our webservices in an automated manner. This post is specific to one small part of this requirement – here we’re going to simply take some XML and change a value within the data and return this altered data.

The code is very simple but demonstrates how to deal with namespaces as well as using XmlDocument and XPath.

Note: I’m using XmlDocument here and XPath for simplicity but obviously this is not the most performant on large documents.

Reading and/or writing xsd files

I wanted to look at reading an xsd (XML schema) file and generate C# source from it in a similar way to xsd.exe.

As XML schema is itself XML I first looked at writing the code using an XmlReader, but whilst this might be an efficient mechanism for reading the file, it’s a bit of a pain to write the code to process the elements and attributes. So what’s the alternative ?

Well there is actually a much simpler class that we can use named XmlSchema which, admittedly, will read the xsd into memory, but I’m not currently looking at performance being an issue.

Note: I’m going to deal with XmlSchema as a reader but there’s a good example of using it to write an XML schema at XmlSchema Class

Here’s a quick example of reading a stream (which contains an XML scherma)

using (XmlReader reader = new XmlTextReader(stream))
{
   XmlSchema schema = XmlSchema.Read(reader, (sender, args) =>
   {
      Console.WriteLine(args.Message);
   });
   // process the schema items etc. here
}

The Console.WriteLine(args.Message) code is within a ValidationEventHandler delegate which is called when syntax errors are detected.

Once we successfully get an XmlSchema we can interact with it’s Items, for example here some code which is intended loop through all complex types and then process the elements and attributes within each complex type

foreach (var item in schema.Items)
{
   XmlSchemaComplexType complexType = item as XmlSchemaComplexType;
   if (complexType != null)
   {
      XmlSchemaSequence sequence = complexType.Particle as XmlSchemaSequence;
      if (sequence != null)
      {
         foreach (var seqItem in sequence.Items)
         {
            XmlSchemaElement element = seqItem as XmlSchemaElement;
            if (element != null)
            {
               // process elements
            }
         }		
      }
      foreach (var attributeItem in complexType.Attributes)
      {
         XmlSchemaAttribute attribute = attributeItem as XmlSchemaAttribute;
         if (attribute != null)
         {
            // process attributes
         }
      }
   }
}

How to, conditionally, stop XML serializing properties

Let’s assume we have this simple C# class which represents some XML data (i.e. it’s serialized to XML eventually)

[XmlType(AnonymousType = true)]
public partial class Employee
{
   [XmlAttribute(AttributeName = "id")]
   public string Id { get; set; }

   [XmlAttribute(AttributeName = "name")]
   public string Name { get; set; }

   [XmlAttribute(AttributeName = "age")]
   public int Age { get; set; }
}

Under certain circumstances we may prefer to not include elements in the XML if the values are not suitable.

We could handle this is a simplistic manner by setting a DefaultValueAttribute on a property and obviously the data will not be serialized unless the value differs from the default, but this is not so useful if you wanted more complex functionality to decide whether a value should be serialized or not, for example what if we don’t want to serialize Age if it’s less than 1 or greater than 100. Or not serialize Name if it’s empty, null or the string length is less than 3 characters and so on.

ShouldSerializeXXX

Note: You should not use ShouldSerializeXXX method and the DefaultValueAttribute on the same property

So, we can now achieve this more complex logic using the ShouldSerializeXXX method. If we create a partial class (shown below) and add the ShouldSerializName method we can tell the serializer to not bother serializing the Name property under these more complex circumstances

public partial class Employee
{
   public bool ShouldSerializeName()
   {
      return !String.IsNullOrEmpty(Name) || Name.Length < 3;
   }
}

When serializing this data the methods are called by the serializer to determine whether a property should be serialized and obviously if it should not be, then the element/attribute will not get added to the XML.

Generating classes from XML using xsd.exe

The XML Schema Definition Tool (xsd.exe) can be used to generate xml schema files from XML and better still C# classes from xml schema files.

Creating classes based upon an XML schema file

So in it’s simplest usage we can simply type

xsd person.xsd /classes

and this generates C# classes representing the xml schema. The default output is C# but using the /language or the shorter form /l switch we can generate Visual Basic using the VB value, JScript using JS or CS if we wanted to explicitly static the language was to be C#. So for example using the previous command line but now to generate VB code we can write

xsd person.xsd /classes /l:VB

Assuming we have an xml schema, person.xsd, which looks like this

<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Person" nillable="true" type="Person" />
  <xs:complexType name="Person">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="1" name="FirstName" type="xs:string" />
      <xs:element minOccurs="0" maxOccurs="1" name="LastName" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="Age" type="xs:int" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

The class created (in C#) looks like the following (comments removed)

[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=true)]
public partial class Person {
    
    private string firstNameField;
    
    private string lastNameField;
    
    private int ageField;
    
    public string FirstName {
        get {
            return this.firstNameField;
        }
        set {
            this.firstNameField = value;
        }
    }
    
    public string LastName {
        get {
            return this.lastNameField;
        }
        set {
            this.lastNameField = value;
        }
    }
    
    public int Age {
        get {
            return this.ageField;
        }
        set {
            this.ageField = value;
        }
    }
}

Creating an XML schema based on an XML file

It might be that we’ve got an XML file but no xml schema, so we’ll need to convert that to an xml schema before we can generate our classes file. Again we can use xsd.exe

xsd person.xml

the above will create an xml schema based upon the XML file, obviously this is limited to what is available in the XML file itself, so if your XML doesn’t have “optional” elements/attributes xsd.exe obviously cannot include those in the schema it produces.

Assuming we therefore started with an XML file, the person.xml, which looks like the following

<?xml version="1.0" encoding="utf-8"?>

<Person>
   <FirstName>Spoungebob</FirstName>
   <LastName>Squarepants</LastName>
   <Age>21</Age>
</Person>

Note: I’ve no idea if that is really SpongeBob’s age.

Running xsd.exe against person.xml file we get the following xsd schema

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="Person">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="FirstName" type="xs:string" minOccurs="0" />
        <xs:element name="LastName" type="xs:string" minOccurs="0" />
        <xs:element name="Age" type="xs:string" minOccurs="0" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element ref="Person" />
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>

From this we could now create our classes as previously outlined.

Creating an xml schema based on .NET type

What if we’ve got a class/type and we want to serialize it as XML, let’s use xsd.exe to create the XML schema for us.

If the class looks like the following

public class Person
{
   public string FirstName { get; set; }
   public string LastName { get; set; }
   public int Age { get; set; }
}
[code]

<em>Note: Assuming the class is compiled into an assembly call DomainObjects.dll</em>

Then running xsd.exe with the following command line

[code language="xml"]
xsd.exe DomainObjects.dll /type:Person

will then generate the following xml schema

<?xml version="1.0" encoding="utf-8"?>
<xs:schema elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Person" nillable="true" type="Person" />
  <xs:complexType name="Person">
    <xs:sequence>
      <xs:element minOccurs="0" maxOccurs="1" name="FirstName" type="xs:string" />
      <xs:element minOccurs="0" maxOccurs="1" name="LastName" type="xs:string" />
      <xs:element minOccurs="1" maxOccurs="1" name="Age" type="xs:int" />
    </xs:sequence>
  </xs:complexType>
</xs:schema>

You’ll notice this is slightly different from the code generated from the person.xml file.