Search code examples
c#xmlreferencedatacontractcircular-reference

What serializer to use (to xml) for circular reference and custom field?


I have the following xml:

<A name="">
    <B name="">
        <C name="">
            <B name=""/>
            <B name=""/>
        </C>
    </B>
    <B name="">
        <C name="">
            <B name=""/>
            <B name=""/>
            <B name=""/>
            <B name=""/>
        </C>
    </B>
</A>

Please notice that element C creates circular reference, so I can't use XmlSerializer.

How I can deserialize and serialize it? It seems that I can't use DataContractSerializer because:

  1. DataContract doesn't support attributes ("Name" in my example)
  2. DataContract doesn't support ignoring outer element name, for example

    List<B> BList;
    

Will be serialized to:

<C name="">
    <BList>
        <B name=""/>
        <B name=""/>
    </Blist>
</C>

But I want too keep structure like in first example.

Thanks a lot.


Solution

  • you can achieve this with the help of XML Serializer and Deserializer

    Class Structure:

    [XmlRoot(ElementName = "A")]
        public class A
        {
            [XmlAttribute("Name")]
            public string Name { get; set; }
            private List<B> b = new List<B>();
    
            [XmlElement("B")]
            public List<B> B
            {
                get { return b; }
                set { b = value; }
            }
        }
    
        public class B
        {
            [XmlAttribute("Name")]
            public string Name { get; set; }
            private List<C> c = new List<C>();
    
            [XmlElement("C")]
            public List<C> C
            {
                get { return c; }
                set { c = value; }
            }
        }
    
        public class C
        {
            [XmlAttribute("Name")]
            public string Name { get; set; }
            private List<B> b = new List<B>();
    
            [XmlElement("B")]
            public List<B> B
            {
                get { return b; }
                set { b = value; }
            }
        }
    

    To fill Objects ( update this as per your requirement ) :

    private A a = new A();
            private void Load()
            {
                a.B.Clear();
                a.Name = string.Empty;
                for (int i = 0; i < 3; i++)
                {
                    var tempB = new B();
                    tempB.Name = string.Empty;
                    for (int j = 0; j < 5; j++)
                    {
                        var tempC = new C();
                        tempC.Name = string.Empty;
                        for (int k = 0; k < 3; k++)
                        {
                            var innerChildB = new B();
                            innerChildB.Name = string.Empty;
                            tempC.B.Add(innerChildB);
                        }
                        tempB.C.Add(tempC);
                    }
                    a.B.Add(tempB);
                }
            }
    

    Serialization:

    private void Serialize()
            {
                try
                {
                    // to Save columnorders to the file
                    var serializer = new XmlSerializer(typeof(A));
                    var ns = new XmlSerializerNamespaces();
                    ns.Add("", "");
    
                    using (TextWriter writer = new StreamWriter(@"D:\Test_Jun13.xml"))
                    {
                        serializer.Serialize(writer, a, ns);
                    }
                }
                catch { }
            }
    

    Deserialization:

    private void DeSerialize()
        {
            try
            {
                if (File.Exists(@"D:\Test_Jun13.xml"))
                {
                    var deserializer = new XmlSerializer(typeof(A));
                    using (TextReader reader = new StreamReader(@"D:\Test_Jun13.xml"))
                    {
                        var obj = deserializer.Deserialize(reader);
                        a = (A)obj;
                    }
                }
            }
            catch
            {
    
            }
    
    
        }
    

    XML File will look like:

    <?xml version="1.0" encoding="utf-8"?>
    <A Name="">
      <B Name="">
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
      </B>
      <B Name="">
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
      </B>
      <B Name="">
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
        <C Name="">
          <B Name="" />
          <B Name="" />
          <B Name="" />
        </C>
      </B>
    </A>
    

    will this fix your issue?