How to set Umbraco Child Node to List<T> - c#

I have a blog export package which exports blog content in Umbraco to XML.
Now I want to export comment data, the comments section is set as a childNode on the NewsItem node, how can I use this format to grab the data from the childNode into the list?
Here is my code:
public List<BlogPosts> getPostList()
{
var contentType = ApplicationContext.Current.Services.ContentTypeService
.GetContentType("umbNewsItem");
var nodes = ApplicationContext.Current.Services.ContentService
.GetContentOfContentType(contentType.Id).Select(content => new Node(content.Id));
return nodes.Select(node => new BlogPosts()
{
Title = node.GetProperty("title").ToNullSafeString(),
BodyText = node.GetProperty("bodyText").ToNullSafeString(),
PublishDate = node.GetProperty("publishDate").ToNullSafeString(),
Author = node.GetProperty("author").ToNullSafeString(),
Image = node.GetProperty("image").ToNullSafeString(),
//This is where I want to grab the blog comments content
Comments = node.ChildrenAsList.Add("comments")
}).ToList();
}
My first attempt with this, I get an error on the .Add("comments") line which reads:
The best overloaded method match for 'System.Collections.Generic.List<umbraco.interfaces.INode>.Add(umbraco.interfaces.INode)' has some invalid arguments
the next thing I tried was this:
Comments = node.ChildrenAsList<BlogComment>.Add("comments").ToList()
which returns the following error:
The property 'umbraco.NodeFactory.Node.ChildrenAsList' cannot be used with type arguments
I have also tried this:
Comments = node.ChildrenAsList.Add("comments").ToList()
which returned this error:
The best overloaded method match for 'System.Collections.Generic.List<umbraco.interfaces.INode>.Add(umbraco.interfaces.INode)' has some invalid arguments
This is my BlogPosts model:
public class BlogPosts
{
public string Title { get; set; }
public string BodyText { get; set; }
public string PublishDate { get; set; }
public string Author { get; set; }
public string Image { get; set; }
public List<BlogComment> Comments { get; set; }
}
public class BlogComment
{
public string Comment { get; set; }
public string CommentDate { get; set; }
}
This is an example of the Umbraco backoffice page:
Image
I've searched throughout stackoverflow and google for anything which refers to calling data from a childNode into a list but the list type here is INode, when using this:
Comments = node.ChildrenAsList
it returns this error:
Cannot implicitly convert type 'System.Collections.Generic.List<umbraco.interfaces.INode>' to 'System.Collections.Generic.List<UmbracoBlogsExportPackage.Models.BlogComment>'

Okay then :-)
First of all, .Add() tries to add something to a collection, so that
won't work here.
Second, I think selecting Content as Nodes is a bit backwards, so I
would try not to do that.
Third, IEnumerable have a Cast() method that I think might work
here. I can't really test it, though.
Again, this is very untested, but maybe try something like this? Obviously I don't know the Comment DocType alias, so remember to change that bit :-)
public List<BlogPosts> getPostList()
{
var contentType = UmbracoContext.Current.Application.Services.ContentTypeService
.GetContentType("umbNewsItem");
var contentService = UmbracoContext.Current.Application.Services.ContentService;
var nodes = contentService.GetContentOfContentType(contentType.Id);
return nodes.Select(node => new BlogPosts()
{
Title = node.GetValue("title").ToNullSafeString(),
BodyText = node.GetValue("bodyText").ToNullSafeString(),
PublishDate = node.GetValue("publishDate").ToNullSafeString(),
Author = node.GetValue("author").ToNullSafeString(),
Image = node.GetValue("image").ToNullSafeString(),
//This is where I want to grab the blog comments content
Comments = contentService.GetChildren(node.Id).Where(x => x.ContentType.Alias == "Comment").Cast<BlogComment>().ToList()
}).ToList();
}

Related

Use multi-field List<> from Deserialized XML file to populate second single field list (Xamarin)

This has to be so simple... in T-SQL it would take me a second.
Before I get duplicate flags... I have been trying some similar problems posted and I have been on this for hours, tinkering with various replies involving JTokens, changing to IEnumerable, deserializing one field only to name a few. I keep getting errors such as:
xamarin cannot implicitly convert type
'System.Collections.Generic.List to 'System.Colletions.List
I have deserialized an xml file into a list like so:
var assembly = IntrospectionExtensions.GetTypeInfo(typeof(LoadResourceText)).Assembly;
Stream stream = assembly.GetManifestResourceStream("papapp.WineCatInfo.xml");
List<WineCategoryInfo> winecategoryinfos;
using (var reader = new StreamReader(stream))
{
var serializer = new XmlSerializer(typeof(List<WineCategoryInfo>));
winecategoryinfos = (List<WineCategoryInfo>)serializer.Deserialize(reader);
}
#endregion
return winecategoryinfos;
The list it populates is defined like so:
public class WineCategoryInfo
{
public string WineTypeNo { get; set; }
public string WineFamily { get; set; }
public string MainStyle { get; set; }
public string StyleType { get; set; }
public string LengthCharacteristic { get; set; }
public string RegionCommonAppelation { get; set; }
}
I would like a query on the deserialized date to place all the values of one particular field from the above list into a second list, defined like so:
public class WineFamilies
{
public string WineFamily { get; set; }
}
Can someone explain to me how to achieve this?
Many thanks.
use LINQ
using System.Linq;
var family = (from x in winecategoryinfos select x.WineFamily).ToList<string>();
or to eliminate duplicates
var family = (from x in winecategoryinfos select x.WineFamily).Distinct().ToList<string>();
if you want to use your WineFamilies class instead of string, try
var family = (from x in winecategoryinfos select new WineFamilies() { WineFamily = x.WineFamily }).ToList();

Create JSON object from c# class

I have a view model which looks like so:
public class CategoriesJsonViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public List<Description> UsedDescriptions { get; set; }
public List<Description> UnusedDescriptions { get; set; }
}
I am creating a List of CategoriesJsonViewModel in my controller and trying to send it to the client browser in Json format. I use Json() method to do that:
List<CategoriesJsonViewModel> categoriesVM = new List<CategoriesJsonViewModel>();
List<Category> categories = repo.GetAllCategories();
foreach(var i in categories)
{
CategoriesJsonViewModel categoryVM = new CategoriesJsonViewModel();
categoryVM.Id = i.Id;
categoryVM.Title = i.Title;
categoriesVM.Add(categoryVM);
categoryVM.UsedDescriptions = repo.GetUsedDescriptions(i.Id);
categoryVM.UnusedDescriptions = repo.GetUnusedDescriptions(i.Id);
}
return Json(categoriesVM);
Although the categoriesVM object is being built properly, I do not get appropriate Json object from it for some reason. Why is it so?
I suggest you get the outputted json and put into jsonlint.com
That'll help you find out what is causing the json to be invalid. It may be something to do with your definition of the Description object as your CategoriesJsonViewModel looks like it should be ok.

Atom xml read with C#

I don't know about this much at all, I have built-in page that contains a gridview to describe daily input data separated into columns from different authors, it looks like an excel file. And there is an Atom link at the bottom.
If I click on one row's link especially the author of the post, I will be directed to the author's property page in which there will be name, current work done, and how much he has written his book (50/70 80% called status etc), I wonder how can I read in this information and display it in another view of a related application; that is I know the feed's URL only, I really have no clue how that can be done. Thank you for any help.
I haven't tried to use the DataContractSerializer with specialized XML formats, but the XmlSerializer lets you set what is an attribute and what is an element. It is the easiest method as far as I am concerned because you can make a nice object model and use it to read any XML. Here is a PARTIAL example of reading an atom feed. You will need to perform an HttpWebRequest to get the XML (which is pretty straight forward) then use the XmlSerializer to deserialize the feed.
[XmlType(TypeName = "feed", Namespace = "http://www.w3.org/2005/Atom")]
public class Feed
{
[XmlElement(ElementName = "title")]
public string Title { get; set; }
[XmlElement(ElementName = "updated")]
public DateTime? Updated { get; set; }
[XmlElement(ElementName = "id")]
public string Id { get; set; }
[XmlElement(ElementName = "link")]
public Link Link { get; set; }
[XmlElement(ElementName = "entry")]
public List<Entry> Entries { get; set; }
public Feed()
{
Entries = new List<Entry>();
}
}
public class Entry
{
[XmlElement(ElementName = "title")]
public string Title { get; set; }
[XmlElement(ElementName = "updated")]
public DateTime? Updated { get; set; }
[XmlElement(ElementName = "id")]
public string Id { get; set; }
[XmlElement(ElementName = "link")]
public Link Link { get; set; }
[XmlElement(ElementName = "summary")]
public string Summary { get; set; }
}
public class Link
{
[XmlAttribute(AttributeName = "href")]
public string Href { get; set; }
}
Here is a working sample to write/read the feed:
class Program
{
static void Main(string[] args)
{
Feed feed = new Feed();
feed.Title = "Exmple Feed";
feed.Updated = DateTime.Now;
feed.Link = new Link { Href = "http://example.org/" };
feed.Entries.Add(
new Entry
{
Title = "Atom-Powered Robots Run Amok",
Link = new Link { Href = "http://example.org/2003/12/13/atom03" },
Updated = DateTime.Now,
Summary = "Some text."
});
XmlSerializer serializer = new XmlSerializer(typeof(Feed), "http://www.w3.org/2005/Atom");
using (StreamWriter sw = new StreamWriter("c:\\testatom.xml"))
{
serializer.Serialize(sw, feed);
}
using (StreamReader sr = new StreamReader("c:\\testatom.xml"))
{
Feed readFeed = serializer.Deserialize(sr) as Feed;
}
}
}
The best starting point would be to use the SyndicationFeed, which maps to the Atom 1.0 and RSS 2.0 standard. Everything you need for a basic implementation should be available to you:
XmlReader reader = XmlReader.Create("http://localhost/feeds/serializedFeed.xml");
SyndicationFeed feed = SyndicationFeed.Load(reader);
// Feed title
Console.WriteLine(feed.Title.Text);
foreach(var item in feed.Items)
{
// Each item
Console.WriteLine("Title: {0}", item.Title.Text);
Console.WriteLine("Summary: {0}", ((TextSyndicationContent)item.Summary).Text);
}
Perhaps if you have some custom requirements, or want to handle the RSS data differently than this standard, then Doug's answer would be the way to go.
Useful references:
https://msdn.microsoft.com/en-us/library/system.servicemodel.syndication.syndicationfeed(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/bb412174%28v=vs.110%29.aspx

How to read stackoverflow rss feed using linq to xml

I am trying read rss feed of stack overflow using Linq to xml. I am unable to get the entry nodes, as it is returning empty list. This I've tried so far, can any one point out what i am doing wrong here?
Here I am binding to the grid view:
private void StackoverflowFeedList()
{
grdFeedView.DataSource = StackoverflowUtils.GetStackOverflowFeeds();
grdFeedView.DataBind();
}
This is the method which will get all feeds:
public static IEnumerable<StackOverflowFeedItems> GetStackOverflowFeeds ()
{
XNamespace Snmp = "http://www.w3.org/2005/Atom";
XDocument RssFeed = XDocument.Load(#"http://stackoverflow.com/feeds");
var posts = from item in RssFeed.Descendants("entry")
select new StackOverflowFeedItems
{
QuestionID = item.Element(Snmp +"id").Value,
QuestionTitle = item.Element(Snmp +"title").Value,
AuthorName = item.Element(Snmp +"name").Value,
CategoryTag = (from category in item.Elements(Snmp +"category")
orderby category
select category.Value).ToList(),
CreatedDate = DateTime.Parse(item.Element(Snmp +"published").Value),
QuestionSummary = item.Element(Snmp +"summary").Value
};
return posts.ToList();
}
And this is the class I am using for binding:
public class StackOverflowFeedItems
{
public string QuestionID { get; set; }
public string QuestionTitle { get; set; }
public IEnumerable<string> CategoryTag { get; set; }
public string AuthorName { get; set; }
public DateTime CreatedDate { get; set; }
public string QuestionSummary { get; set; }
}
You're not using the namespace variable you've declared. Try using
RssFeed.Descendants(Snmp + "entry")
(And likewise for all other places where you're referring to particular names.)
I'm not saying that's necessarily all of what you need to fix, but it's the most obvious problem. You should also consider using the explicit conversions of XElement and XAttribute instead of the Value property, e.g.
CreatedDate = (DateTime) item.Element(Snmp +"published")
I'd also encourage you to pay more attention to indentation, and use pascalCase consistently when naming local variables. (Quite why the namespace variable is called Snmp is another oddity... cut and paste?)

What is the best way to manually parse an XElement into custom objects?

I have an XElement variable named content which consists of the following XML:
<content>
<title>Contact Data</title>
<p>This is a paragraph this will be displayed in front of the first form.</p>
<form idCode="contactData" query="limit 10; category=internal"/>
<form idCode="contactDataDetail" query="limit 10; category=internal">
<title>Contact Data Detail</title>
<description>This is the detail information</description>
</form>
</content>
I now want to simply run through each of the level-1 nodes and parse them into objects. Back in C# 2.0 I use to do this with XmlReader, check the type of node, and parse it accordingly.
But what is the best way to parse the XML nodes with LINQ, I would expect something like this:
var contentItems = from contentItem in pageItem.content.DescendantNodes()
select new ContentItem
{
Type = contentItem.Element()
};
foreach (var contentItem in contentItems)
{
switch (contentItem.Type)
{
case "title":
...(parse title)...
case "p":
...(parse p)...
case "form":
...(parse form)...
}
}
where:
public class ContentItem
{
public string Type { get; set; }
public string IdCode { get; set; }
public XElement Content { get; set; }
}
Does it have to be XElement? I would (either manually, or via xsd.exe) just create classes that map to the element/attribute names - and use XmlSerializer - in particular via StringReader:
Content content;
using(StringReader sr = new StringReader(xml))
using(XmlReader xr = XmlReader.Create(sr)) {
XmlSerializer ser = new XmlSerializer(typeof(Content));
content = (Content)ser.Deserialize(xr);
}
(edit)
With entity classes:
[XmlRoot("content")]
public class Content {
[XmlElement("title")]
public string Title { get; set; }
[XmlElement("p")]
public string Description { get; set; }
[XmlElement("form")]
public List<ContentForm> Forms { get; set; }
}
public class ContentForm {
[XmlAttribute("idCode")]
public string Id { get; set; }
[XmlAttribute("query")]
public string Query { get; set; }
[XmlElement("title")]
public string Title { get; set; }
[XmlElement("description")]
public string Description { get; set; }
}
I'd suggest inheriting XElement, and implement properties for the stuff you want in it.
These properties shouldn't use backing fields, but rather work directly with the underlying XML element. That way, you'll keep object in sync with XML.
With XML to LINQ one pulls specific data items out of the XML, rather than iterating through the XML looking for what is found.
var results = from node in XmlDocument.SomeContext(...)
select new MyType {
Prop1 = node.Element("One").Value,
Prop2 = node.Element("One").Attributes().Where(
a => A.Value.Contains("Foo").Value
};
If conditions are needed, then (extension) methods and arbitrary expressions can be used (null-coalescing operator, ??, can be very helpful to default).

Categories

Resources