Contents tagged with XML

  • Serializing ArrayLists of Disparate Objects to XML Strings

    In an earlier post here, I wrote two functions to Serialize and Deserialize objects to XML strings.

    Since then, while reading a book about XML, I learned of even more power in the .Net XML Serialization libraries*. In addition to serializing objects and collections of objects you can serialize ArrayLists which can contain disparate or non-homogeneous objects. Techno-babble translation: Disparate and non-homogenous mean 'different'.

    *BTW: Never stop learning or you'll end up as geek road-kill on the nerd highway.

    I wrote two functions (in XMLUtils namespace) to encapsulate the logic. What do these functions do? Why I'd be delighted to show you. Here's an example of the functions in action:

    ArrayList MyArrayList = new ArrayList();
     
    MyArrayList.Add(new MyNameSpace.MyClass("Sue"));
    MyArrayList.Add(DateTime.Now);
    MyArrayList.Add(new MyClass("Bob"));
    MyArrayList.Add(1234);
     
    Response.Write("----- Before serialization ------ <br />");
    foreach (Object O in MyArrayList)
        Response.Write(O.ToString() + "<br />"); 
     
    String MyXml = XMLUtils.SerializeArrayList(MyArrayList);    // Serialize  
     
    MyArrayList = XMLUtils.DeSerializeArrayList(MyXml);         // Deserialize
     
    Response.Write("----- After deserialization ------ <br />");
    foreach (Object O in MyArrayList)
        Response.Write(O.ToString() + "<br />");
     
    // Output:
    //        ----- Before serialization ------ 
    //        Sue
    //        1/5/2010 12:50:15 PM
    //        Bob
    //        1234
    //        ----- After deserialization ------ 
    //        Sue
    //        1/5/2010 12:50:15 PM
    //        Bob
    //        1234
     
       

    The example shows an ArrayList being created with a custom class, a DateTime and an integer…disparate, non-homogeneous objects.

    The ArrayList is then serialized into an XML string.

    The XML string is then deserialized into a new ArrayList with all the objects intact.

    This could be useful…yah?

    To get this to work, one of the overloaded Serialize functions in the XmlSerializer class is used. The Serialize function is passed an array of types to be serialized. It is easy to get all the types in the ArrayList by iterating the list.

    The problem is deserializing the list. How do you get the array of types the deserializer needs?

    My Solution: Add the list of types in the ArrayList…to the ArrayList…before serializing it.

    The solution has one drawback: Deserialization happens twice. The XmlString is deserialized to get the array of types. Once the array of types is collected, the XmlString is deserialized again with the array of types and the ArrayList will be reconstituted correctly. The XmlString could be parsed to get the array of types but it would probably be just as slow as deserializing and definitely more complicated. The list of types could be included as auxiliary information in a custom class but my self-imposed requirement was to serialize to a valid XML document which requires a single root element…so the list of types must be within the root element.

    Here are the functions:

    /// ---- SerializeArrayList ----------------
    /// <summary>
    /// Serialize an ArrayList to an XML string
    /// </summary>
    /// <param name="ArrayListIn">An ArrayList</param>
    /// <returns>XML String</returns>
     
    public static string SerializeArrayList(ArrayList ArrayListIn)
    {
        // get a list of all the types in the ArrayList to serialize
        // avoid duplicates
        ArrayList TypesInList = new ArrayList();
     
        foreach (Object Item in ArrayListIn)
        {
            if (TypesInList.Contains(Item.GetType()) == false)
                TypesInList.Add(Item.GetType());
        }
     
        // we're going to add a string array, so add these two types
        if (TypesInList.Contains(typeof(String)) == false)
            TypesInList.Add(typeof(String));
        if (TypesInList.Contains(typeof(String[])) == false)
            TypesInList.Add(typeof(String[]));
     
        // Convert the list of types to a string array of type names
        // so we can add it to the ArrayList
        String[] TypeNamesArray = new String[TypesInList.Count];
     
        for (int i = 0; i < TypesInList.Count; i++)        
            TypeNamesArray[i] = ((Type)TypesInList[i]).AssemblyQualifiedName;
     
        // add the array of type names to the ArrayList
        ArrayListIn.Add(TypeNamesArray);
     
        // The Serialize function require an array of type objects
        Type[] Types = (Type[])TypesInList.ToArray(typeof(Type));
     
        // create the serializer, give it the ArrayList type and 
        // the array of types in the ArrayList
        XmlSerializer Serializer = new XmlSerializer(typeof(ArrayList), Types);
     
        // create a stream for the Serializer output
        StringWriter Writer = new StringWriter();
     
        // Do the Serialization
        Serializer.Serialize(Writer, ArrayListIn);
     
        String XMLString = Writer.ToString();
     
        // remove the string array of types we added.
        // we don't want to affect the original list.
        ArrayListIn.RemoveAt(ArrayListIn.Count - 1);
        return XMLString;
    }
     
    /// ---- DeSerializeArrayList --------------------------------------
    /// <summary>
    /// Deserialize an XML string to an ArrayList that was
    /// serialized with the SerializeArrayList function.
    /// </summary>
    /// <param name="XmlString">XML String to deserialize</param>
    /// <returns>A populated ArrayList</returns>
     
    public static ArrayList DeSerializeArrayList(String XmlString)
    {
        // extract the array of type names
        // it's the last node of the ArrayList
        Type[] TempTypes = new Type[2];
     
        TempTypes[0] = typeof(System.String);
        TempTypes[1] = typeof(System.String[]);
        XmlSerializer Serializer = new XmlSerializer(typeof(ArrayList), TempTypes);
     
        ArrayList MyArrayList;
     
        // create a stream for the DeSerializer input
        StringReader StrReader = new StringReader(XmlString);
     
        // first deserialization (we'll do this again)
        MyArrayList = Serializer.Deserialize(StrReader) as ArrayList;
     
        // get the array of type names (last node in ArrayList)
        String[] StrTypes = MyArrayList[MyArrayList.Count - 1] as String[];
     
        // convert it to an array of type objects
        TempTypes = new Type[StrTypes.Length];
        for (int i = 0; i < TempTypes.Length; i++)
            TempTypes[i] = Type.GetType(StrTypes[i]);
     
        // create the serializer, this time with a complete array
        // of the types contained in it.
        Serializer = new XmlSerializer(typeof(ArrayList), TempTypes);
     
        // create a stream for the DeSerializer output
        StrReader = new StringReader(XmlString);
     
        // Deserialize
        MyArrayList = Serializer.Deserialize(StrReader) as ArrayList;
     
        // get rid of the array of type names, we put it
        // there and it's not part of the orginal ArrayList
        MyArrayList.RemoveAt(MyArrayList.Count - 1);
        return MyArrayList;
    }

    I put the functions in a namespace called XMLUtils (in a file called XMLUtils.cs). You can download the file here. It also includes updated versions of the two functions to serialize and deserialize single objects from an earlier post.

    Note: The classes and namespaces of the objects in the ArrayList must be available in the scope of where the serialization and deserialization takes place.

    Note: I initially tried to serialize an array of Types instead of an array of Type Names. But the serializer did not like that. It didn't like it one bit.

    Note: I could have created the functions as extension methods or added an extension method wrapper like this:

    public static string ExSerializeArrayList(this ArrayList ArrayListIn)
    {
        return SerializeArrayList(ArrayListIn);
    }

    But, to be symmetric, an Extension method would need to be created for the String class and that would burden the often-used String class with a very specialized and rare usage… so it was not done.

    I hope someone finds this useful.

    Thanks,

    Steve Wellens

  • Debugging XML Transforms (XSLT) with Visual Studio

    XSLT stands for Extensible Stylesheet Language Transformations.

    [Update/Note] This post describes the XSLT debugger which is only available in the Professional and Team System versions of Visual Studio.

    There is so much to learn in our technical world… and so little time….and for some of us, even fewer brain cells. Alas, such is the life of a nerd/dweeb/geek.

    The latest technology I spent brain cells on is XML Transforms. You've probably seen those mysterious little files with the XSLT extensions that do magically wondrous things to XML files.

    For traditional developers, XSLT is weird because it's not a traditional procedural language: "Do A, if successful then do B". XSLT uses "templates" with XPATH to select a group of nodes and then formats the selected nodes in the template body. To delve deeper into the document, XSLT uses sub-templates in a recursive tree-like fashion. However, these sub-templates are disjointed hunks of text in the XSLT document so it's difficult to visually comprehend what is going on…at least to an untrained eye.

    This post isn't going to explain how XSLT transforms work—it's going to explain how to run them under the Visual Studio Debugger and watch them do their magic. FYI: I only tried this with VS 2008.

    For more information on XSLT, go to the WC3 website here.

    Here is the XML input file we are going to work with:

    <?xml version="1.0" standalone="yes"?>
    <Golfers>
      <Golfer >
        <ID>1</ID>
        <Name>Bobby Jones</Name>
        <Birthday>1902-03-17</Birthday>
      </Golfer>
      <Golfer>
        <ID>2</ID>
        <Name>Sam Snead</Name>
        <Birthday>1912-05-27</Birthday>
      </Golfer>
      <Golfer>
        <ID>3</ID>
        <Name>Tiger Woods</Name>
        <Birthday>1975-12-30</Birthday>
      </Golfer>
    </Golfers>

    Here is the XSLT file we are going to transform it with:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
      <xsl:output method="xml"   indent="yes"/>

      <xsl:template match="/Golfers">
        <Golfers>
          <xsl:apply-templates select="Golfer"/>
        </Golfers>
      </xsl:template>

      <xsl:template match="Golfer">
        <xsl:element name="Golfer">
         
          <xsl:attribute name="ID" >
            <xsl:value-of select="ID"/>
          </xsl:attribute>

          <xsl:attribute name="Name" >
            <xsl:value-of select="Name"/>
          </xsl:attribute>
         
          <xsl:attribute name="Birthday" >
            <xsl:value-of select="Birthday"/>
          </xsl:attribute>

        </xsl:element>
      </xsl:template>

    </xsl:stylesheet>

    The transform file will turn the XML elements into attributes. Why do this? Because the .Net DataSet and DataTable classes seems to prefer XML attributes when reading XML files. And, because after studying XML for a long time, I've come to prefer sub-elements when there is a one-to-many relationship and to prefer attributes when there one-to-one relationship between the elements.

    To start, first open up the XSLT file in Visual Studio:

    The XML tool bar should appear:

    If it doesn't appear, right click on the toolbar area and turn it on:

    Put a breakpoint in the XSLT file (F9 or use the mouse or use the Debug menu):

    Click the Debug XSLT button:

    The first time you run it, an open file dialog will prompt you: "Choose Input XML Document."

    Note: Subsequently when you run it, the input file will open automatically*.

    The standard Debug toolbar will appear. With the toolbar you can start stepping through the transform code. Two synchronized windows will be open:

    In the image above, I've clicked 'step' several times. You can see in the right window that the second XML node is being processed.

    If you go to the Debug menu and select Locals, you can get more information about what is happening:

    You can do watches and other debugging things while the code is paused. You can see the output file being built in the window behind the input XML window.

    When it's all done the new XML file will look like this:

    <?xml version="1.0" encoding="utf-8"?>
    <Golfers>
      <Golfer ID="1" Name="Bobby Jones" Birthday="1902-03-17" />
      <Golfer ID="2" Name="Sam Snead" Birthday="1912-05-27" />
      <Golfer ID="3" Name="Tiger Woods" Birthday="1975-12-30" />
    </Golfers>

    As my Canadian friends would say: "That's pretty cool, eh?"

    *To override the automatic opening of the XML input file, right click the XSLT file and select properties. You can edit the input and output file paths and names:

    That's it. Who knew the Microsoft boys and girls would go to such depths to provide such a powerful tool.  It was a pleasant discovery.

    I hope someone finds this useful.

    Steve Wellens

  • Serializing and Deserializing Objects…to and from…XML

    Over on the Asp.Net forums I recently had the opportunity* to help a few lost souls by showing them how to serialize objects to XML and deserialize the XML back into objects. Since the question has come up more than once, I decided to BLOG it so I could refer similar questions in the future to this post.

    *I use the word opportunity because by helping others I am forced to think hard about the technology and to think even harder about how to communicate the technology. It makes me better at what I do. All right then, enough after-school-special-feel-good-about-yourself-I'm-ok-you're-ok fluffy nonsense… on with the code:

    Here is a simple class I'm going to work with. It has both properties and fields:

    public class MyClass
    {
        // old school property
        private int _Age;  
        public int Age  
        {
            get { return _Age; }
            set { _Age = value; }
        }
     
        // new school property
        public bool Citizen { get; set; }
     
        // there's nothing wrong with using fields
        public string Name;  
    }

    Here are the two functions to Serialize and Deserialize an object:

    /// ---- SerializeAnObject -----------------------------
    /// <summary>
    /// Serializes an object to an XML string
    /// </summary>
    /// <param name="AnObject">The Object to serialize</param>
    /// <returns>XML string</returns>
     
    public static string SerializeAnObject(object AnObject)
    {
        XmlSerializer Xml_Serializer = new XmlSerializer(AnObject.GetType());
        StringWriter Writer = new StringWriter();      
     
        Xml_Serializer.Serialize(Writer, AnObject);
        return Writer.ToString();
    }
     
     
    /// ---- DeSerializeAnObject ------------------------------
    /// <summary>
    /// DeSerialize an object
    /// </summary>
    /// <param name="XmlOfAnObject">The XML string</param>
    /// <param name="ObjectType">The type of object</param>
    /// <returns>A deserialized object...must be cast to correct type</returns>
     
    public static Object DeSerializeAnObject(string XmlOfAnObject, Type ObjectType)
    {       
        StringReader StrReader = new StringReader(XmlOfAnObject);
        XmlSerializer Xml_Serializer = new XmlSerializer(ObjectType);
        XmlTextReader XmlReader = new XmlTextReader(StrReader);
        try
        {
            Object AnObject = Xml_Serializer.Deserialize(XmlReader);
            return AnObject;
        }
        finally
        {
            XmlReader.Close();
            StrReader.Close();
        }
    }

    Here is some sample code showing how to use the functions.

    Note: I keep these functions (and other functions) in a class I call MiscUtilities. You will have to modify the code…depending on where you place the functions.

    protected void Button1_Click(object sender, EventArgs e)
    {
        // create and initialize an object
        MyClass Test = new MyClass();
     
        Test.Age = 18;
        Test.Name = "Rocky Balboa";
        Test.Citizen = true;
     
        //  Serialize it
        String XML;
     
        XML = MiscUtilities.SerializeAnObject(Test);
     
        // Deserialize it
        MyClass Test2;
     
        Test2 = MiscUtilities.DeSerializeAnObject(XML, typeof(MyClass)) as MyClass;
     
        // TODO:  Get a cup of coffee and bask in the glory of rock solid code.
    }

    Here is what the XML string looks like (after formatting):

    <?xml version="1.0"?>
    <MyClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <Name>Rocky Balboa</Name>
      <Age>18</Age>
      <Citizen>true</Citizen>
    </MyClass>

    There are limitations: XmlSerializer does not serialize private fields, methods, indexers or read-only fields.

    Once you have the XML string, you can email it, store it in a database, save it to disk, or…print a copy of it and have your mom tape it to the refrigerator next to the picture of a turkey you made in second grade by tracing around your hand with a Crayola crayon.

    I hope someone finds this useful.

  • Free Tools that I Use

    Here are tools I use on a regular basis. They have attributes I find essential:

    1. They are free.
    2. They do one thing and they do it well.

    XPathBuilder: Dynamically searches XML: Bubba Soft

    Expresso: Design and test regular expressions before you compile: Ultrapico

    WinMerge: Compares files and directories: WinMerge

    XVI32: A hex editor. With this I learned about the BOM: Christian Maas

    While these tools are great, they can really add to your productivity when you integrate them into Visual Studio. When you right click a file in the solution and use "Open With…" You can add these tools to the list of applications:

    I hope you find this useful.

    Steve Wellens