Reading Multi level XML file while using C#
What would be the easiest way to manipulate the data being mindful that i am really working with an XML file that I have imported into memory:
<Data>
<Drives>
<label>Area 51</label>
<date>12/10/2012</date>
<Description>testing site</Description>
<Status>valid</Status>
<Membership>
Username="Jsmith"
Bool="or"
username="MGordon"
</Membership>
</Drives>
<Drives>
<label>Apollo</label>
<date>12/04/2010</date>
<Description>fly to the Moon</Description>
<Status>Terminated</Status>
<Membership>
Username="DKerr"
bool="and"
Username="Sremi"
bool="or"
Group="ApolloReadOnly"
</Membership>
</Drives>
<Drives>
<label>Deep Impact</label>
<date>12/06/08</date>
<Description>Exploring Comet Temple</Description>
<Status>Achieved</Status>
<Membership>
<collection>
Username="Gblaine"
Group="SSnype"
group="Wesson"
bool="or"
Computer="Exec-02"
</Collection>
</Membership>
</Drives>
<Data>
Ideally, I would need this:
LabeL Date Description Status Membership
Area 51 12/10/2012 Testing Site valid Jsmtih or MGordon
Apollo 12/04/2010 fly to the Moon Terminated DKerr and Sremi or AppollyReadonly
Deep impact 12/06/12 Exploring.. Achived this collection is true (GBlaine or SSnype or WEsson or computer=EXec-02)
Please keep in mind that I am beginnger at this stage.
Thanks.
Re: Reading Multi level XML file while using C#
You can easily read this data with xml serialization. I can show you how to do it with a couple of simple classes using xml attributes.
But first, I need to ask if you have the ability to alter the xml schema. Your existing xml snippet has some inconsistencies. Can you modifiy that or is it fixed?
Re: Reading Multi level XML file while using C#
Quote:
Originally Posted by
Arjay
You can easily read this data with xml serialization. I can show you how to do it with a couple of simple classes using xml attributes.
But first, I need to ask if you have the ability to alter the xml schema. Your existing xml snippet has some inconsistencies. Can you modify that or is it fixed?
What are the inconsistencies? If you're talking about the data between the membership tags then this is exactly the challenge with this problem.
Re: Reading Multi level XML file while using C#
Quote:
Originally Posted by
grego1533
What are the inconsistencies? If you're talking about the data between the membership tags then this is exactly the challenge with this problem.
Well you've got different casing within the tags. Usually xml tags are pascal case (start with a capital letter) or camel case (start with a lower case letter). You can certainly have a mix but it's a bit odd.
As far as 'collection' element inside the 'Membership' element... that's okay, but the opening tag must exactly match the closing tag. You have <collection>...</Collection> and that isn't valid xml.
Re: Reading Multi level XML file while using C#
Quote:
Originally Posted by
Arjay
Well you've got different casing within the tags. Usually xml tags are pascal case (start with a capital letter) or camel case (start with a lower case letter). You can certainly have a mix but it's a bit odd.
As far as 'collection' element inside the 'Membership' element... that's okay, but the opening tag must exactly match the closing tag. You have <collection>...</Collection> and that isn't valid xml.
You're correct, I have made up the example but the actual data does follow the same concept that you outlined above. I originally shredded the XML in SQL but the unpredictability of the membership tag is painful to manipulate. Thanks for everything!
1 Attachment(s)
Re: Reading Multi level XML file while using C#
Okay. You can do this with 4 classes and some XmlAttributes on the class properties.
First the xml.. I fixed up the xml to make it consistent and valid xml.
Code:
<?xml version="1.0" encoding="utf-8" ?>
<data>
<drive>
<label>Area 51</label>
<date>12/10/2012</date>
<description>testing site</description>
<status>Valid</status>
<membership>
Username="Jsmith"
Bool="or"
username="MGordon"
</membership>
</drive>
<drive>
<label>Apollo</label>
<date>12/04/2010</date>
<description>fly to the Moon</description>
<status>Terminated</status>
<membership>
Username="DKerr"
bool="and"
Username="Sremi"
bool="or"
Group="ApolloReadOnly"
</membership>
</drive>
<drive>
<label>Deep Impact</label>
<date>12/06/08</date>
<description>Exploring Comet Temple</description>
<status>Achieved</status>
<membership>
<collection>
Username="Gblaine"
Group="SSnype"
group="Wesson"
bool="or"
Computer="Exec-02"
</collection>
</membership>
</drive>
</data>
Next the serialization classes. The Data class is the 'root' class that contains a static Load method. This loads the xml file into a reader, then deserializes it into the Data (and other) class instances.
Code:
using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Serialization;
namespace CG.MultiLevelXml.Serialization
{
public enum Status
{
Achieved = 0,
Terminated = 1,
Valid = 2
}
[XmlType(AnonymousType = true)]
[XmlRoot(ElementName = "data", Namespace = "", IsNullable = false)]
public class Data
{
public static Data Load(string xmlFile)
{
var serializer = new XmlSerializer(typeof (Data));
using( var reader = XmlReader.Create(xmlFile))
{
return (Data) serializer.Deserialize(reader);
}
}
/// <summary>
/// Drive list
/// </summary>
/// <remarks>
/// No te: Use a generic collection here to 'back' the drive array.
/// That way client code won't have to check for Drives == null
/// </remarks>
[XmlElement( "drive" )]
public Drive[] Drives
{
get
{
if( _driveList == null )
{
_driveList = new List<Drive>();
}
return _driveList.ToArray();
}
set
{
if ( _driveList == null )
{
_driveList = new List<Drive>( );
}
if(value != null)
{
_driveList.AddRange(value);
}
}
}
private List<Drive> _driveList = new List<Drive>();
}
public class Drive
{
[XmlElement("label")]
public string Label { get; set; }
[XmlElement( "date" )]
public string Date { get; set; }
[XmlElement("description")]
public string Description { get; set; }
[XmlElement( "status" )]
public Status Status { get; set; }
[XmlElement( "membership" )]
public Membership Membership { get; set; }
/// <summary>
/// Use this property to retrieve the MemberShip or Collection value
/// </summary>
[XmlIgnore]
public string MembershipValue
{
get
{
return IsCollection ? Membership.Collection.Value : Membership.Value;
}
}
/// <summary>
/// Use this property to determine if Membership or Collection
/// </summary>
[XmlIgnore]
public bool IsCollection
{
get
{
return (Membership != null && Membership.Collection != null);
}
}
/// <summary>
/// Override to format an output string
/// </summary>
/// <returns></returns>
public override string ToString( )
{
return String.Format("{0,-15}{1,-15}{2,-30}{3,-12}{4,-14}{5}", Label, Date, Description, Status, IsCollection, MembershipValue);
}
}
public class Membership
{
[XmlText]
public string Value { get; set; }
[XmlElement( "collection", IsNullable = true)]
public Collection Collection { get; set; }
}
public class Collection
{
[XmlText]
public string Value { get; set; }
}
}
Finally, using the class...
Code:
using System;
using CG.MultiLevelXml.Serialization;
namespace CG.MultiLevelXml
{
class Program
{
static void Main( string [ ] args )
{
var data = Data.Load("data.xml");
Console.WriteLine( "{0,-15}{1,-15}{2,-30}{3,-12}{4,-14}{5}\n", "Label", "Date", "Description", "Status", "IsCollection", "MembershipValue" );
foreach(var drive in data.Drives)
{
Console.WriteLine(drive);
}
}
}
}
Output:
Code:
Label Date Description Status IsCollection MembershipValue
Area 51 12/10/2012 testing site Valid False
Username="Jsmith"
Bool="or"
username="MGordon"
Apollo 12/04/2010 fly to the Moon Terminated False
Username="DKerr"
bool="and"
Username="Sremi"
bool="or"
Group="ApolloReadOnly"
Deep Impact 12/06/08 Exploring Comet Temple Achieved True
Username="Gblaine"
Group="SSnype"
group="Wesson"
bool="or"
Computer="Exec-02"
See the attached project solution.