Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.net XML Serialization - Storing Reference instead of Object Copy

  • In .Net/C# Application, I have data structures which have references to each other.
  • When I serialize them, .Net Serializes all references with separate object copies.
  • In Following Example, I am trying to serialize to Array of 'Person'
  • A 'Person' may have reference to another person.

    public class Person
    {
        public string Name;
        public Person Friend;
    }
    
    Person p1 = new Person();
    p1.Name = "John";
    
    Person p2 = new Person();
    p2.Name = "Mike";
    
    p1.Friend = p2;
    
    Person[] group = new Person[] { p1, p2 };
    XmlSerializer ser = new XmlSerializer(typeof(Person[]));
    using (TextWriter tw = new StreamWriter("test.xml"))
        ser.Serialize(tw,group );
    
    //above code generates following xml
    
    <ArrayOfPerson>
      <Person>
        <Name>John</Name>
        <Friend>
          <Name>Mike</Name>
        </Friend>
      </Person>
      <Person>
        <Name>Mike</Name>
      </Person>
    </ArrayOfPerson>
    
  • In above code, the same 'Mike' object are there on two places, since there are two references for the same object.

  • While deserializing, they become two different objects, which is not exact state when they are serialized.
  • I want to avoid this and have only copy of object in serialized xml, and all references should refer to this copy. After deserialization , i want to get back, same old data structure.
  • Is it Possible ?
like image 413
Palani Avatar asked Oct 24 '09 09:10

Palani


People also ask

What is the correct way of using XML serialization?

XML Serialization Considerations Type identity and assembly information are not included. Only public properties and fields can be serialized. Properties must have public accessors (get and set methods). If you must serialize non-public data, use the DataContractSerializer class rather than XML serialization.

What is the basic difference between SOAP serialization and XML serialization?

XML serialization can also be used to serialize objects into XML streams that conform to the SOAP specification. SOAP is a protocol based on XML, designed specifically to transport procedure calls using XML. To serialize or deserialize objects, use the XmlSerializer class.

What does it mean to serialize XML?

XML serialization is the process of converting XML data from its representation in the XQuery and XPath data model, which is the hierarchical format it has in a Db2® database, to the serialized string format that it has in an application.


2 Answers

It is not possible with XmlSerializer. You could achieve this with DataContractSerializer using the PreserveObjectReferences property. You may take a look at this post which explains the details.

Here's a sample code:

public class Person {     public string Name;     public Person Friend; }  class Program {     static void Main(string[] args)     {         Person p1 = new Person();         p1.Name = "John";          Person p2 = new Person();         p2.Name = "Mike";         p1.Friend = p2;         Person[] group = new Person[] { p1, p2 };          var serializer = new DataContractSerializer(group.GetType(), null,              0x7FFF /*maxItemsInObjectGraph*/,              false /*ignoreExtensionDataObject*/,              true /*preserveObjectReferences : this is where the magic happens */,              null /*dataContractSurrogate*/);         serializer.WriteObject(Console.OpenStandardOutput(), group);     } } 

This produces the following XML:

<ArrayOfPerson z:Id="1" z:Size="2" xmlns="http://schemas.datacontract.org/2004/07/ToDelete" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">     <Person z:Id="2">         <Friend z:Id="3">             <Friend i:nil="true"/>             <Name z:Id="4">Mike</Name>         </Friend>         <Name z:Id="5">John</Name>     </Person>     <Person z:Ref="3" i:nil="true"/> </ArrayOfPerson> 

Now set PreserveObjectReferences to false in the constructor and you will get this:

<ArrayOfPerson xmlns="http://schemas.datacontract.org/2004/07/ToDelete" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">     <Person>         <Friend>             <Friend i:nil="true"/>             <Name>Mike</Name>         </Friend>         <Name>John</Name>     </Person>     <Person>         <Friend i:nil="true"/>         <Name>Mike</Name>     </Person> </ArrayOfPerson> 

It is worth mentioning that the XML produced this way is not interoperable and can only be deserialized with a DataContractSerializer (same remark as with the BinaryFormatter).

like image 77
Darin Dimitrov Avatar answered Oct 07 '22 20:10

Darin Dimitrov


You can use ExtendedXmlSerializer. Here is an example of serialization object reference and circular reference

If you have a class:

public class Person
{
    public int Id { get; set; }

    public string Name { get; set; }

    public Person Boss { get; set; }
}

public class Company
{
    public List<Person> Employees { get; set; }
}

then you create object with circular reference, like this:

var boss = new Person {Id = 1, Name = "John"};
boss.Boss = boss; //himself boss
var worker = new Person {Id = 2, Name = "Oliver"};
worker.Boss = boss;
var obj = new Company
{
    Employees = new List<Person>
    {
        worker,
        boss
    }
};

You must configure Person class as reference object:

var serializer = new ConfigurationContainer().ConfigureType<Person>()
                                             .EnableReferences(p => p.Id)
                                             .Create();

In the end you can serialize your object:

var xml = serializer.Serialize(obj);

Output xml will look like this:

<?xml version="1.0" encoding="utf-8"?>
<Company xmlns="clr-namespace:ExtendedXmlSerializer.Samples.ObjectReference;assembly=ExtendedXmlSerializer.Samples">
  <Employees>
    <Capacity>4</Capacity>
    <Person Id="2">
      <Name>Oliver</Name>
      <Boss Id="1">
        <Name>John</Name>
        <Boss xmlns:exs="https://extendedxmlserializer.github.io/v2" exs:entity="1" />
      </Boss>
    </Person>
    <Person xmlns:exs="https://extendedxmlserializer.github.io/v2" exs:entity="1" />
  </Employees>
</Company>

ExtendedXmlSerializer support .net 4.5 and .net Core.

like image 21
Wojtpl2 Avatar answered Oct 07 '22 19:10

Wojtpl2