Solved

Deserialize XML string that contains an array of "an array of elements"

Posted on 2013-01-25
3
896 Views
Last Modified: 2016-10-14
I am using vs 2012, vb.net, .net 4.0 and I need to deserialize the following XML:

<?xml version="1.0" encoding="UTF-8"?>
-<data>
      -<apps>
            -<item>
                  <name>xxx</name>
                  <folder>c:\web\xxx</folder>
                  <version>2.xxx</version>
                  -<bindings>
                        <item>www.example.com</item>
                        <item>beta.xxx.com</item>
                  </bindings>
            </item>
            -<item>
                  <name>xxx</name>
                  <folder>c:\web\xxx</folder>
                  <version>3.xxx</version>
                  -<bindings>
                        <item>www.example.com</item>
                        <item>xxx:*</item>
                  </bindings>
            </item>
            -<item>
                  <name>xxx</name>
                  <folder>c:\web\xxx</folder>
                  <version>3.xxx</version>
                  -<bindings>
                        <item>*</item>
                  </bindings>
            </item>
      </apps>
</data>

I created the following structure (in Class Pong):


    Public Structure data
        <XmlArray>
        <XmlArrayItem("item")>
        Public apps As List(Of dataItem)
    End Structure

    Public Structure dataItem
        Public name As String
        Public folder As String
        Public version As String
        <XmlArray>
        <XmlArrayItem("item")>
        Public bindings As List(Of bindingItem)
    End Structure

    Public Structure bindingItem
        Public item As String
    End Structure



I use the following to deserialize the XML into the Pong.data structure:

     Dim serializer As New XmlSerializer(GetType(Distribute.data))
     Dim settings As New XmlReaderSettings()

     Using textReader As New StringReader(sXML)
         Using xmlReader__1 As XmlReader = XmlReader.Create(textReader, settings)
             oMasterData = DirectCast(serializer.Deserialize(xmlReader__1), Distribute.data)
         End Using
     End Using


I get the correct array of information in oMasterData for the various "item" array (name, folder and version) but
the inner array for bindings comes back with a length=0.

I found many examples of similar deserializations but each falls short when
the main structure is an array and in the elements of that array another array occurs.

I had a suspision that a problems occurs when both arrays are called "item".

Any code examples (either vb or C#, C++) would be appreciated.
0
Comment
Question by:cnxmax
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
3 Comments
 
LVL 4

Accepted Solution

by:
mcmahon_s earned 500 total points
ID: 38823480
Well, the good news is you are right. Multiple occurrences of "item" is what is causing the issue. The bad news is there is no easy way out of this. You either need to transform you xml so the one of the item tags are renamed or process the xml more manually i.e. reading one element at a time and loading it into your class.
0
 
LVL 16

Expert Comment

by:hjgode
ID: 38823599
Hello

I have done that in the past using Class definitions with arrays.

The important snippets are:

        [XmlRootAttribute("Subsystem")]
        public class SubSystem{
            [XmlElement("Group")]
            public Group[] groups;
            [XmlAttribute("Name")]
            public string sName{get; set;}

Open in new window


You see that groups is an array of Group objects. Then the Group class again references another array:

        public class Group{
            [XmlElement("Field")]    
            public Field[] fields;
            [XmlAttribute("Name")]
            public string sName{get; set;}
            public void Display(){
                Console.WriteLine(sName);
                foreach(Field f in fields){
                    f.Display();
                }
            }
            private string _shortName;
            public string shortName{
                get{return _shortName;}
                set{string[] s=value.Split(new char[]{'\\'});
                    _shortName=s[s.Length-1];
                }
            }
        }

        public class Field{
            private string _shortName;
            public string sShortName{
                get{return _shortName;}
            }
       ...

Open in new window


So, we can have one or more Group TAGs inside a subsystem TAG and that can contain one more Field TAGs.

The xml has groups and therein you can have additional (sub) groups and fields. Here is an excerpt of an xml:

<?xml version="1.0" encoding="UTF-8"?>
	<DevInfo Action="Set" Persist="true" SeqNo="165">
	<!-- SETTINGS -->
	    <Subsystem Name="Data Collection">
	        <Group Name="Scanners" Instance="0">
	            <Group Name="Symbologies">
	                <Group Name="Code 39">
	                    <Field Name="Enable Code 39">1</Field>
	                    <Group Name="Options">
	                        <Field Name="Full ASCII Conversion">0</Field>
	                        <Field Name="Start/Stop transmission">0</Field>
	                        <Field Name="Start character">2</Field>
	                        <Field Name="Verify check digit">0</Field>
	                        <Field Name="Transmit check digit">0</Field>
	                        <Field Name="Reading range">1</Field>
	                        <Field Name="Reading tolerance">0</Field>
	                        <Field Name="Length mode">0</Field>
	                        <Field Name="Length 1">3</Field>
	                        <Field Name="Length 2">3</Field>
	                        <Field Name="Length 3">3</Field>
	                        <Field Name="User defined symbology ID">B1</Field>
	                    </Group>
	                </Group>
	                <Group Name="UPC/EAN">
	                    <Field Name="Enable UPC A">1</Field>
	                    <Field Name="Enable UPC E">1</Field>
	                    <Field Name="Enable EAN 8">1</Field>
	                    <Field Name="Enable EAN 13">1</Field>
	                    <Field Name="Enable UPC-E1">0</Field>
          ...

Open in new window


Here is the code I sue to serialze/deserialize such xml's:
    using System;
    using System.IO;
    using System.Xml;
    using System.Xml.Serialization;
    using System.Collections;
    using System.Collections.Generic;

    // based on http://drdobbs.com/windows/184416669?pgno=2

    namespace ITCDeviceMonitor
    {
        [XmlRootAttribute("Subsystem")]
        public class SubSystem{
            [XmlElement("Group")]
            public Group[] groups;
            [XmlAttribute("Name")]
            public string sName{get; set;}
            
           public void Display() // 
            {
                Console.WriteLine(sName);
                foreach (Group g in groups)
                {
                    g.Display();
                }
            }
            public static SubSystem deserialize(string sXMLfile){
                XmlSerializer xs = new XmlSerializer(typeof(SubSystem));
                //StreamReader sr = new StreamReader("./SystemHealth.xml");
                StreamReader sr = new StreamReader(sXMLfile);
                SubSystem s = (SubSystem)xs.Deserialize(sr);
                sr.Close();
                return s;
            }
            public static void serialize(SubSystem subsys, string sXMLfile){
                XmlSerializer xs = new XmlSerializer(typeof(SubSystem));
                //omit xmlns:xsi from xml output
                //Create our own namespaces for the output
                XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                //Add an empty namespace and empty value
                ns.Add("", "");
                //StreamWriter sw = new StreamWriter("./SystemHealth.out.xml");
                StreamWriter sw = new StreamWriter(sXMLfile);
                xs.Serialize(sw, subsys, ns);
            }
        }
        
        public class Group{
            [XmlElement("Field")]    
            public Field[] fields;
            [XmlAttribute("Name")]
            public string sName{get; set;}
            public void Display(){
                Console.WriteLine(sName);
                foreach(Field f in fields){
                    f.Display();
                }
            }
            private string _shortName;
            public string shortName{
                get{return _shortName;}
                set{string[] s=value.Split(new char[]{'\\'});
                    _shortName=s[s.Length-1];
                }
            }
        }
        
        public class Field{
            private string _shortName;
            public string sShortName{
                get{return _shortName;}
            }
            private string _sName;
            [XmlAttribute("Name")]
            public string sName{
                get{return _sName;} 
                set{
                    _sName=value;
                    string[] s = value.Split(new char[]{'\\'});
                    _shortName=s[s.Length-1];
                }
            }
            
            [XmlAttribute("Type")]
            public string sType{get; set;}
            [XmlText(typeof(string))]
            public string sValue{get; set;}
            
            // This field shouldn't be serialized 
               // if it is uninitialized.
            //[XmlAttribute("Error")]
            public string sError{get;set;}
            
            public void Display(){
                Console.WriteLine(_shortName + " " + sType + " "  + sValue + " ");
            }
        }
    }

Open in new window

0
 

Author Closing Comment

by:cnxmax
ID: 38931282
Changed second occurance of item to BindingItem ... all is well.
0

Featured Post

Creating Instructional Tutorials  

For Any Use & On Any Platform

Contextual Guidance at the moment of need helps your employees/users adopt software o& achieve even the most complex tasks instantly. Boost knowledge retention, software adoption & employee engagement with easy solution.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
VB.Net - String Manipulation Scenario 2 29
Easy filter aspnet 2 35
VB.Net creating Contact in Outlook 1 55
reading an excel file vb.net 2 17
For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

733 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question