Creating classes from Linq

  • Thread starter Thread starter CSharper
  • Start date Start date
C

CSharper

I have an xml like the following

<Department Name="HR">
<Description>HR in Iowa</Description>
<SubDepartment Name="Payroll">
<Description>Payroll in CR</Description>
<Personal Name=X" Age="30">
<Description>Payroll Executive</Description>
</Personal>
</SubDepartment>
</Department>

I will get an XMl of this type with 1000s of rows, I would like to
create a list of class of Type Department on the fly. I was able to
create it with Linq, byt mine was little ugly. What is the right way
to do?

What is the best way to do it in Linq?

Thanks,
 
CSharper said:
I have an xml like the following
[...]
I will get an XMl of this type with 1000s of rows, I would like to
create a list of class of Type Department on the fly. I was able to
create it with Linq, byt mine was little ugly.

I don't know how "ugly" is your Linq, but I am going to suggest an
alternative: you could create a class with an internal List of Department,
apply (if needed) XML serialization attributes to the List and the
properties of the Department class, and then use the XmlSerializer to
deserialize the XML into your class.
 
I have an xml like the following
[...]
I will get an XMl of this type with 1000s of rows, I would like to
create a list of class of Type Department on the fly. I was able to
create it with Linq, byt mine was little ugly.

   I don't know how "ugly" is your Linq, but I am going to suggest an
alternative: you could create a class with an internal List of Department,
apply (if needed) XML serialization attributes to the List and the
properties of the Department class, and then use the XmlSerializer to
deserialize the XML into your class.

Here is how I am going it

var departmentList = (from dNode in dDocument.Descendants
("Department")
select new SubDepartment()
{
Name= dNode.Attribute("Name").Value,
Description = dNode.Descendants
("Description").First().Value,
SubDepartments = (from sdNode in
dNode.Descendants("SubDepartment")
select new SubDeaprtment()
{
Name = sdNode.Attribute
("Name").Value,
Description =
sdNode.Descendants("Description").First().Value,
Personals= (from pNode in
sdNode.Descendants("Personal")
select new
Personal()
{
Name=
pNode.Attribute("Name").Value,
Age=
int.pharse(pNode.Attribute("Age").Value),
Description
= pNode.Descendants("Description").First().Value
})
})

});

I got this one working fine. Do you think it is the right way to do
it? (Especially for Description part?)

Also, how can I check and see if Age field is available before
assigning the value to age, if the value is not available i want to
default it to 0.

Thanks,
 
CSharper said:
Here is how I am going it
var departmentList = (from dNode in dDocument.Descendants ("Department")
select new SubDepartment()
{
Name= dNode.Attribute("Name").Value,
[...]
});

I got this one working fine. Do you think it is the right way to do
it? (Especially for Description part?)

Well, you are not actually using Linq for much. You just iterate over
the first level nodes of the XML, and then you merely use the XElement
properties and methods to parse the contained node. You could as well have
done this the "old-fashioned" way, by loading the xml into a XmlDocument and
parsing the nodes from there - no Linq required.

As for the "Description" part, yes, I think it is fine. The text inside
an element is the value of the first descendant of that node... unless it
contains other elements inside, so you need to be sure that the schema of
the xml that you are reading is exactly the same as in the sample.
Also, how can I check and see if Age field is available before
assigning the value to age, if the value is not available i want to
default it to 0.

I have not tried this with an XNode, but when using the XmlDocument you
get "null" when you try to extract an attribute that doesn't exist. I expect
a similar behavior from XNode. Since you are already passing the returned
attribute through "int.pharse" (which I presume is an Extension method of
your own), you can modify that method to return zero when it receives null.
 
CSharper said:
Here is how I am going it
var departmentList = (from dNode in dDocument.Descendants ("Department")
                          select new SubDepartment()
                          {
                              Name= dNode.Attribute("Name").Value,
[...]
                          });
I got this one working fine. Do you think it is the right way to do
it? (Especially for Description part?)

    Well, you are not actually using Linq for much. You just iterate over
the first level nodes of the XML, and then you merely use the XElement
properties and methods to parse the contained node. You could as well have
done this the "old-fashioned" way, by loading the xml into a XmlDocument and
parsing the nodes from there - no Linq required.

     As for the "Description" part, yes, I think it is fine. The text inside
an element is the value of the first descendant of that node... unless it
contains other elements inside, so you need to be sure that the schema of
the xml that you are reading is exactly the same as in the sample.
Also, how can I check and see if Age field is available before
assigning the value to age, if the value is not available i want to
default it to 0.

     I have not tried this with an XNode, but when using the XmlDocument you
get "null" when you try to extract an attribute that doesn't exist. I expect
a similar behavior from XNode. Since you are already passing the returned
attribute through "int.pharse" (which I presume is an Extension method of
your own), you can modify that method to return zero when it receives null.

Thank you very much.
 
     I have not tried this with an XNode, but when using the XmlDocument you
get "null" when you try to extract an attribute that doesn't exist.

If you mean XmlElement.GetAttribute(), then it's not true. It doesn't
return null for missing attributes - it returns an empty string, as
per W3C DOM spec. See MSDN docs:

http://msdn.microsoft.com/en-us/library/acwfyhc7.aspx

I expect
a similar behavior from XNode. Since you are already passing the returned
attribute through "int.pharse" (which I presume is an Extension method of
your own), you can modify that method to return zero when it receives null.

For XLINQ, this is a different story. Note that the code looks like
this:

pNode.Attribute("Age").Value

It's not Value that'll be null here if the attribute is missing - it's
Attribute("Age"). If that happens, the call to Value will obviously
throw a NullReferenceException. So it's not that simple.

Apart from the obvious way with an explicit null-check (which requires
several statements), it's also possible to (ab)use the sequence-
returning XElement.Attributes() method to make it a bit shorter,
perhaps at the expense of clarity:

pNode.Attributes("Age").Select(a => a.Value).SingleOrDefault()

The above one-liner will produce a null string for a missing
attribute. And then we can use the coalescing ?? operator to provide a
meaningful default:

Age = int.Parse(pNode.Attributes("Age").Select(a =>
a.Value).SingleOrDefault() ?? "18");
 
Back
Top