Solved

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

Posted on 2013-01-25
3
881 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
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
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…
I designed this idea while studying technology in the classroom.  This is a semester long project.  Students are asked to take photographs on a specific topic which they find meaningful, it can be a place or situation such as travel or homelessness.…

948 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

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now