Converting xml to hierarchical data in c# with classes -


i have class goes , gets data database , gets xml data in form of hierarchical data.

below sample of data:

<securitygroups> <securitygroup>     <id>1</id>     <name>view</name> </securitygroup> <securitygroup>     <id>2</id>     <name>fill</name>     <securityusers>         <securityuser>             <securityid>2</securityid>             <userid>2</userid>             <username>fill</username>         </securityuser>         <securityuser>             <securityid>2</securityid>             <userid>3</userid>             <username>fillone</username>         </securityuser>         <securityuser>             <securityid>2</securityid>             <userid>4</userid>         <username/></securityuser>     </securityusers> </securitygroup> <securitygroup>     <id>3</id>     <name>update</name>     <securityusers>         <securityuser>             <securityid>3</securityid>             <userid>5</userid>             <username>update</username>         </securityuser>         <securityuser>             <securityid>3</securityid>             <userid>6</userid>             <username>updateone</username>         </securityuser>     </securityusers> </securitygroup> <securitygroup>     <id>4</id>     <name>admin</name>     <securityusers>         <securityuser>             <securityid>4</securityid>             <userid>1</userid>             <username>jtays</username>         </securityuser>     </securityusers> </securitygroup> 

which works great! now, have class uses reflection convert xml models going use in treeview. below entire class.

the models are:

[xmlrootattribute(namespace = "", isnullable = false)] public class securitygroup {     [xmlelementattribute(form = xmlschemaform.unqualified)]     public int id { get; set; }     [xmlelementattribute(form = xmlschemaform.unqualified)]     public string name { get; set; }     [xmlelementattribute("securityuser",         form = xmlschemaform.unqualified)]     public list<securityuser> securityusers { get; set; } }  public class securityuser:ientity {     [xmlelement(form = xmlschemaform.unqualified)]     public int securityid { get; set; }     [xmlelementattribute(form = xmlschemaform.unqualified)]     public int userid { get; set; }     [xmlelementattribute(form = xmlschemaform.unqualified)]     public string username { get; set; }      public int id { get; set; } } 

here class converts.

    public class adminmanager : iadminservice {     public ienumerable<securitygroup> securitygroups()     {         ienumerable<securitygroup> list = null;         xmldocument xmldoc = new xmldocument();         using (var c = new fmcontext())         {             var xmldata = c.database.sqlquery<string>("allsecurtyusersproc").firstordefault();             if (xmldata != null)             {                 xmldoc.loadxml(xmldata);                 list = convertxmltoclass<securitygroup>(xmldoc, "/securitygroups/securitygroup");             }         }         return list;     }      public static ienumerable<t> convertxmltoclass<t>( xmldocument doc, string nodestring)         t:class, new()     {         var xmlnodes = doc.selectnodes(nodestring);         list<t> list = new list<t>();         foreach (xmlnode node in xmlnodes)         {             var item = getnewitem<t>(node);             list.add(item);         }         return list;     }      public static t getnewitem<t>(xmlnode node)         t:class, new()     {         var type = typeof (t);         var item = new t();         var properties = type.getproperties();         foreach (var property in properties)         {             var propertytype = property.propertytype;             var propertyname = property.name;             object value = null;             if (isenumerable(property))             {                 value = getnodecollectionvalue(property,node);             }             else             {                 value = getnodevalue(node, propertyname);             }             if (value!=null)             {                 property.setvalue(item, convert.changetype(value, propertytype), null);             }          }         return item;     }      private static object getnodecollectionvalue(propertyinfo property, xmlnode node)     {         var doc = new xmldocument();         var itemtype = property.propertytype.generictypearguments[0];         var xml = $"<{property.name}><{itemtype.name}>{node.innerxml}</{itemtype.name}></{property.name}>";         doc.loadxml(xml);         if (itemtype != null)         {             var type = typeof (adminmanager);             var methodinfo = type.getmethod("convertxmltoclass");             if (methodinfo!=null)             {                 var method = methodinfo.makegenericmethod(itemtype);                 if (method != null)                 {                     object[] args = {doc, property.name};                     object result = method.invoke(null, args);                     return result;                 }             }          }          return new object();     }       private static bool isenumerable(propertyinfo property)     {         var type = property.propertytype;         return typeof (ienumerable).isassignablefrom(type) && type.isgenerictype;     }      private static object getnodevalue(xmlnode node, string nodename)     {         var = node[nodename]?.innertext;         return ?? null;     } } 

okay, issue. problem when converts doesn't correct data securtyusers classes adds them object, null or 0. can me figure out went worng?

first: example xml doesn't include closing tag </securitygroups>.

in getnodecollectionvalue pass property.name shouldn't property.name + "/" + itemtype.name because want access children of node?

additionally node.innerxml not traversed, pass same node again , again.

i highly recommend using .net xml deserializer instead of reinventing wheel.


generate xml schema xml example. afterwards create .net classes xsd. pass xml server stringreader , deserialize using reader. access securitygroup class instance.

[update] show usage

create xml schema either manually or using xsd.exe (you need windows sdk). see examples.

  • create sample.xml file, content example
  • locate , run xsd tool xsd sample.xml /outputdir:xmlserialization
  • a .xsd file should generated, may want modify element types
    • for example securitygroup.id maybe auto-generated xs:string, change i.e. xs:int
    • or remove minoccurs="0" @ securityuser.userid if know property set
    • you maybe have fix securitygroup.securityusers from
<xs:element name="securityusers" minoccurs="0" maxoccurs="unbounded">     <xs:complextype>         <xs:sequence>             <xs:element name="securityuser" minoccurs="0" maxoccurs="unbounded"> 

to

<xs:element name="securityusers" minoccurs="0">     <xs:complextype>         <xs:sequence>             <xs:element name="securityuser" maxoccurs="unbounded"> 
  • run xsd tool using xsd xsd sample.xsd /outputdir:xmlserialization /c
  • a .cs file should generated, verify
    • i needed fix xsd manually because i.e. securitygroup.securityuser generated 2-dim array
  • use auto-generated classes in project / script
  • create xmlserializer - see example - , deserialize xml string, access data afterwards
securitygroups deserialized; var serializer = new system.xml.serialization.xmlserializer(typeof(securitygroups)); using (var stringreader = new system.io.stringreader(xmldata)) {     deserialized = serializer.deserialize(stringreader) securitygroups; } 
  • see manually fixed xsd here, verified working sample data

Comments