none
Serialize / deserialize / whole object, only a part of the object RRS feed

  • Question

  • Hello,
    First
    I serialize a class with subclasses. Well so far.
    [XmlRoot("ORDER")]
    public class Order
    {
    	public class Batch
    	{
    		[XmlAttribute("batchID")]
    		public string BatchID { get; set; }
    		[XmlAttribute("quantity")]
    		public int Quantity { get; set; }
    	}
    
    	[XmlAttribute("orderNumberScan")]
    	public string OrderNumberScan { get; set; }
    
    	[XmlArray("BATCHES")]
    	[XmlArrayItem("BATCH")]
    	//[XmlElement("BATCH")]
    	public List<Batch> CurrentListBatches;
    
    <ORDER orderNumberScan="0815" >
      <CurrentProduct product="Receiver" manufactor="Sony" />
      <BATCHES>
        <BATCH batchID="Charge 001" quantity="100" />
        <BATCH batchID="Charge 002" quantity="200" />
        <BATCH batchID="003" quantity="99" />
        <BATCH batchID="Charge 004" quantity="131" />
      </BATCHES>
    </ORDER>
    I would now like to serialize a part and save it as a file.
    The result is.
    <ArrayOfBatch>
      <Batch batchID="Charge 001" quantity="100" />
      <Batch batchID="Charge 002" quantity="200" />
      <Batch batchID="003" quantity="99" />
      <Batch batchID="Charge 004" quantity="131" />
    </ArrayOfBatch>
    Where does the element name ArrayOfBatch come from?
    How can I rename it to batches?

    Thank you for suggesting solutions in advance.
    Second

    protected static object LockBatches = new object();
     
    lock (LockBatches) 
    {
    	SaveXML(currentBatches, CurrentOrder.CurrentListBatches);
    }
    
    lock (LockBatches) 
    {
    	CurrentOrder.CurrentListBatches = DeserializeXML(currentBatchesFile);
    }
    
    
    The list is filled during the process by UI and emptied by the process flow.
    In the same application cannot be read and written at the same time.
    How can I solve this? Is this correct? Can I use one static object?
    Best regards Markus



    Saturday, August 10, 2019 10:34 AM

Answers

  • Hi Markus,

    Thanks for the feedback.

    >>I think only this is possible

    I think the following code is very streamlined and can't be optimized anymore.

     public static void WriteXml<T>(string filename, T template, XmlRootAttribute newRoot)
            {
                lock (LockObj)
                {
                    FileStream fs = new FileStream(filename, FileMode.Create);
                    XmlSerializer xs;
                    xs = newRoot == null ? new XmlSerializer(typeof(T)) : new XmlSerializer(typeof(T), newRoot);
                    xs.Serialize(fs, template);
                    fs.Close();
                }
            }

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Friday, August 16, 2019 5:43 AM
    Moderator

All replies

  • Hi Markus,

    Thank you for posting here.

    First, you want to serialize a part of class and save it as a file. If you want to serialize the object to the xml you provided, it is necessary for you to use CurrentListBatches. Therefore, you may have to serialize all the Order class.

    Second, I am not sure why you get the xml with the element name ArrayOfBatch. After all, you don't provide the related code.

    Finally, you could refer to the following code to get the xml you expected, also, you could read and write the xml at the same time.

    Code:

    class Program
        {
            static void Main(string[] args)
            {
                Order.Batch batch = new Order.Batch();
                batch.BatchID = "test1";
                batch.Quantity = 11;
                Order.Batch batch1 = new Order.Batch();
                batch1.BatchID = "test2";
                batch.Quantity = 12;
                Order.Batch batch2 = new Order.Batch();
                batch2.BatchID = "test3";
                batch2.Quantity = 13;
                Order order = new Order();
                order.OrderNumberScan = "hi";
                var list=new List<Order.Batch>();
                list.Add(batch);
                list.Add(batch1);
                list.Add(batch2);
                order.CurrentListBatches = list;
                //xmlserializer
                FileStream fs = new FileStream("D:\\test2.xml", FileMode.Create);
                XmlSerializer xs = new XmlSerializer(typeof(Order));
                xs.Serialize(fs, order);
                fs.Close();
                //xmlDeserializer
                fs = new FileStream("D:\\test2.xml", FileMode.Open);
                xs = new XmlSerializer(typeof(Order));
                Order o= xs.Deserialize(fs) as Order;
                if (o != null)
                {
                    var list1 = o.CurrentListBatches;
                    foreach (var item in list1)
                    {
                        Console.WriteLine(item.BatchID+" "+item.Quantity);
                    }
                }
                fs.Close();
    
                Console.ReadKey();
    
    
            }
        }
    
        [XmlRoot("ORDER")]
        public class Order
        {
            public class Batch
            {
                [XmlAttribute("batchID")]
                public string BatchID { get; set; }
                [XmlAttribute("quantity")]
                public int Quantity { get; set; }
            }
    
            [XmlAttribute("orderNumberScan")]
            public string OrderNumberScan { get; set; }
    
            [XmlArray("BATCHES")]
            [XmlArrayItem("BATCH")]
            public List<Batch> CurrentListBatches;
        }

    Xml File:

    Result:

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, August 12, 2019 2:25 AM
    Moderator
  • Hello Jack,
    Thank you for your answer. The problem is the element name.
    I just want to understand it.
    How could I change this element name if the customer is not satisfied with this automatically generated name?
    How can I make sure that reading, writing, does not happen at the same time?
    Can you publish an example? Thanks in advance.
    lock (LockBatches)  
    {
     SaveTraceXML(currentBatches, CurrentOrder.CurrentListBatches);
    }
    lock (LockOrder)
    {
     SaveTraceXML(path, CurrentOrder);
    }
    
    protected void SaveTraceXML<T>(string file, T dataObject)
    {
     XmlSerializer serializer = new XmlSerializer(typeof(T));
     using (Stream stream = new FileStream(file, FileMode.Create))
     using (XmlWriter xmlWriter = XmlWriter.Create(stream, WriterSettingsExclusiv))
     {
      serializer.Serialize(xmlWriter, dataObject, Namespaces);
     }
    }
    protected T DeserializeFile<T>(string absolutePath)
    {
     T ret = default(T);
     if (!File.Exists(absolutePath))
      return ret;
     XmlSerializer serializer = new XmlSerializer(typeof(T));
     using (Stream stream = new FileStream(absolutePath, FileMode.Open, System.IO.FileAccess.Read, FileShare.ReadWrite))
     using (XmlReader reader = XmlReader.Create(stream, ReaderSettings))
     {
      ret = (T)serializer.Deserialize(reader);
      return ret;
     }
    }


    With best regards Markus
    Monday, August 12, 2019 4:02 PM
  • Hi Markus,

    Thanks for the feedback.

    >>How could I change this element name if the customer is not satisfied with this automatically generated name?

    The element name depends on the define in the class. For example, if you set [XmlRoot("ORDER")], the root node is ORDER, which also applies to other elements.

    >>How can I make sure that reading, writing, does not happen at the same time?

    You could add the following code after writing the xml to keep them not at the same time.

     Thread.Sleep(2000);

    >>Can you publish an example?

    I have posted a completed example code, you could have a look. If you think this solved your problem, please post "Mark as answer" to the appropriate answer.

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, August 13, 2019 2:22 AM
    Moderator
  • Hello Jack,
    >The element name depends on the define in the class. For example, if you
    >set [XmlRoot("ORDER")], the root node is ORDER, which also applies
    >to other elements.
    You're right, I can change the element name here.
    lock (LockBatches)  
    {
     SaveTraceXML(currentBatches, CurrentOrder.CurrentListBatches);
    }
    lock (LockOrder)
    {
     SaveTraceXML(path, CurrentOrder);
    }

    <ArrayOfBatch>
      <Batch batchID="test1" quantity="12" />
      <Batch batchID="test2" quantity="0" />
      <Batch batchID="test3" quantity="13" />
    </ArrayOfBatch>
    User Interface fill the list
    The process processes the list and reduces the number by 1. If this is 0, the element name is deleted.
    <ArrayOfBatch>
      <Batch batchID="test1" quantity="12" />
      <Batch batchID="test2" quantity="0" />
      <Batch batchID="test3" quantity="12" />  save 11 save 10 save .......1 save 0 delete
    </ArrayOfBatch>
    -> To add a sleep time is the worst solution.
    And it may happen that the process counts it down, the operator in the Userinterface fills the list.

    My question was, if I serialize only a part, the element name ArrayOfBatches appears. Where does this name come from, how can I change it?

    I try this https://stackoverflow.com/questions/3129001/how-to-rename-arrayof-xml-attribute-that-generated-after-serializing-list-of-o

      XmlSerializer serializer = new XmlSerializer(typeof(List<Order.Batch>), new XmlRootAttribute("DropDownOptions"));
    But not works.

    >I have posted a completed example code, you could have a look.
    >If you think this solved your problem, please post "Mark as answer"
    >to the appropriate answer.

    Of course I'm putting that on solved, unfortunately it's not solved.
    To put a sleep is in my view the wrong way. The application is slow, so I asked in the expert forum for a good right solution.
    Maybe you can give me a hint or the other experts know the solution.

    Below you'll find the code I tested.
    Thanks in advance for your help.

    With best regards Markus
    // ~~~~~~~~~~~~~~~~
    Code
    
    namespace SerializePart
    {
        [XmlRoot("ORDER")]
        public class Order
        {
            //[XmlRoot("BATCHES")]
            public class Batch
            {
                [XmlAttribute("batchID")]
                public string BatchID { get; set; }
                [XmlAttribute("quantity")]
                public int Quantity { get; set; }
            }
    
            [XmlAttribute("orderNumberScan")]
            public string OrderNumberScan { get; set; }
    
            [XmlArray("BATCHES")]
            [XmlArrayItem("BATCH")]
            public List<Batch> CurrentListBatches;
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Order.Batch batch = new Order.Batch();
                batch.BatchID = "test1";
                batch.Quantity = 11;
                Order.Batch batch1 = new Order.Batch();
                batch1.BatchID = "test2";
                batch.Quantity = 12;
                Order.Batch batch2 = new Order.Batch();
                batch2.BatchID = "test3";
                batch2.Quantity = 13;
                Order order = new Order();
                order.OrderNumberScan = "hi";
                var list = new List<Order.Batch>();
                list.Add(batch);
                list.Add(batch1);
                list.Add(batch2);
                order.CurrentListBatches = list;
    
    
                //xmlserializer
                FileStream fs = new FileStream("c:\\temp\\test1Whole.xml", FileMode.Create);
                XmlSerializer xs = new XmlSerializer(typeof(Order));
                xs.Serialize(fs, order);
                fs.Close();
    
      
    
                //xmlserializer only part
                FileStream fs2 = new FileStream("c:\\temp\\test1Part.xml", FileMode.Create);
                XmlSerializer xs2 = new XmlSerializer(typeof(List<Order.Batch>));
                xs2.Serialize(fs2, order.CurrentListBatches);
                fs2.Close();
    			
    			// Output, why ArrayOfBatch
    //<?xml version="1.0"?>
    //<ArrayOfBatch xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    //  <Batch batchID="test1" quantity="12" />
    //  <Batch batchID="test2" quantity="0" />
    //  <Batch batchID="test3" quantity="13" />
    //</ArrayOfBatch>
    
    
                //xmlDeserializer
                fs = new FileStream("c:\\temp\\test1Whole.xml", FileMode.Open);
                xs = new XmlSerializer(typeof(Order));
                Order o = xs.Deserialize(fs) as Order;
                if (o != null)
                {
                    var list1 = o.CurrentListBatches;
                    foreach (var item in list1)
                    {
                        Console.WriteLine(item.BatchID + " " + item.Quantity);
                    }
                }
                fs.Close();
    
                Console.ReadKey();
            }
        }
    }


    Tuesday, August 13, 2019 4:15 PM
  • Hi Markus,

    Thanks for the feedback.

    You could use the lock to prevent read and write the file at the same time.

     [XmlRoot("ORDER")]
        public class Order
        {
            public class Batch
            {
                [XmlAttribute("batchID")]
                public string BatchID { get; set; }
                [XmlAttribute("quantity")]
                public int Quantity { get; set; }
            }
    
            [XmlAttribute("orderNumberScan")]
            public string OrderNumberScan { get; set; }
    
            [XmlArray("ArrayOfBatch")]
            [XmlArrayItem("BATCH")]
            public List<Batch> CurrentListBatches;
        }
            class Program
           {
            public static readonly object LockObj = new object();
            static void Main(string[] args)
            {
                Order.Batch batch = new Order.Batch();
                batch.BatchID = "test1";
                batch.Quantity = 11;
                Order.Batch batch1 = new Order.Batch();
                batch1.BatchID = "test2";
                batch.Quantity = 12;
                Order.Batch batch2 = new Order.Batch();
                batch2.BatchID = "test3";
                batch2.Quantity = 13;
                Order order = new Order();
                order.OrderNumberScan = "hi";
                var list = new List<Order.Batch>();
                list.Add(batch);
                list.Add(batch1);
                list.Add(batch2);
                order.CurrentListBatches = list;
                string path = "D:\\test.xml";
                Writexml(path, order);
                Readxml(path);
                Console.ReadKey();
    
                
            }
            public static void Writexml(string filename,Order order)
            {
                lock (LockObj)
                {
                    FileStream fs = new FileStream(filename, FileMode.Create);
                    XmlSerializer xs = new XmlSerializer(typeof(Order));
                    xs.Serialize(fs, order);
                    fs.Close();
                }
            }
    
            public static void Readxml(string filename)
            {
                lock (LockObj)
                {
                    FileStream fs = new FileStream(filename, FileMode.Open);
                    XmlSerializer xs = new XmlSerializer(typeof(Order));
                    Order o = xs.Deserialize(fs) as Order;
                    if (o != null)
                    {
                        var list1 = o.CurrentListBatches;
                        foreach (var item in list1)
                        {
                            Console.WriteLine(item.BatchID + " " + item.Quantity);
                        }
                    }
                    fs.Close();
                }
            }

    If you want to change the element name ArrayOfBatches, you could try the following code.

                var doc = XDocument.Load("D:\\test.xml");
    
                foreach (var element in doc.Descendants())
                {
                    if (element.Name == "ArrayOfBatch")
                    {
                        element.Name = "Batches";
                    }
                }
                doc.Save("D:\\test.xml");

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, August 14, 2019 6:10 AM
    Moderator
  • Hi Jack,
    It works as expected. Thanks.
    I don't like loading, renaming save it. Not so good.
    I have found a solution.
    XmlSerializer xs;
    if (newRoot == null)
    	 xs = new XmlSerializer(typeof(T));
    else
    	xs = new XmlSerializer(typeof(T), new XmlRootAttribute(newRoot));
    
    result = (T)xs.Deserialize(fs);
    Can I optimize this code?
    Last question, then I can click on answered.
    xs = new XmlSerializer(typeof(T), newRoot != null ?  new XmlRootAttribute(newRoot) :  XXXXXXXX );
    Best regards Markus
    namespace SerializePart
    {
        [XmlRoot("ORDER")]
        public class Order
        {
            public class Batch
            {
                [XmlAttribute("batchID")]
                public string BatchID { get; set; }
                [XmlAttribute("quantity")]
                public int Quantity { get; set; }
            }
    
            [XmlAttribute("orderNumberScan")]
            public string OrderNumberScan { get; set; }
    
            [XmlArray("BATCHES")]
            [XmlArrayItem("BATCH")]
            public List<Batch> CurrentListBatches;
        }
    
        class Program
        {
            public static readonly object LockObj = new object();
    
            private const string WHOLE_ORDER_FILEPATH = "C:\\Temp\\B_WholeOrder.XML";
            private const string ONLY_LIST_FILEPATH = "C:\\Temp\\B_OnlyTheList.XML";
    
            static void Main(string[] args)
            {
                Order.Batch batch = new Order.Batch();
                batch.BatchID = "test1";
                batch.Quantity = 11;
                Order.Batch batch1 = new Order.Batch();
                batch1.BatchID = "test2";
                batch.Quantity = 12;
                Order.Batch batch2 = new Order.Batch();
                batch2.BatchID = "test3";
                batch2.Quantity = 13;
                Order order = new Order();
                order.OrderNumberScan = "hi";
                var list = new List<Order.Batch>();
                list.Add(batch);
                list.Add(batch1);
                list.Add(batch2);
                order.CurrentListBatches = list;
    
    
    
                string path = WHOLE_ORDER_FILEPATH; // "C:\\temp\\testNewOrder.xml";
                WriteXml<Order>(path, order);
                Order orderFromRead = ReadXml<Order>(path);
    
                path = ONLY_LIST_FILEPATH; // "C:\\temp\\testNewBatchesOnlyPart.xml";
                WriteXml<List<Order.Batch>>(path, order.CurrentListBatches, new XmlRootAttribute("TestPartObjects"));
                list = ReadXml< List<Order.Batch>>(path, "TestPartObjects");
    
                if (list != null)
                {
                    foreach (var item in list)
                    {
                        Console.WriteLine(item.BatchID + " " + item.Quantity);
                    }
                }
    
                Console.ReadKey();
            }
    
            public static void WriteXml<T>(string filename, T template, XmlRootAttribute newRoot = null)
            {
                lock (LockObj)
                {
                    FileStream fs = new FileStream(filename, FileMode.Create );
                    XmlSerializer xs = new XmlSerializer(typeof(T), newRoot);
                    xs.Serialize(fs, template);
                    fs.Close();
                }
            }
    
            public static T ReadXml<T>(string filename, string newRoot = null)
            {
                T result = default(T);
                lock (LockObj)
                {
                    FileStream fs = new FileStream(filename, FileMode.Open);
    
                    XmlSerializer xs;
                    if (newRoot == null)
                         xs = new XmlSerializer(typeof(T));
                    else
                        xs = new XmlSerializer(typeof(T), new XmlRootAttribute(newRoot));
       
                    result = (T)xs.Deserialize(fs);
                   
                    fs.Close();
                }
                return result;
            }
    
    
            public static void Writexml(string filename, Order order)
            {
                lock (LockObj)
                {
                    FileStream fs = new FileStream(filename, FileMode.Create);
                    XmlSerializer xs = new XmlSerializer(typeof(Order));
                    xs.Serialize(fs, order);
                    fs.Close();
                }
            }
    
            public static void Readxml(string filename)
            {
                lock (LockObj)
                {
                    FileStream fs = new FileStream(filename, FileMode.Open);
                    XmlSerializer xs = new XmlSerializer(typeof(Order));
                    Order o = xs.Deserialize(fs) as Order;
                    if (o != null)
                    {
                        var list1 = o.CurrentListBatches;
                        foreach (var item in list1)
                        {
                            Console.WriteLine(item.BatchID + " " + item.Quantity);
                        }
                    }
                    fs.Close();
                }
            }
    
            public void ChangeElementRootname()
            {
    		// ** not good, bad way, needs time
                var doc = XDocument.Load("D:\\test.xml");
    
                foreach (var element in doc.Descendants())
                {
                    if (element.Name == "ArrayOfBatch")
                    {
                        element.Name = "Batches";
                    }
                }
                doc.Save("D:\\test.xml");
            }
        }
    }

    Wednesday, August 14, 2019 4:15 PM
  • Hi Markus,

    Thanks for the feedback.

    >>Can I optimize this code?

    Which code do you want to optimize? Is the following code?

    xs = new XmlSerializer(typeof(T), new XmlRootAttribute(newRoot));

    I think this code is enough to optimize.

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Thursday, August 15, 2019 8:53 AM
    Moderator
  • Hi Jack,
    What's happen if newRoot is null?

    // here no problem
    XmlSerializer xs;
    if (newRoot == null)
      xs = new XmlSerializer(typeof(T));
    else
      xs = new XmlSerializer(typeof(T), new XmlRootAttribute(newRoot));
    
    
    // Shorter version but not work
    xs = new XmlSerializer(typeof(T), newRoot != null ?  new XmlRootAttribute(newRoot) :  XXXXXXXX );
    
    xs = new XmlSerializer(typeof(T), newRoot.? :  XXXXXXXX );
    
    
    I think only this is possible
    XmlSerializer xs;
    //if (newRoot == null)
    //     xs = new XmlSerializer(typeof(T));
    //else
    //    xs = new XmlSerializer(typeof(T), new XmlRootAttribute(newRoot));
    xs = newRoot == null ? new XmlSerializer(typeof(T)) : new XmlSerializer(typeof(T), new XmlRootAttribute(newRoot));


    With best regards Markus



    Thursday, August 15, 2019 4:38 PM
  • Hi Markus,

    Thanks for the feedback.

    >>I think only this is possible

    I think the following code is very streamlined and can't be optimized anymore.

     public static void WriteXml<T>(string filename, T template, XmlRootAttribute newRoot)
            {
                lock (LockObj)
                {
                    FileStream fs = new FileStream(filename, FileMode.Create);
                    XmlSerializer xs;
                    xs = newRoot == null ? new XmlSerializer(typeof(T)) : new XmlSerializer(typeof(T), newRoot);
                    xs.Serialize(fs, template);
                    fs.Close();
                }
            }

    Best Regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.


    Friday, August 16, 2019 5:43 AM
    Moderator