Reputation: 3905
Please review below code and advice what needs to be done in order to get the additional last line in output as shown in expected output
class test {
static void Main(string[] args)
{
XDocument doc = XDocument.Load("E:\\BI_analytics\\Data\\so.xml");
var query = from test in doc.Descendants("tester")
from testreq in test.Descendants("testRequest")
from testresp in test.Descendants("testResponse")
let id = testreq.Element("id") == null ? string.Empty : testreq.Element("id").Value
// select id;
from itm in testresp.Descendants("item")
select new
{
ID = (string)id,
Name = (string)itm.Attribute("itemname"),
Code = (string)itm.Attribute("itemocde"),
};
foreach (var result in query)
{
Console.WriteLine(result);
}
}
}
Current output
{ ID = 2, Name = test item1, Code = 111 } { ID = 2, Name = test item2, Code = 222 } { ID = 3, Name = test item3, Code = 333 } { ID = 3, Name = test item4, Code = 444 }
Expected output
{ ID = 2, Name = test item1, Code = 111 } { ID = 2, Name = test item2, Code = 222 } { ID = 3, Name = test item3, Code = 333 } { ID = 3, Name = test item4, Code = 444 } { ID = 4, Name = , Code = }
<?xml version="1.0" encoding="utf-8"?>
<root>
<tester>
<testRequest>
<id>2</id>
</testRequest>
<testResponse>
<items>
<item itemname="test item1" itemocde="111"/>
<item itemname="test item2" itemocde="222"/>
</items>
</testResponse>
</tester>
<tester>
<testRequest>
<id>3</id>
</testRequest>
<testResponse>
<items>
<item itemname="test item3" itemocde="333"/>
<item itemname="test item4" itemocde="444"/>
</items>
</testResponse>
</tester>
<tester>
<testRequest>
<id>4</id>
</testRequest>
<testResponse>
<items />
</testResponse>
</tester>
</root>
Upvotes: 1
Views: 83
Reputation: 935
I use a class to help me return values even if it is null that looks like this:
public static class LinqToXMLUtility
{
/// <summary>
/// Used to Get check the XElement Value and return
/// empty string if it is null (used for optional or missing xml items)
/// </summary>
/// <param name="pElement"></param>
/// <param name="pstrElementName"></param>
/// <returns></returns>
public static string GetXElementValue(XElement pElement, string pstrElementName)
{
string strRet = string.Empty;
try
{
XElement lElement = pElement.Element(pstrElementName);
if (lElement != null)
{
strRet = lElement.Value;
}
}
catch { }
return strRet;
}
}
And use it like so.
class test
{
static void Main(string[] args)
{
XDocument doc = XDocument.Load("E:\\BI_analytics\\Data\\so.xml");
var query = from test in doc.Descendants("tester")
from testreq in test.Descendants("testRequest")
from testresp in test.Descendants("testResponse")
let id = testreq.Element("id") == null ? string.Empty :
testreq.Element("id").Value
// select id;
from itm in testresp.Descendants("item")
select new
{
ID = LinqToXMLUtility.GetXElementValue(itm, "id"),
Name = LinqToXMLUtility.GetXElementValue(itm, "itemname"),
Code = LinqToXMLUtility.GetXElementValue(itm, "itemocde"),
};
foreach (var result in query)
{
Console.WriteLine(result);
}
}
}
Upvotes: 3
Reputation: 1500505
This is the problem:
from itm in testresp.Descendants("item")
You don't have any item
elements, so you probably want:
from itm in testresp.Descendants("item").DefaultIfEmpty()
... at which point you need:
select new
{
ID = (string)id,
Name = itm == null ? "" : (string)itm.Attribute("itemname"),
Code = itm == null ? "" : (string)itm.Attribute("itemocde"),
};
Upvotes: 2