Reading all matches from attribute value XML C# - c#

I have a code which retrieves only one value from the xml file using xmlreader.
<recordset>
<itemidlist>
<itemid idtype = "plant">787484545</itemid>
<itemid idtype = "seed">659988222</itemid>
</itemidlist>
<itemidlist>
<itemid idtype = "plant">90327328</itemid>
<itemid idtype = "seed">099849999</itemid>
</itemidlist>
<itemidlist>
<itemid idtype = "plant">34545488</itemid>
<itemid idtype = "seed">787555444</itemid>
</itemidlist>
</recordset>
And C# coded this entry:(s is the xml file)
using (var reader = XmlReader.Create(s))
{
var nodecount = 0;
var plant = "";
var seed = "";
var typeid = false;
var typeid2 = false;
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element &&
reader.Name == "recordset")
{
nodecount++;
}
if (reader.NodeType == XmlNodeType.Element &&
reader.Name == "itemid")
{
var idtype = reader.GetAttribute("idtype");
typeid = idtype == "plant";
typeid2 = idtype == "seed";
}
while (typeid && reader.NodeType == XmlNodeType.Element &&
reader.Name == "itemid")
{
plant = reader.ReadInnerXml();
}
while (typeid2 && reader.NodeType == XmlNodeType.Element &&
reader.Name == "itemid")
{
seed = reader.ReadInnerXml();
}
}
}
and this happens when a add to datagridview:
Only one record was found:
Plant Seed
787484545 659988222

You're only setting on seed and one plant variable, so if any more than one value is found it will be overwritten. How do you propose to return multiple values?
Any reason not to use LINQ to XML for this?
var doc = XDocument.Load(s);
var plants = doc.Descendants("itemid")
.Where(x => (string) x.Attribute("idtype") == "plant")
.Select(x => x.Value);
var seeds = doc.Descendants("itemid")
.Where(x => (string) x.Attribute("idtype") == "seed")
.Select(x => x.Value);
See this fiddle for a working demo.

Related

How to convert System.Web.Mvc.SelectListItem to list

I want to display data using datatable so my hard coded System.Web.Mvc.SelectListItem value and text collect and make a list using linq but get error System.Linq.Enumerable+WhereSelectListIterator`2[System.Web.Mvc.SelectListItem,System.String]
var parentkeylist = clsDataCache.GetPriorityList().ToList();
var parentkeylist = clsDataCache.GetPriorityList().ToList();//this is SelectListItem
List data = this.GetAllStpOrganizationEntityData(input);
foreach (stp_organizationentityEntity obj in data)
{
if (obj.parentkey != null)
{
obj.priotytext = parentkeylist.Where(x => x.Value == obj.parentkey.ToString()).Select(x => x.Text).Cast<string>().ToString();//not cast Text value get error System.Linq.Enumerable+WhereSelectListIterator`2[System.Web.Mvc.SelectListItem,System.String]
}
else
{
obj.priotytext = "Root";
}
}
if (data != null && data.Count > 0)
{
long totalRecords = data.FirstOrDefault().RETURN_KEY;
var tut = (from t in data
select new
{
t.entityname,
t.organizationkey,
t.priotytext,
t.entirytypekey,
t.entitylevel,
//t.seqfirstindex,
//t.seqfullindex,
// t.entitycpde,
//t.description,
t.isactive,
ex_nvarchar1 = objSecPanel.genButtonPanel(t.entitykey.GetValueOrDefault(-99), "entitykey", this.HttpContext.User.Identity as ClaimsIdentity,
"StpOrganizationEntity/StpOrganizationEntityUpdate", "EditStpOrganizationEntity", "StpOrganizationEntity/StpOrganizationEntityDelete", "DeleteStpOrganizationEntity",
"StpOrganizationEntity/StpOrganizationEntityDetails", "StpOrganizationEntityDetails")
}).ToList();
}
var parentkeylist = clsDataCache.GetPriorityList().ToList();
var parentkeylist = clsDataCache.GetPriorityList().ToList();//this is SelectListItem
List data = this.GetAllStpOrganizationEntityData(input);
foreach (stp_organizationentityEntity obj in data)
{
if (obj.parentkey != null)
{
obj.priotytext = parentkeylist.Where(x => x.Value == obj.parentkey.ToString()).Select(x => x.Text).Cast<string>().ToString();//not cast Text value get error System.Linq.Enumerable+WhereSelectListIterator`2[System.Web.Mvc.SelectListItem,System.String]
}
else
{
obj.priotytext = "Root";
}
}
if (data != null && data.Count > 0)
{
long totalRecords = data.FirstOrDefault().RETURN_KEY;
var tut = (from t in data
select new
{
t.entityname,
t.organizationkey,
t.priotytext,
t.entirytypekey,
t.entitylevel,
//t.seqfirstindex,
//t.seqfullindex,
// t.entitycpde,
//t.description,
t.isactive,
ex_nvarchar1 = objSecPanel.genButtonPanel(t.entitykey.GetValueOrDefault(-99), "entitykey", this.HttpContext.User.Identity as ClaimsIdentity,
"StpOrganizationEntity/StpOrganizationEntityUpdate", "EditStpOrganizationEntity", "StpOrganizationEntity/StpOrganizationEntityDelete", "DeleteStpOrganizationEntity",
"StpOrganizationEntity/StpOrganizationEntityDetails", "StpOrganizationEntityDetails")
}).ToList();
}enter image description here

XML element with multiple different Text elements

I have the following elements as part of an XML document:
<RegisterEntry>
<EntryNumber>3</EntryNumber>
<EntryDate>2009-01-30</EntryDate>
<EntryType>Registered Charges</EntryType>
<EntryText>REGISTERED CHARGE dated 30 December 2008.</EntryText>
</RegisterEntry>
<RegisterEntry>
<EntryNumber>4</EntryNumber>
<EntryType>Registered Charges</EntryType>
<EntryText>REGISTERED CHARGE dated 30 December 2008.</EntryText>
</RegisterEntry>
I am using XmlReader to iterate through the document. The RegisterEntry is an XMLNodeType.Element and the four enclosed in this element are XmlNodeType.Text. How can I assign each of these Text values to a different variable as the XmlReader returns an empty string for Node.Name on a NodeType.Text. Also, the repeated elements do not always have the same number of text elements. Code below:
XmlTextReader reader = new XmlTextReader(fName);
if(reader.NodeType == XmlNodeType.Element && reader.Name =="RegisterEntry")
{
propEntryNo = "";
propEntryDate = "";
propEntryType = "";
propEntryText = "";
while(reader.Read())
{
if(reader.NodeType == XmlNodeType.Text && reader.Name == "EntryNumber" && reader.HasValue)
{
propEntryNo = reader.Value;
}
if (reader.NodeType == XmlNodeType.Text && reader.Name == "EntryDate" && reader.HasValue)
{
propEntryDate = reader.Value;
}
if (reader.NodeType == XmlNodeType.Text && reader.Name == "EntryType" && reader.HasValue)
{
propEntryType = reader.Value;
}
if (reader.NodeType == XmlNodeType.Text && reader.Name == "EntryText" && reader.HasValue)
{
propEntryText += reader.Value + ",";
}
if(reader.NodeType == XmlNodeType.EndElement && reader.Name == "RegisterEntry")
{
add variable values to list
break;
}
}
}
In each of the if statements above the NodeType returns as Text and the Name as an empty string.
The XML element and the text inside are different nodes!
You have to read the content of the XML element first. Simple example:
switch (reader.Name)
{
// found a node with name = "EntryNumber" (type = Element)
case "EntryNumber":
// make sure it's not the closing tag
if (reader.IsStartElement())
{
// read the text inside the element, which is a seperate node (type = Text)
reader.Read();
// get the value of the text node
propEntryNo = reader.Value;
}
break;
// ...
}
Another option would be ReadElementContentAsString
switch (reader.Name)
{
case "EntryNumber":
propEntryNo = reader.ReadElementContentAsString();
break;
// ...
}
Of course, these simple examples assume that the XML is in the expected format. You should include appropriate checks in your code.
As for the other suggested solutions:
You could XmlDocument or XDocument or instead. The handling is easier, but the memory overhead is bigger (see also).
Deserializing the XML into objects is another option. But I feel handling errors caused by an unexpected format is trickier then.
You can use XDocument to list your RegisterEntry child node like
class Program
{
static void Main(string[] args)
{
XDocument doc = XDocument.Load(#"C:\Users\xxx\source\repos\ConsoleApp4\ConsoleApp4\Files\XMLFile14.xml");
var registerEntries = doc.Descendants("RegisterEntry");
var result = (from e in registerEntries
select new
{
EntryNumber = e.Element("EntryNumber") != null ? Convert.ToInt32(e.Element("EntryNumber").Value) : 0,
EntryDate = e.Element("EntryDate") != null ? Convert.ToDateTime(e.Element("EntryDate").Value) : (DateTime?)null,
EntryType = e.Element("EntryType") != null ? e.Element("EntryType").Value : "",
EntryText = e.Element("EntryText") != null ? e.Element("EntryText").Value : "",
}).ToList();
foreach (var entry in result)
{
Console.WriteLine($"EntryNumber: {entry.EntryNumber}");
Console.WriteLine($"EntryDate: {entry.EntryDate}");
Console.WriteLine($"EntryType: {entry.EntryType}");
Console.WriteLine($"EntryText: {entry.EntryText}");
Console.WriteLine();
}
Console.ReadLine();
}
}
Output:
You can also make certain operations on your list like.
//If you want to get all `EntryText` in xml to be comma separated then you can do like
string propEntryText = string.Join(", ", result.Select(x => x.EntryText));
//Get first register entry from xml
var getFirstRegisterEntry = result.FirstOrDefault();
//Get last register entry from xml
var getLastRegisterEntry = result.LastOrDefault();
//Get register entry from xml with specific condition
var getSpecificRegisterEntry = result.Where(x => x.EntryNumber == 3).SingleOrDefault();

grab xml child of child element

i have successfully accessed itemId, galleryURL, title, viewItemURL value under item collections but problem is i need to access another value which is not directly under item collections it just inside another child. Please have a look on this picture of XML to get better idea. Please advice me how can i access listingInfo->watchCount
public ActionResult Search(string OperationName, string calltype, string page, string keywords, string type, string location, string condition, string min, string max, string negative, string minFeedback, string maxFeedback, string drange, string categoryId)
{
string AppId = "demo-key"; //api configs
string BaseUrl = "http://svcs.ebay.com/services/search/FindingService/v1?OPERATION-NAME="; //base url api end point
if (calltype == "categoryClick")
{
string Url = BaseUrl + OperationName + "&SERVICE-VERSION=1.0.0&SECURITY-APPNAME=" + AppId + "&RESPONSE-DATA-FORMAT=XML&REST-PAYLOAD&categoryId=" + categoryId + "&paginationInput.entriesPerPage=2&paginationInput.pageNumber=" + page + "";
var items = new List<EbayDataViewModel>();
XDocument xdoc = XDocument.Load(Url);
// Since i am only interested in <item> collections within <searchResult>
var searchResultItems = xdoc.Descendants()
.Where(x => x.Name.LocalName == "item");
foreach (var sri in searchResultItems)
{
// Get all child xml elements
var childElements = sri.Elements();
var itemId = childElements.FirstOrDefault(x => x.Name.LocalName == "itemId");
var imageurl = childElements.FirstOrDefault(x => x.Name.LocalName == "galleryURL");
var title = childElements.FirstOrDefault(x => x.Name.LocalName == "title");
var url = childElements.FirstOrDefault(x => x.Name.LocalName == "viewItemURL");
// var numberofwatch = childElements.Where(x => x.Name.LocalName == "listinginfo"); this is one step inside of another element
//add items from xml data to EbayDataViewModel object
items.Add(new EbayDataViewModel
{
ItemId = itemId == null ? String.Empty : itemId.Value,
EbayImageUrl = imageurl == null ? String.Empty : imageurl.Value,
EbayTitle = title == null ? String.Empty : title.Value,
EbayUrl = url == null ? String.Empty : url.Value,
//NumberOfWatch = numberofwatch == null ? String.Empty : numberofwatch.Value,
});
}
var e = Json(items);
return Json(items);
}else{
}
return null;
}
You can use XPathSelectElement (see MSDN XPathSelectElement)
string str =
#"<?xml version=""1.0""?>
<sri>
<item><listingInfo><watchCount>1</watchCount></listingInfo></item>
<item><listingInfo><watchCount>2</watchCount></listingInfo></item>
</sri>";
XDocument xdoc = XDocument.Parse(str);
var searchResultItems = xdoc.Descendants().Where(x => x.Name.LocalName == "item");
foreach (var item in searchResultItems)
{
var wc = item.XPathSelectElement("listingInfo/watchCount");
Console.WriteLine(wc.Value);
}
This line of code solves your problem i think
var nofwatch = childElements.FirstOrDefault(x => x.Name.LocalName ==
"listingInfo").Elements().FirstOrDefault(x => x.Name.LocalName ==
"watchCount");
foreach (var sri in searchResultItems)
{
// Get all child xml elements
var childElements = sri.Elements();
var itemId = childElements.FirstOrDefault(x => x.Name.LocalName == "itemId");
var imageurl = childElements.FirstOrDefault(x => x.Name.LocalName == "galleryURL");
var title = childElements.FirstOrDefault(x => x.Name.LocalName == "title");
var url = childElements.FirstOrDefault(x => x.Name.LocalName == "viewItemURL");
var nofwatch = childElements.FirstOrDefault(x => x.Name.LocalName == "listingInfo").Elements().FirstOrDefault(x => x.Name.LocalName == "watchCount");
//add items from xml data to EbayDataViewModel object
items.Add(new EbayDataViewModel
{
ItemId = itemId == null ? String.Empty : itemId.Value,
EbayImageUrl = imageurl == null ? String.Empty : imageurl.Value,
EbayTitle = title == null ? String.Empty : title.Value,
EbayUrl = url == null ? String.Empty : url.Value,
NumberOfWatch = nofwatch == null ? String.Empty : nofwatch.Value,
});
}

Dynamic table name in Entity Framework

I am using Entity Framwork with a database-first approach. I want to change the table name or view name dynamically based on conditions.
Here, I am using V_OVT_VLD_340B_DNA_CLD or V_OVT_B_table or V_OVT_c_table to get the records.
Based upon the source, I need to call the different table name and get the records. The whole code snippet is the same, except for the table name.
Please refer below code
private dOVT_OutlierViewEntities db = new dOVT_OutlierViewEntities();
if(source == "a")
{
var result = this.db.V_OVT_VLD_340B_DNA_CLD.Where(x => x.DNA_PGM_PRTN_ID == partitionId && x.CLIENT_ID == clientId).ToList().Select(y => new ValidationModel
{
claim_validation_test_id = new List<byte?> { y.CLAIM_VLD_TEST_ID },
claim_id = y.CLAIM_ID,
Provider_ID = y.Provider_ID,
}).Take(id).ToList();
}
if(source == "b")
{
var result = this.db.v_OVT_B_table.Where(x => x.DNA_PGM_PRTN_ID == partitionId && x.CLIENT_ID == clientId).ToList().Select(y => new ValidationModel
{
claim_validation_test_id = new List<byte?> { y.CLAIM_VLD_TEST_ID },
claim_id = y.CLAIM_ID,
Provider_ID = y.Provider_ID,
}).Take(id).ToList();
}
if(source == "c")
{
var result = this.db.v_OVT_C_table.Where(x => x.DNA_PGM_PRTN_ID == partitionId && x.CLIENT_ID == clientId).ToList().Select(y => new ValidationModel
{
claim_validation_test_id = new List<byte?> { y.CLAIM_VLD_TEST_ID },
claim_id = y.CLAIM_ID,
Provider_ID = y.Provider_ID,
}).Take(id).ToList();
}
I want to modify the above implementation by dynamically attaching the table name to db context based upon condition.
string tableName = string.empty
if(source == "a")
tableName = "aTable";
if(source == "b")
tableName="bTable";
this.db.tableName.where().....
Is that possible?
You can go with a switch condition to set the table type and use that with context
switch (tableName)
{
case "a":
tableType = typeof(V_OVT_VLD_340B_DNA_CLD);
break;
case "b":
tableType = typeof(v_OVT_B_table);
break;
default:
tableType = typeof(v_OVT_C_table);
break;
}
var query = context.Set(tableType);
var result = query.Find(); //filter with this query condition
You can do something like this..
string tableName = string.empty
if(source == "a")
tableName =db.GetTable("aTable");
if(source == "b")
tableName=db.GetTable("bTable");
and then query like..
tableName.where()

Read XML Attribute

I am actually trying to read this piece of XML.
http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/xml/351352?res=3hourly&key=99b9f578-ad3d-446c-9d29-0bbee028b483
I was wondering how I could read only the node Period with the value="2012-11-15Z"
So the one below :
This is the code I use
using (XmlReader reader = XmlReader.Create("http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/xml/351352?res=3hourly&key=99b9f578-ad3d-446c-9d29-0bbee028b483"))
{
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element
&& reader.Name == "Period")
{
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element &&
reader.Name == "Rep")
{
first.Text = reader.GetAttribute("T");
}
}
}
}
}
What is the way for me to read only this node ?
Should I write
if (reader.NodeType == XmlNodeType.Element
&& reader.Name == "Period" && reader.GetAttribute("value") == "2012-11-15Z")
This doesn't seem to work ..
Can someone help me ?
You can easily do that with LINQ to XML:
XDocument xdoc = XDocument.Load(path_to_xml);
var period = xdoc.Descendants("Period")
.Where(p => (string)p.Attribute("value") == "2012-11-15Z")
.SingleOrDefault();
It will return XElement, but you can select any data from period. E.g. T attributes:
List<int> tList = xdoc.Descendants("Period")
.Where(p => (string)p.Attribute("value") == "2012-11-15Z")
.SelectMany(p => p.Elements())
.Select(rep => (int)rep.Attribute("T"))
.ToList();
var query = xdoc.Descendants("Period")
.Where(p => (string)p.Attribute("value") == "2012-11-15Z")
.SelectMany(p => p.Elements())
.Select(rep => new {
T = (int)rep.Attribute("T"),
D = (string)rep.Attribute("D") })
.ToList();
Last query will return List of strongly-typed anonymous objects with integer property T and string property D:
foreach(var x in query)
// use x.T and x.D
Try using xpath to lookup the value like this
XmlDocument doc = new XmlDocument();
using (XmlReader reader = XmlReader.Create("http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/xml/351352?res=3hourly&key=99b9f578-ad3d-446c-9d29-0bbee028b483"))
{
doc.Load(reader);
XmlNodeList list = doc.SelectNodes("//Period[#value='2012-11-15Z']");
Console.WriteLine(list.Count);
}

Categories

Resources