Hello everyone,
This is my first time to learn LINQ and I need to be able to query data quickly and store the information in an object. Not sure which thread to post this to, but I think C-Sharp Programming should be the correct thread.
Anyway, I have the following string :
I need to be able to read each Param attribute from say, the
section of this XML string.
For instance, i want to be able to read the Description attribute in this section of the above XML :
and then programatically read the rest of the attributes in each PARAM section, say, the Compressed and FileSystem attributes, etc.
and so on...
How do I do this ?
I tried this snippet as an example but it does not work ( I get an exception when I added the commented out lines below )
class Param { public string Description { get; set; } public string Compressed { get; set; } public string FileSystem { get; set; }
public string TotalSpace { get; set; } public string AvailableSpace { get; set; } public string PercentageAvailable { get; set; } public string Volumename { get; set; } public string VolumeSerialNum { get; set; }
};
public class DiskDrives { public string Drive { get; set; } }
XDocument xdoc = Xdocument.Parse(theString);
List LocalDisks = (from drives in
xdoc.Descendants("Disks") select new DiskDrives { Drive = drives.Attribute("Drive").Value, }).ToList(); foreach (var drives in LocalDisks) { Console.WriteLine("Drive: " + drives.Drive.ToString()); var Parameters = from theparam in xdoc.Descendants("Disks") where (theparam.Attribute("Drive").Value == drives.Drive) select new Param { Description = theparam.Element("Param").Attribute("Description").Value, // Note, I had to comment the next two lines out as they were causing // exceptions. // My intent is to capture the rest of the attributes in the // above XML string // Compressed = theparam.Element("Param").Attribute("Compressed").Value, //FileSystem = theparam.Element("Param").Attribute("FileSystem").Value, };
foreach (var item in Parameters) { Console.WriteLine("Item: " + item.Description); // I get the correct value here "Local Fixed Disk" Console.WriteLine("Item: " + item.Compressed); // The value should be "No" Console.WriteLine("Item: " + item.FileSystem); // The value should be "NTFS" } } |
In the above code, the commented out lines cause exceptions.
I am able to get the Description attribute of the first
section, but do not know how I can get the other attributes programatically ( e.g., the Compressed and FileSystem attributes ).
Your help/advise regarding this matter will be highly appreciated.
jingePosted May 6, 2010, 8:57 PM
NathanielPosted May 6, 2010, 11:55 AM
You are indeed very helpful and my hats off to you for your patience in helping this greenie.
I looked at the XML string again and I did notice that the Param sections consist of Key/Value pairs that need to be captured in some sort of Key/Val data structure ( for instance, Description is a key and "Local Fixed Disk" is the value ).
Hence, I modified the code to look like this ( modified the class to capture the XML data ):
---------------------------------------------------------------------------------------------------------------------------
public class DiskDrives
{
public string DriveName { get; set; }
public SortedList<string, string> DiskParams; // Intended to be Key/Val pair
} // End class DiskDrives
I then modified the LINQ code as follows
---------------------------------------------------------------------------------------------------------
XDocument xdoc = XDocument.Parse(Properties.Resources.TheString);
// Get Data for the LocalFixeDisk section --- Drive and corresponding Parameters
ListWksDrives =
(from drives in xdoc.Descendants("Disks")
select new DiskDrives{
DriveName = drives.Attribute("Drive").Value,
}).ToList<DiskDrives>();
// From hereon, we get the Param key/val pairs
int cnt = ListWksDrives.Count();
foreach (var drives in ListWksDrives)
{
Console.WriteLine("Drive: " + drives.DriveName.ToString());
drives.DiskParams = new SortedList<string, string>(cnt);
foreach (XElement elem in xdoc.Descendants("Disks"))
{
var MyParams = elem.Elements("Param");
foreach (XElement elem1 in MyParams)
{
Console.WriteLine(" Key/Val : " + elem1.FirstAttribute.Name + "/" +
elem1.FirstAttribute.Value);
if (elem.Attribute("Drive").Value.ToString() == drives.DriveName){
drives.DiskParams.Add(elem1.FirstAttribute.Name.ToString(),
elem1.FirstAttribute.Value.ToString());
}
}
}
}// End foreach (var drives in ListWksDrives)
Console.WriteLine("************ DISK INFO *****************");
Console.WriteLine();
for (int i=0; i < ListWksDrives.Count; i++)
{
Console.WriteLine("Disk Drive: " + ListWksDrives[i].DriveName);
foreach (KeyValuePair<string, string> keyValPair in ListWksDrives[i].DiskParams)
{
Console.WriteLine("Key:" + keyValPair.Key + " Value: " + keyValPair.Value);
}
}
jingePosted May 3, 2010, 10:37 PM
jingePosted May 3, 2010, 10:35 PM
First I'd like to point out that the xml have two errors. Obviously, the last element does not have a close dash. But this is not the problem of the exception.
In you linq - xml query, you don't have error checking code, you need to check if the attribute is null before calling value property, otherwise , it's possibly you get null reference exception.
The corrected xml is in the following:
To get rid of the exception:
Try change your code to the following:
List
xdoc.Descendants("Disks")
select new DiskDrives
{
Drive = drives.Attribute("Drive").Value,
}).ToList
foreach (var drives in LocalDisks)
{
Console.WriteLine("Drive: " + drives.Drive.ToString());
var Parameters = from theparam in xdoc.Descendants("Disks")
where (theparam.Attribute("Drive").Value == drives.Drive)
select new Param
{
Description = theparam.Element("Param").Attribute("Description") == null ? String.Empty : theparam.Element("Param").Attribute("Description").Value,
// Note, I had to comment the next two lines out as they were causing // exceptions.
// My intent is to capture the rest of the attributes in the // above XML string
Compressed = theparam.Element("Param").Attribute("Compressed") == null ? String.Empty : theparam.Element("Param").Attribute("Compressed").Value,
FileSystem = theparam.Element("Param").Attribute("FileSystem") == null ? String.Empty : theparam.Element("Param").Attribute("FileSystem").Value
};
foreach (var item in Parameters)
{
Console.WriteLine("Item: " + item.Description); // I get the correct value here "Local Fixed Disk"
Console.WriteLine("Item: " + item.Compressed); // The value should be "No"
Console.WriteLine("Item: " + item.FileSystem); // The value should be "NTFS"
}
}
But are you sure you only want to display the value of the attributes of the first element? If not you may switch to the following code snippet and see if it is what you want:
select new Param
{
//Description = (theparam.Attribute("Description").Value ?? string.Empty),
//Compressed = (theparam.Attribute("Compressed").Value ?? String.Empty),
//FileSystem = (theparam.Attribute("FileSystem")Value ?? string.Empty)
Description = theparam.Attribute("Description") == null ? string.Empty : theparam.Attribute("Description").Value,
Compressed = theparam.Attribute("Compressed") == null ? string.Empty : theparam.Attribute("Compressed").Value,
FileSystem = theparam.Attribute("FileSystem") == null ? string.Empty : theparam.Attribute("FileSystem").Value
};
foreach (var item in Parameters)
{
Console.WriteLine("Item: " + item.Description); // I get the correct value here "Local Fixed Disk"
Console.WriteLine("Item: " + item.Compressed); // The value should be "No"
Console.WriteLine("Item: " + item.FileSystem); // The value should be "NTFS"
}