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