Solved

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

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

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
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…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…

707 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

15 Experts available now in Live!

Get 1:1 Help Now