Search code examples
c#xmlserializationxmlserializer

XML Array Serialization Using XML Code Annotations


I am struggling to serialize the following XML code...

<Activity mc:Ignorable="sap sap2010 sads" x:Class="Main"
 xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 xmlns:sco="clr-namespace:System.Collections.ObjectModel;assembly=mscorlib"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TextExpression.NamespacesForImplementation>
    <sco:Collection x:TypeArguments="x:String">
      <x:String>System.Activities</x:String>
      <x:String>System.Activities.Statements</x:String>
      <x:String>System.Activities.Expressions</x:String>
      <x:String>System.Activities.Validation</x:String>
      <x:String>System.Activities.XamlIntegration</x:String>
      <x:String>Microsoft.VisualBasic</x:String>
      <x:String>Microsoft.VisualBasic.Activities</x:String>
      <x:String>System</x:String>
      <x:String>System.Collections</x:String>
      <x:String>System.Collections.Generic</x:String>
      <x:String>System.Data</x:String>
      <x:String>System.Diagnostics</x:String>
      <x:String>System.Drawing</x:String>
      <x:String>System.IO</x:String>
      <x:String>System.Linq</x:String>
      <x:String>System.Net.Mail</x:String>
      <x:String>System.Xml</x:String>
      <x:String>System.Xml.Linq</x:String>
      <x:String>UiPath.Core</x:String>
      <x:String>System.Windows.Markup</x:String>
      <x:String>UiPath.Core.Activities</x:String>
    </sco:Collection>
  </TextExpression.NamespacesForImplementation>
</Activity>

I feel I have tried all combinations of [XmlArray] and [XmlArrayItem] on various properties but I can's seem to capture both the TypeArguments attribute and the list of string values. I am also unsure on which classes I need to produce to make this work. Any suggestions?

Note I have also tried using the 'Special Paste' option to generate the class structure, but after serializing and immediately deserializing, the output xml file is not of the same structure.


Solution

  • The following works for me.

    Classes used for serializing and deserializing:

    [XmlRoot(Namespace = "http://schemas.microsoft.com/netfx/2009/xaml/activities")]
    public class Activity
    {
        [XmlAttribute(Namespace = "http://schemas.microsoft.com/netfx/2009/xaml/activities")]
        public string Ignorable { get; set; }
    
        [XmlAttribute(Namespace = "http://schemas.microsoft.com/winfx/2006/xaml")]
        public string Class { get; set; }
    
        [XmlElement("TextExpression.NamespacesForImplementation")]
        public NamespacesForImplementation NamespacesForImplementation { get; set; }
    }
    
    public class NamespacesForImplementation
    {
        [XmlElement(Namespace = "clr-namespace:System.Collections.ObjectModel;assembly=mscorlib")]
        public NamespaceCollection Collection { get; set; }
    }
    
    public class NamespaceCollection
    {
        [XmlAttribute(Namespace = "http://schemas.microsoft.com/winfx/2006/xaml")]
        public string TypeArguments { get; set; }
    
        [XmlElement(ElementName = "String", Namespace = "http://schemas.microsoft.com/winfx/2006/xaml")]
        public List<string> Content { get; set; }
    }
    

    Test program serializing the exact XML in your question:

    class Program
    {
        static void Main(string[] args)
        {
            var serializer = new XmlSerializer(typeof(Activity));
    
            Activity activity;
            using (var stream = File.OpenText("Test.xml"))
            {
                activity = (Activity) serializer.Deserialize(stream);
            }
    
            XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
            ns.Add(string.Empty, "http://schemas.microsoft.com/netfx/2009/xaml/activities");
            ns.Add("mc", "http://schemas.openxmlformats.org/markup-compatibility/2006");
            ns.Add("sco", "clr-namespace:System.Collections.ObjectModel;assembly=mscorlib");
            ns.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
    
            using (var stringWriter = new StringWriter())
            {
                serializer.Serialize(stringWriter, activity, ns);
                Console.WriteLine(stringWriter.ToString());
            }
        }
    }
    

    The output of the program is the following:

    <?xml version="1.0" encoding="utf-16"?>
    <Activity xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sco="clr-namespace:System.Collections.ObjectModel;assembly=mscorlib" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Class="Main" xmlns="http://schemas.microsoft.com/netfx/2009/xaml/activities">
      <TextExpression.NamespacesForImplementation>
        <sco:Collection x:TypeArguments="x:String">
          <x:String>System.Activities</x:String>
          <x:String>System.Activities.Statements</x:String>
          <x:String>System.Activities.Expressions</x:String>
          <x:String>System.Activities.Validation</x:String>
          <x:String>System.Activities.XamlIntegration</x:String>
          <x:String>Microsoft.VisualBasic</x:String>
          <x:String>Microsoft.VisualBasic.Activities</x:String>
          <x:String>System</x:String>
          <x:String>System.Collections</x:String>
          <x:String>System.Collections.Generic</x:String>
          <x:String>System.Data</x:String>
          <x:String>System.Diagnostics</x:String>
          <x:String>System.Drawing</x:String>
          <x:String>System.IO</x:String>
          <x:String>System.Linq</x:String>
          <x:String>System.Net.Mail</x:String>
          <x:String>System.Xml</x:String>
          <x:String>System.Xml.Linq</x:String>
          <x:String>UiPath.Core</x:String>
          <x:String>System.Windows.Markup</x:String>
          <x:String>UiPath.Core.Activities</x:String>
        </sco:Collection>
      </TextExpression.NamespacesForImplementation>
    </Activity>