PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/BlogEngine/DotNetSlave.BusinessLogic/API/BlogML/BlogReader.cs

#
C# | 406 lines | 287 code | 64 blank | 55 comment | 53 complexity | 9a93813964d4848671e61a51c8cf3ca1 MD5 | raw file
Possible License(s): LGPL-2.1, Apache-2.0, BSD-3-Clause
  1. namespace BlogEngine.Core.API.BlogML
  2. {
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Text;
  7. using System.Xml;
  8. using System.Linq;
  9. using System.Globalization;
  10. using global::BlogML;
  11. using global::BlogML.Xml;
  12. /// <summary>
  13. /// Class to validate BlogML data and import it into Blog
  14. /// </summary>
  15. public class BlogReader : BaseReader
  16. {
  17. #region Constants and Fields
  18. /// <summary>
  19. /// The xml data.
  20. /// </summary>
  21. private string xmlData = string.Empty;
  22. /// <summary>
  23. /// The category lookup.
  24. /// </summary>
  25. private List<Category> categoryLookup = new List<Category>();
  26. private List<BlogMlExtendedPost> blogsExtended = new List<BlogMlExtendedPost>();
  27. #endregion
  28. #region Properties
  29. /// <summary>
  30. /// imported posts counter
  31. /// </summary>
  32. public int PostCount { get; set; }
  33. /// <summary>
  34. /// Sets BlogML data uploaded and saved as string
  35. /// </summary>
  36. public string XmlData
  37. {
  38. set
  39. {
  40. xmlData = value;
  41. }
  42. }
  43. /// <summary>
  44. /// Gets an XmlReader that converts BlogML data saved as string into XML stream
  45. /// </summary>
  46. private XmlTextReader XmlReader
  47. {
  48. get
  49. {
  50. var byteArray = Encoding.UTF8.GetBytes(this.xmlData);
  51. var stream = new MemoryStream(byteArray);
  52. return new XmlTextReader(stream);
  53. }
  54. }
  55. #endregion
  56. #region Public Methods
  57. /// <summary>
  58. /// Imports BlogML file into blog
  59. /// </summary>
  60. /// <returns>
  61. /// True if successful
  62. /// </returns>
  63. public override bool Import()
  64. {
  65. Message = string.Empty;
  66. var blog = new BlogMLBlog();
  67. try
  68. {
  69. blog = BlogMLSerializer.Deserialize(XmlReader);
  70. }
  71. catch (Exception ex)
  72. {
  73. Message = string.Format("BlogReader.Import: BlogML could not load with 2.0 specs. {0}", ex.Message);
  74. Utils.Log(Message);
  75. return false;
  76. }
  77. try
  78. {
  79. LoadFromXmlDocument();
  80. LoadBlogCategories(blog);
  81. LoadBlogExtendedPosts(blog);
  82. LoadBlogPosts();
  83. Message = string.Format("Imported {0} new posts", PostCount);
  84. }
  85. catch (Exception ex)
  86. {
  87. Message = string.Format("BlogReader.Import: {0}", ex.Message);
  88. Utils.Log(Message);
  89. return false;
  90. }
  91. return true;
  92. }
  93. #endregion
  94. #region Methods
  95. private Dictionary<string, Dictionary<string, Guid>> _substitueGuids;
  96. private Guid GetGuid(string type, string value)
  97. {
  98. value = (value ?? string.Empty).Trim();
  99. // Value might be a GUID, or it could be a simple integer.
  100. if (!Utils.StringIsNullOrWhitespace(value) &&
  101. value.Length == 36)
  102. {
  103. return new Guid(value);
  104. }
  105. // If we've already retrieved a Guid for a particular type/value, then
  106. // return the same Guid. This is in case the type/value is referenced by
  107. // other objects, we would want to use the same Guid to keep the
  108. // references correct.
  109. if (_substitueGuids == null)
  110. {
  111. _substitueGuids = new Dictionary<string, Dictionary<string, Guid>>(StringComparer.OrdinalIgnoreCase);
  112. }
  113. if (!_substitueGuids.ContainsKey(type))
  114. _substitueGuids.Add(type, new Dictionary<string, Guid>(StringComparer.OrdinalIgnoreCase));
  115. if (!_substitueGuids[type].ContainsKey(value))
  116. _substitueGuids[type].Add(value, Guid.NewGuid());
  117. return _substitueGuids[type][value];
  118. }
  119. private T GetAttributeValue<T>(XmlAttribute attr)
  120. {
  121. if (attr == null)
  122. return default(T);
  123. return (T)Convert.ChangeType(attr.Value, typeof(T));
  124. }
  125. private DateTime GetDate(XmlAttribute attr)
  126. {
  127. string value = GetAttributeValue<string>(attr);
  128. DateTime defaultDate = DateTime.Now;
  129. DateTime dt = defaultDate;
  130. if (!Utils.StringIsNullOrWhitespace(value))
  131. {
  132. if (!DateTime.TryParseExact(value, "yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out dt))
  133. dt = defaultDate;
  134. }
  135. return dt;
  136. }
  137. private Uri GetUri(string value)
  138. {
  139. Uri uri;
  140. if (Uri.TryCreate(value, UriKind.RelativeOrAbsolute, out uri))
  141. return uri;
  142. return null;
  143. }
  144. /// <summary>
  145. /// BlogML does not support tags - load directly fro XML
  146. /// </summary>
  147. private void LoadFromXmlDocument()
  148. {
  149. var doc = new XmlDocument();
  150. doc.Load(XmlReader);
  151. var posts = doc.GetElementsByTagName("post");
  152. foreach (XmlNode post in posts)
  153. {
  154. var blogX = new BlogMlExtendedPost();
  155. if (post.Attributes != null)
  156. blogX.PostUrl = GetAttributeValue<string>(post.Attributes["post-url"]);
  157. if (post.ChildNodes.Count <= 0)
  158. {
  159. blogsExtended.Add(blogX);
  160. continue;
  161. }
  162. foreach (XmlNode child in post.ChildNodes)
  163. {
  164. if (child.Name == "tags")
  165. {
  166. foreach (XmlNode tag in child.ChildNodes)
  167. {
  168. if (tag.Attributes != null)
  169. {
  170. if (blogX.Tags == null) blogX.Tags = new StateList<string>();
  171. blogX.Tags.Add(GetAttributeValue<string>(tag.Attributes["ref"]));
  172. }
  173. }
  174. }
  175. if (child.Name == "comments")
  176. LoadBlogComments(blogX, child);
  177. if (child.Name == "trackbacks")
  178. LoadBlogTrackbacks(blogX, child);
  179. }
  180. blogsExtended.Add(blogX);
  181. }
  182. }
  183. /// <summary>
  184. /// Lost post comments from xml file
  185. /// </summary>
  186. /// <param name="blogX">extended blog</param>
  187. /// <param name="child">comments xml node</param>
  188. private void LoadBlogComments(BlogMlExtendedPost blogX, XmlNode child)
  189. {
  190. foreach (XmlNode com in child.ChildNodes)
  191. {
  192. if(com.Attributes != null)
  193. {
  194. var c = new Comment
  195. {
  196. Id = GetGuid("comment", GetAttributeValue<string>(com.Attributes["id"])),
  197. Author = GetAttributeValue<string>(com.Attributes["user-name"]),
  198. Email = GetAttributeValue<string>(com.Attributes["user-email"]),
  199. ParentId = GetGuid("comment", GetAttributeValue<string>(com.Attributes["parentid"])),
  200. IP = GetAttributeValue<string>(com.Attributes["user-ip"]),
  201. DateCreated = GetDate(com.Attributes["date-created"])
  202. };
  203. if (!string.IsNullOrEmpty(GetAttributeValue<string>(com.Attributes["user-url"])))
  204. c.Website = GetUri(GetAttributeValue<string>(com.Attributes["user-url"]));
  205. c.IsApproved = GetAttributeValue<bool>(com.Attributes["approved"]);
  206. foreach (XmlNode comNode in com.ChildNodes)
  207. {
  208. if(comNode.Name == "content")
  209. {
  210. c.Content = comNode.InnerText;
  211. }
  212. }
  213. if(blogX.Comments == null) blogX.Comments = new List<Comment>();
  214. blogX.Comments.Add(c);
  215. }
  216. }
  217. }
  218. /// <summary>
  219. /// Lost post trackbacks and pingbacks from xml file
  220. /// </summary>
  221. /// <param name="blogX">extended blog</param>
  222. /// <param name="child">comments xml node</param>
  223. private void LoadBlogTrackbacks(BlogMlExtendedPost blogX, XmlNode child)
  224. {
  225. foreach (XmlNode com in child.ChildNodes)
  226. {
  227. if (com.Attributes != null)
  228. {
  229. var c = new Comment
  230. {
  231. Id = GetGuid("comment", GetAttributeValue<string>(com.Attributes["id"])),
  232. IP = "127.0.0.1",
  233. IsApproved = GetAttributeValue<bool>(com.Attributes["approved"]),
  234. DateCreated = GetDate(com.Attributes["date-created"])
  235. };
  236. if (!string.IsNullOrEmpty(GetAttributeValue<string>(com.Attributes["url"])))
  237. c.Website = GetUri(GetAttributeValue<string>(com.Attributes["url"]));
  238. foreach (XmlNode comNode in com.ChildNodes)
  239. {
  240. if (comNode.Name == "title")
  241. {
  242. c.Content = comNode.InnerText;
  243. }
  244. }
  245. c.Email = c.Content.ToLowerInvariant().Contains("pingback") ? "pingback" : "trackback";
  246. c.Author = c.Email;
  247. if (blogX.Comments == null) blogX.Comments = new List<Comment>();
  248. blogX.Comments.Add(c);
  249. }
  250. }
  251. }
  252. /// <summary>
  253. /// Load blog categories
  254. /// </summary>
  255. /// <param name="blog">BlogML blog</param>
  256. private void LoadBlogCategories(BlogMLBlog blog)
  257. {
  258. foreach (var cat in blog.Categories)
  259. {
  260. var c = new Category
  261. {
  262. Id = GetGuid("category", cat.ID),
  263. Title = cat.Title,
  264. Description = string.IsNullOrEmpty(cat.Description) ? "" : cat.Description,
  265. DateCreated = cat.DateCreated,
  266. DateModified = cat.DateModified
  267. };
  268. if (!string.IsNullOrEmpty(cat.ParentRef) && cat.ParentRef != "0")
  269. c.Parent = GetGuid("category", cat.ParentRef);
  270. categoryLookup.Add(c);
  271. if (Category.GetCategory(c.Id) == null)
  272. {
  273. c.Save();
  274. }
  275. }
  276. }
  277. /// <summary>
  278. /// extended post has all BlogML plus fields not supported
  279. /// by BlogML like tags. here we assign BlogML post
  280. /// to extended matching on post URL
  281. /// </summary>
  282. /// <param name="blog">BlogML blog</param>
  283. private void LoadBlogExtendedPosts(BlogMLBlog blog)
  284. {
  285. foreach (var post in blog.Posts)
  286. {
  287. if (post.PostType == BlogPostTypes.Normal)
  288. {
  289. BlogMLPost p = post;
  290. blogsExtended.Where(b => b.PostUrl == p.PostUrl).FirstOrDefault().BlogPost = post;
  291. }
  292. }
  293. }
  294. /// <summary>
  295. /// Loads the blog posts.
  296. /// </summary>
  297. private void LoadBlogPosts()
  298. {
  299. var bi = new BlogImporter();
  300. Utils.Log("BlogReader.LoadBlogPosts: Start importing posts");
  301. foreach (BlogMlExtendedPost extPost in blogsExtended)
  302. {
  303. try
  304. {
  305. BlogMlExtendedPost post = extPost;
  306. if (extPost.BlogPost.Categories.Count > 0)
  307. {
  308. for (var i = 0; i < extPost.BlogPost.Categories.Count; i++)
  309. {
  310. int i2 = i;
  311. var cId = GetGuid("category", post.BlogPost.Categories[i2].Ref);
  312. foreach (var category in categoryLookup)
  313. {
  314. if (category.Id == cId)
  315. {
  316. if (extPost.Categories == null)
  317. extPost.Categories = new StateList<Category>();
  318. extPost.Categories.Add(category);
  319. }
  320. }
  321. }
  322. }
  323. if (!string.IsNullOrEmpty(bi.AddPost(extPost)))
  324. {
  325. PostCount++;
  326. }
  327. else
  328. {
  329. Utils.Log("Post '{0}' has been skipped" + extPost.BlogPost.Title);
  330. }
  331. }
  332. catch (Exception ex)
  333. {
  334. Utils.Log("BlogReader.LoadBlogPosts: " + ex.Message);
  335. }
  336. }
  337. bi.ForceReload();
  338. Utils.Log(string.Format("BlogReader.LoadBlogPosts: Completed importing {0} posts", PostCount));
  339. }
  340. #endregion
  341. }
  342. }