grab xml child of child element - c#

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,
});
}

Related

Extracting Key value from XML tags C# LINQ

void Main()
{
string xml = #"<root>
<Page1>
<Key_Head>Name1</Key_Head>
<Key_Title>value1</Key_Title>
</Page1>
<Page1>
<Key_Head>Name2</Key_Head>
<Key_Title>value2</Key_Title>
</Page1>
</root>";
var doc1 = XDocument.Parse(xml);
var result = ConvertXmlToDic(doc1.Root);
}
private static List<NameValuePair> ConvertXmlToDic(XElement element)
{
var result =
element
.Elements()
.Select(e => new
{
Name = e.Name.ToString(),
Value = (e.Descendants().Count() == 0)
? e.Value
: ConvertXmlToDic(e).ToString()
})
.ToDictionary(e => e.Name, e => e.Value)
.Select(e => new List<NameValuePair>()
{
new NameValuePair() { Name = e.Key, Value = e.Value }
});
return (List<NameValuePair>)result;
}
How do I get the tag values for <Key_Head>Name1</Key_Head><Key_Title>value1</Key_Title> as key values. Like list of (Name1,Value1) ? This is what I have tried so far.
You can simplify the logic to retrieve Key_Head and Key_Title as below:
private static List<NameValuePair> ConvertXmlToDic(XElement element)
{
var result = element.Elements()
.Select(e => new NameValuePair
{
Name = e.Element("Key_Head").Value,
Value = e.Element("Key_Title").Value
})
.ToList();
return result;
}
Output
Name: Name1, Value: value1
Name: name2, Value: value2
Sample program

How to sort C# Jobject

In my model I have public JObject GenericData { get; set; } for this property I need to create Jobject in my Controller that will pass data to this property. I have done this but now I need to sort data inside Jobject and I don't know how to do it. There is no sort function for Jobject out of box.
My code in controller looks like this.
var attributes = _context.AttributeRecords.Include(a => a.Attribute);
var queryRecords = attributes.Select(l => new
{
RecordId = l.RecordId,
ProjectId = l.ProjectId,
Attribute = l.Attribute.Description,
Value = l.Value,
InfoId = l.InfoId
}).ToList();
var recordsValues = queryRecords.Where(b => b.InfoId == i.InfoId).ToList();
var jObjectValues = new JObject();
foreach (var n in recordsValues)
{
if (n.Value.Contains(","))
{
var stringToSplit = n.Value;
var stringValues = stringToSplit.Split(',');
List<string> arr = new List<string>();
var allValues = "";
foreach (var d in stringValues)
{
var values = await _context.AttributeValues.FirstOrDefaultAsync(v => v.Key == n.Value);
arr.Add(values != null ? values.Description : d);
allValues = string.Join(",", arr);
}
jObjectValues.Add(n.Attribute, allValues);
}
else
{
var values = await _context.AttributeValues.FirstOrDefaultAsync(v => v.Key == n.Value);
jObjectValues.Add(n.Attribute, values != null ? values.Description : n.Value);
}
i.GenericData = jObjectValues;
}
You don't need to sort Jobject you can do it like this:
var queryRecords = attributes.Select(l => new
{
RecordId = l.RecordId,
ProjectId = l.ProjectId,
Attribute = l.Attribute.Description,
Value = l.Value,
InfoId = l.InfoId
}).OrderBy(o => o.Attribute).ToList();
I hope this will help you.

Reading all matches from attribute value XML 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.

HtmlAgilityPack cant get string indexer

i want to parse HTML Using HTML Agility Pack
When i am searching index with int i am getting result.
HtmlWeb htmlWeb = new HtmlWeb();
HtmlDocument htmlDocument = htmlWeb.Load("http://www.timeanddate.com/worldclock/georgia/tbilisi");
var s1 = htmlDocument.DocumentNode.Descendants().Where(x => x.HasAttributes && x.Attributes[0].Value == "ct");
But when i want to search atribute with string indexer i get an exeption.
var s2 = htmlDocument.DocumentNode.Descendants().Where(a => a.HasAttributes && a.Attributes["id"].Value == "ct");
And when i dont use LINQ and use predicate delegate everithing is Ok.
Predicate<HtmlNode> pred = new Predicate<HtmlNode>(forpred);
List<HtmlNode> ss = htmlDocument.DocumentNode.Descendants().ToList().FindAll(pred);
public static bool forpred(HtmlNode node)
{
if (node.HasAttributes)
{
foreach (HtmlAttribute atribute in node.Attributes)
{
if (atribute.Name == "id" && atribute.Value == "ct")
{
return true;
}
}
}
return false;
}
//s1.ToList()[0].InnerHtml
//s2.ToList()[0].InnerHtml
//ss[0].InnerHtml
Because some spans have attributes but not id. Your code can be like this:
var s2 = htmlDocument.DocumentNode
.Descendants()
.Where(a => a.Attributes["id"]!=null && a.Attributes["id"].Value == "ct")
.ToList();

parse xml google calendar event

I'm trying to parse google calendar events from this url: http://www.google.com/calendar/feeds/amchamlva%40gmail.com/public/full
and here is my code:
static IEnumerable<Event> getEntryQuery(XDocument xdoc)
{
return from entry in xdoc.Root.Elements().Where(i => i.Name.LocalName == "entry")
select new Event
{
EventId = entry.Elements().First(i => i.Name.LocalName == "id").Value,
Published = DateTime.Parse(entry.Elements().First(i => i.Name.LocalName == "published").Value),
Title = entry.Elements().First(i => i.Name.LocalName == "title").Value,
Content = entry.Elements().First(i => i.Name.LocalName == "content").Value,
Where = entry.Elements().First(i => i.Name.LocalName == "gd:where").FirstAttribute.Value,
Link = entry.Elements().First(i => i.Name.LocalName == "link").Attribute("href").Value,
};
}
using (StreamReader httpwebStreamReader = new StreamReader(e.Result))
{
var results = httpwebStreamReader.ReadToEnd();
XDocument doc = XDocument.Parse(results);
System.Diagnostics.Debug.WriteLine(doc);
var myFeed = getEntryQuery(doc);
foreach (var feed in myFeed)
{
System.Diagnostics.Debug.WriteLine(feed.Content);
}
}
and It works almost fine, except for this:
Where = entry.Elements().First(i => i.Name.LocalName == "gd:where").FirstAttribute.Value,
I got an exception probably because value it's null, actually i need to get valueString attribue value (for example 'Somewhere' in this case)
<gd:where valueString='Somewhere'/>
'gd' looks like a namespace, take a look at how to work with xml namespaces in LINQ to XML:
http://msdn.microsoft.com/en-us/library/bb387093.aspx
http://msdn.microsoft.com/en-us/library/bb669152.aspx
Maybe try something along the lines of
XNamespace gdns = "some namespace here";
entry.Elements(gdns + "where")
The local name of <gd:where> is just where - the gd part is the namespace alias.
Rather than using all of these First calls checking the local name, it would be much cleaner if you'd just use the right fully qualified name. For example:
XNamespace gd = "http://schemas.google.com/g/2005";
XNamespace atom = "http://www.w3.org/2005/Atom";
return from entry in xdoc.Root.Elements(gd + "entry")
select new Event
{
EventId = (string) entry.Element(atom + "id"),
Published = (DateTime) entry.Element(atom + "published"),
Title = (string) entry.Element(atom + "title"),
Content = (string) entry.Element(atom + "content"),
Where = (string) entry.Element(gd + "where")
Link = (string) entry.Element(atom + "link")
};
(That's making educated guesses on the namespace based on some documentation. You should check this against your actual feed though.)
thanks for your help guys, it works with this simple code:
//Where = entry.Elements().First(i => i.Name.LocalName == "where").Value,
Where = entry.Elements().First(i => i.Name.LocalName == "where").Attribute("valueString").Value,
later I'll try to implement your suggestions for a better code implementation ;)

Categories

Resources