private static BlogMLBlog GetBlog(string filename) { using (var stream = File.OpenRead(filename)) { return(BlogMLSerializer.Deserialize(stream)); } }
private bool Initialize() { string blogMLFileLocation; if (!CommandLineUtils.TryGetFileLocation("BlogML File To convert", out blogMLFileLocation)) { return(false); } using (StreamReader blogReader = File.OpenText(blogMLFileLocation)) { BlogToConvert = BlogMLSerializer.Deserialize(blogReader); } AssignAllToOneUser = CommandLineUtils.GetBoolean("Assign all posts and tags to one existing user?"); if (AssignAllToOneUser) { OneUserId = CommandLineUtils.GetInteger("What is the ID of the one existing user?"); } GreatestExistingUserId = CommandLineUtils.GetInteger("What is the highest integer id of any existing user in your ghost blog?"); return(true); }
private BlogMLBlog DeserializeBlogMlByStream(Stream stream) { try { return(BlogMLSerializer.Deserialize(stream)); } catch (Exception ex) { _orchardServices.Notifier.Error(T("Error deserializing your blog Error:{0} - Please verify that this is an XML file stream", ex.Message)); throw; } }
/// <summary> /// setps: /// 1, import category,tags, authors ... /// 2, import post, page, command /// </summary> public async Task <BlogMLImporterResult> ImportAsync(User user, string xml) { if (user == null) { throw new ArgumentNullException(nameof(user)); } if (xml == null) { throw new ArgumentNullException(nameof(xml)); } _xml = xml; _user = user; var blog = new BlogMLBlog(); try { blog = BlogMLSerializer.Deserialize(XmlReader); } catch (Exception ex) { string message = string.Format("BlogML could not load with 2.0 specs. {0}", ex.Message); _logger.LogError(message); } try { await ImportCategoryAsync(blog); LoadFromXmlDocument(); await ImportPostsAsync(blog); _logger.LogInformation($"Import completed. \n Category count: {CategoryCount}, Post count: {PostCount}, Page count: {PageCount} . "); return(new BlogMLImporterResult() { CategoryCount = CategoryCount, PageCount = PageCount, PostCount = PostCount, }); } catch (Exception ex) { _logger.LogError(ex, "BlogML import failed."); throw; } }
public void Can_Deserialize_Exported_File() { var migrator = new Migrator(); migrator.Migrate(); var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, BlogMLExportWorker.ExportFileName); var file = new FileStream(path, FileMode.Open); var blog = BlogMLSerializer.Deserialize(file); Assert.NotNull(blog); Assert.NotEqual(0, blog.Posts.Count); Assert.NotEqual(0, blog.Categories.Count); }
public void Process(BlogMLBlog blogml) { var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ExportFileName); Log.InfoFormat("Creating BlogML export file in {0}", path); using (var output = new FileStream(path, FileMode.Create)) { Log.Info("Serializing Blog data into file."); BlogMLSerializer.Serialize(output, blogml); } Log.Info("Finished writing the export file."); }
public async Task <bool> ImportAsync(User author) { _author = author; Message = string.Empty; var blog = new BlogMLBlog(); try { blog = BlogMLSerializer.Deserialize(XmlReader); } catch (Exception ex) { Message = string.Format("BlogReader.Import: BlogML could not load with 2.0 specs. {0}", ex.Message); _logger.LogError(Message); return(false); } if (blog.Authors.Count > 0) { var firstAuthor = blog.Authors[0]; } try { LoadFromXmlDocument(); await LoadBlogCategories(blog); LoadBlogExtendedPosts(blog); await LoadBlogPosts(); Message = string.Format("Imported {0} new posts", PostCount); } catch (Exception ex) { Message = string.Format("BlogReader.Import: {0}", ex.Message); _logger.LogError(Message); return(false); } return(true); }
public void Exports_Post_Category_Relations() { var migrator = new Migrator(); migrator.Migrate(); var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, BlogMLExportWorker.ExportFileName); var file = new FileStream(path, FileMode.Open); var blog = BlogMLSerializer.Deserialize(file); var post = blog.Posts[0]; var categories = post.Categories; Assert.NotNull(categories); Assert.NotEmpty(categories); }
public BlogMLBlog DeserializeXMLStream(Stream stream) { BlogMLBlog blogPosts; try { blogPosts = BlogMLSerializer.Deserialize(stream); } catch (Exception exc) { var message = "Failed to deserialize XML file"; var logMessage = "Failed to deserialize provided XML file."; throw new ValidationException(() => message, logMessage, exc); } stream.Close(); stream.Dispose(); return(blogPosts); }
public BlogMLBlog DeserializeXMLStream(Stream stream) { try { stream.Position = 0; XmlReaderSettings readerSettings = new XmlReaderSettings(); readerSettings.ConformanceLevel = ConformanceLevel.Document; readerSettings.CheckCharacters = true; readerSettings.ValidationType = ValidationType.None; var xmlReader = XmlReader.Create(stream, readerSettings); XmlDocument xdoc = new XmlDocument(); xdoc.Load(xmlReader); } catch (Exception exc) { var message = BlogGlobalization.ImportBlogPosts_FileIsNotValidXML_Message; var logMessage = "Provided file is not a valid XML file."; throw new ValidationException(() => message, logMessage, exc); } BlogMLBlog blogPosts; try { stream.Position = 0; blogPosts = BlogMLSerializer.Deserialize(stream); } catch (Exception exc) { var message = BlogGlobalization.ImportBlogPosts_FailedToDeserializeXML_Message; var logMessage = "Failed to deserialize provided XML file."; throw new ValidationException(() => message, logMessage, exc); } stream.Close(); stream.Dispose(); return(blogPosts); }
static void ConvertBlog(string inputXml, string outDir) { BlogMLBlog blog; using (var fs = File.OpenRead(inputXml)) { blog = BlogMLSerializer.Deserialize(fs); } // Load the document and set the root element. var blogDoc = new XmlDocument(); using (XmlTextReader tr = new XmlTextReader(inputXml)) { tr.Namespaces = false; blogDoc.Load(inputXml); } var categories = blog.Categories .Select(cat => new CategoryRef { Title = cat.Title, Id = cat.ID }) .ToDictionary(x => x.Id); // var mdConverter = new Converter(new DivPScheme()); var mdConverter = new Converter(); blog.Posts.ForEach(post => { var slug = post.PostUrl.Substring(post.PostUrl.LastIndexOf('/') + 1); var tags = GetTags(blogDoc, post.ID); var header = ComposeBlogHeader(post, categories, tags); var markdown = mdConverter.Convert(post.Content.UncodedText); Console.WriteLine($"Writing {slug} ({post.Title})"); WriteConvertedMarkdown(outDir, slug, header, markdown); }); }
/// <summary> /// Imports BlogML file into blog /// </summary> /// <returns> /// True if successful /// </returns> public override bool Import() { Message = string.Empty; var blog = new BlogMLBlog(); try { blog = BlogMLSerializer.Deserialize(XmlReader); } catch (Exception ex) { Message = string.Format("BlogReader.Import: BlogML could not load with 2.0 specs. {0}", ex.Message); Utils.Log(Message); return(false); } try { LoadFromXmlDocument(); LoadBlogCategories(blog); LoadBlogExtendedPosts(blog); LoadBlogPosts(); Message = string.Format("Imported {0} new posts", PostCount); } catch (Exception ex) { Message = string.Format("BlogReader.Import: {0}", ex.Message); Utils.Log(Message); return(false); } return(true); }
static void ConvertBlog(string inputXml, string outDir) { BlogMLBlog blog; using (var fs = File.OpenRead(inputXml)) { blog = BlogMLSerializer.Deserialize(fs); } // Load the document and set the root element. var blogDoc = new XmlDocument(); using (XmlTextReader tr = new XmlTextReader(inputXml)) { tr.Namespaces = false; blogDoc.Load(inputXml); } var categories = blog.Categories .Select(cat => new CategoryRef { Title = cat.Title, Id = cat.ID }) .ToDictionary(x => x.Id); var convertedPostCount = 0; ITextFormatter textFormatter = new DefaultTextFormatter(); IBlogUrlConverter blogUrlConverter = new TechnologyToolboxBlogUrlConverter(); IBlogAttachmentService blogPostAttachmentService = new TechnologyToolboxBlogAttachmentService(); ICodeBlockAnalyzer codeBlockAnalyzer = new OneNoteCodeBlockAnalyzer(); var reverseMarkdownConfig = new Config { CodeBlockLanguageMapper = new TechnologyToolboxCodeBlockLanguageMapper(), EmphasisChar = '_', GithubFlavored = true, HorizontalRuleString = "---", ListNumberingStyle = ListNumberingStyle.AlwaysOne, RemoveExcessIndentationFromCode = true, RemoveTrailingWhitespaceFromCode = true }; var imageUrlMapper = new TechnologyToolboxImageUrlMapper(); var linkMapper = new LinkMapper(blogUrlConverter); blog.Posts.ForEach(post => { var pipeline = new BlogPostConversionPipelineBuilder() .ForPost(post) .WithOutputDirectory(outDir) .AddStep(new SlugDeterminationStep(blogUrlConverter)) .AddStep(new TechnologyToolboxMsdnBlogUrlExtractionStep(blogDoc)) // Extract tags *before* preprocessing blog post (for // example, to allow the preprocessing step to remove tags // embedded in the content of the post) .AddStep(new TechnologyToolboxTagExtractionStep(blogDoc)) // Replace image URLs *before* preprocessing blog post (for // example, to allow the preprocessing step to replace <img> // elements embedded in the content of the post with Hugo // "figure" shortcodes) .AddStep(new ImageUrlReplacementStep(imageUrlMapper)) .AddStep(new FixHtmlFormattingIssuesStep()) .AddStep(new TechnologyToolboxBlogPostPreprocessor( linkMapper)) // Perform code analysis *after* preprocessing blog post (for // example, to avoid overwriting "Text" language specified for // log excerpts) .AddStep(new CodeBlockAnalysisStep( codeBlockAnalyzer, reverseMarkdownConfig.CodeBlockLanguageMapper)) .AddStep(new ReverseMarkdownPreprocessingStep()) .AddStep(new ReverseMarkdownConversionStep( reverseMarkdownConfig)) .AddStep(new ReverseMarkdownPostprocessingStep()) .AddStep(new AttachmentLookupStep(blogPostAttachmentService)) .AddStep(new CategoryLookupStep(categories)) .AddStep(new SaveMarkdownStep(textFormatter, false)) .AddStep(new CreateBlogArchivePagesStep()) .Build(); pipeline.Execute(); convertedPostCount++; }); Console.WriteLine($"Posts converted: {convertedPostCount}"); }
public virtual OxiteModel BlogMLSave(Area areaInput, string slugPattern, User currentUser) { //TODO: (erikpo) Change this to be user selectable in the multiple blogs case if the user is a site owner Area area = areaService.GetArea("Blog"); if (area == null) { return(null); } ValidationStateDictionary validationState = new ValidationStateDictionary(); XmlTextReader reader = null; bool modifiedSite = false; try { reader = new XmlTextReader(Request.Files[0].InputStream); BlogMLBlog blog = BlogMLSerializer.Deserialize(reader); Language language = languageService.GetLanguage(site.LanguageDefault); area.Description = blog.SubTitle; area.DisplayName = blog.Title; area.Created = blog.DateCreated; areaService.EditArea(area, out validationState); if (!site.HasMultipleAreas) { site.DisplayName = area.DisplayName; site.Description = area.Description; siteService.EditSite(site, out validationState); if (!validationState.IsValid) { throw new Exception(); } modifiedSite = true; } postService.RemoveAll(area); foreach (BlogMLPost blogMLPost in blog.Posts) { if (string.IsNullOrEmpty(blogMLPost.Title) || string.IsNullOrEmpty(blogMLPost.Content.Text)) { continue; } Post post = blogMLPost.ToPost(blog, currentUser, slugPattern); postService.AddPost(post, currentUser, false, out validationState, out post); if (!validationState.IsValid) { throw new Exception(); } foreach (BlogMLComment blogMLComment in blogMLPost.Comments) { Comment comment = blogMLComment.ToComment(blog, currentUser, language); postService.ValidateComment(comment, out validationState); if (validationState.IsValid) { postService.AddCommentWithoutMessages(area, post, comment, comment.Creator, false, out validationState, out comment); if (!validationState.IsValid) { throw new Exception(); } } } } } catch (Exception ex) { ModelState.AddModelErrors(validationState); if (!string.IsNullOrEmpty(ex.Message)) { ModelState.AddModelError("ModelName", ex); } return(BlogML(areaInput)); } finally { if (reader != null) { reader.Close(); } } if (modifiedSite) { OxiteApplication.Load(ControllerContext.HttpContext); } return(new OxiteModel { Container = area }); }
public virtual OxiteViewModel ImportSave(Blog blog, string slugPattern) { if (blog == null) { return(null); } ValidationStateDictionary validationState = new ValidationStateDictionary(); XmlTextReader reader = null; bool modifiedSite = false; try { reader = new XmlTextReader(Request.Files[0].InputStream); BlogMLBlog blogMLBlog = BlogMLSerializer.Deserialize(reader); Language language = languageService.GetLanguage(context.Site.LanguageDefault); BlogInputForImport blogInput = new BlogInputForImport(blogMLBlog.SubTitle, blogMLBlog.SubTitle, blogMLBlog.DateCreated); ModelResult <Blog> results = blogService.EditBlog(blog, blogInput); if (!results.IsValid) { ModelState.AddModelErrors(results.ValidationState); return(Import(blog)); } if (!context.Site.HasMultipleBlogs) { Site site = siteService.GetSite(); site.DisplayName = blog.DisplayName; site.Description = blog.Description; siteService.EditSite(site, out validationState); if (!validationState.IsValid) { throw new Exception(); } modifiedSite = true; } postService.RemoveAll(blog); foreach (BlogMLPost blogMLPost in blogMLBlog.Posts) { if (string.IsNullOrEmpty(blogMLPost.Title) || string.IsNullOrEmpty(blogMLPost.Content.Text)) { continue; } PostInputForImport postInput = blogMLPost.ToImportPostInput(blogMLBlog, context.Site.CommentingDisabled | blog.CommentingDisabled, slugPattern, blogMLPost.Approved ? EntityState.Normal : EntityState.PendingApproval, context.User.Cast <User>()); ModelResult <Post> addPostResults = postService.AddPost(blog, postInput); if (!addPostResults.IsValid) { ModelState.AddModelErrors(addPostResults.ValidationState); return(Import(blog)); } foreach (BlogMLComment blogMLComment in blogMLPost.Comments) { CommentInputForImport commentInput = blogMLComment.ToImportCommentInput(blogMLBlog, context.User.Cast <User>(), language); ModelResult <PostComment> addCommentResults = commentService.AddComment(addPostResults.Item, commentInput); if (!addCommentResults.IsValid) { ModelState.AddModelErrors(addCommentResults.ValidationState); return(Import(blog)); } } } } catch (Exception ex) { ModelState.AddModelErrors(validationState); if (!string.IsNullOrEmpty(ex.Message)) { ModelState.AddModelError("ModelName", ex); } return(Import(blog)); } finally { if (reader != null) { reader.Close(); } } if (modifiedSite) { OxiteApplication.Load(ControllerContext.HttpContext); } return(new OxiteViewModel { Container = blog }); }
public void ImportBlog(Stream stream) { var importedBlog = BlogMLSerializer.Deserialize(stream); ImportBlog(importedBlog); }
public IEnumerable <TaskStep> Execute(Dictionary <string, object> properties) { var inputFile = (string)properties["inputFile"]; if (!File.Exists(inputFile)) { throw new ArgumentException("The file: '{0}' does not exist."); } var progress = 0; yield return(new TaskStep(progress++, "Input file '{0}' found", inputFile)); using (var reader = new StreamReader(inputFile)) { yield return(new TaskStep(progress++, "Deserializing input file into BlogML object model")); var blog = BlogMLSerializer.Deserialize(reader); yield return(new TaskStep(progress++, "Successfully deserialized BlogML object model from input file")); yield return(new TaskStep(progress++, "Blog posts found: {0}", blog.Posts.Count)); var remainingProgress = 100 - progress; var postCount = blog.Posts.Count; var postIndex = 0; foreach (var post in blog.Posts) { postIndex++; progress = (int)(((double)postIndex / postCount) * (double)remainingProgress); var entry = new Entry(); entry.Author = authenticator.GetName(); entry.HideChrome = false; entry.IsDiscussionEnabled = true; entry.Status = post.PostType == BlogPostTypes.Article ? EntryStatus.PublicPage : EntryStatus.PublicBlog; entry.Title = entry.MetaTitle = NoLongerThan(200, post.Title); entry.Published = post.DateCreated < DateTime.Today.AddYears(-100) ? DateTime.UtcNow : post.DateCreated; entry.Summary = post.HasExcerpt ? NoLongerThan(500, StripHtml(post.Excerpt.UncodedText)) : ""; entry.MetaDescription = post.HasExcerpt ? NoLongerThan(200, StripHtml(post.Excerpt.UncodedText)) : NoLongerThan(200, StripHtml(post.Content.UncodedText)); entry.Name = NoLongerThan(100, (post.PostUrl ?? post.PostName ?? post.ID).Trim('/')); // Ensure this post wasn't already imported var existing = repository.FindFirstOrDefault(new EntryByNameQuery(entry.Name)); if (existing != null) { yield return(new TaskStep(progress, "Did NOT import post '{0}', because a post by this name already exists", entry.Name)); continue; } var revision = entry.Revise(); revision.Author = authenticator.GetName(); revision.Body = post.Content.UncodedText; revision.Format = Formats.Html; revision.Reason = "Imported from BlogML"; foreach (BlogMLComment comment in post.Comments) { var newComment = entry.Comment(); newComment.AuthorEmail = NoLongerThan(100, comment.UserEMail); newComment.AuthorName = NoLongerThan(100, comment.UserName); newComment.AuthorUrl = NoLongerThan(100, comment.UserUrl); newComment.IsSpam = !comment.Approved; newComment.Posted = comment.DateCreated < DateTime.Today.AddYears(-100) ? DateTime.UtcNow : comment.DateCreated; newComment.Body = comment.Content.UncodedText; } foreach (BlogMLCategoryReference categoryRef in post.Categories) { var category = blog.Categories.FirstOrDefault(x => x.ID == categoryRef.Ref); if (category == null) { continue; } var tagName = new string( (category.Title ?? string.Empty) .ToLowerInvariant() .Select(x => char.IsLetterOrDigit(x) ? x : '-') .ToArray()); if (string.IsNullOrEmpty(tagName)) { continue; } var existingTag = repository.FindFirstOrDefault(new SearchTagsByNameQuery(tagName)); if (existingTag == null) { existingTag = new Tag { Name = tagName }; repository.Add(existingTag); } existingTag.Add(entry); } repository.Add(entry); yield return(new TaskStep(progress, "Imported post '{0}'", entry.Name)); } } yield break; }
/// <summary> /// Converts the blog export to BlogML /// </summary> public void Convert() { XDocument blogger = XDocument.Load(_bloggerExportPath); // extract basic information string blogTitle = blogger.Element(AtomNamespace + "feed").Element(AtomNamespace + "title").Value; DateTime blogUpdated = DateTime.Parse(blogger.Element(AtomNamespace + "feed").Element(AtomNamespace + "updated").Value).ToUniversalTime(); string authorName = blogger.Element(AtomNamespace + "feed").Element(AtomNamespace + "author").Element(AtomNamespace + "name").Value; string authorUri = blogger.Element(AtomNamespace + "feed").Element(AtomNamespace + "author").Element(AtomNamespace + "uri").Value; string authorEmail = blogger.Element(AtomNamespace + "feed").Element(AtomNamespace + "author").Element(AtomNamespace + "email").Value; // assume the updated date and then hunt backwards in time DateTime blogCreated = blogUpdated; LogMessage(string.Format(CultureInfo.CurrentCulture, Properties.Resources.Converter_MessageBlogTitle, blogTitle, blogUpdated)); LogMessage(string.Format(CultureInfo.CurrentCulture, Properties.Resources.Converter_MessageBlogAuthor, authorName, authorEmail, authorUri)); // parse ATOM entries var query = from entry in blogger.Descendants(AtomNamespace + "entry") select new { Id = entry.Element(AtomNamespace + "id").Value, Published = DateTime.Parse(entry.Element(AtomNamespace + "published").Value).ToUniversalTime(), Updated = DateTime.Parse(entry.Element(AtomNamespace + "updated").Value).ToUniversalTime(), Title = entry.Element(AtomNamespace + "title").Value, Content = entry.Element(AtomNamespace + "content").Value, AuthorName = entry.Element(AtomNamespace + "author").Element(AtomNamespace + "name").Value, AuthorUri = entry.Element(AtomNamespace + "author").Element(AtomNamespace + "uri") == null ? null : entry.Element(AtomNamespace + "author").Element(AtomNamespace + "uri").Value, AuthorEmail = entry.Element(AtomNamespace + "author").Element(AtomNamespace + "email") == null ? null : entry.Element(AtomNamespace + "author").Element(AtomNamespace + "email").Value, InReplyTo = entry.Element(ThrNamespace + "in-reply-to") == null ? null : entry.Element(ThrNamespace + "in-reply-to").Attribute("ref").Value, Categories = (from category in entry.Descendants(AtomNamespace + "category") select new { Scheme = category.Attribute("scheme").Value, Term = category.Attribute("term").Value, }), Links = (from link in entry.Descendants(AtomNamespace + "link") select new { Rel = link.Attribute("rel").Value, Type = link.Attribute("type").Value, Href = link.Attribute("href").Value, }), }; // separate out the different export categories from the ATOM entries Dictionary <string, BlogMLPost> posts = new Dictionary <string, BlogMLPost>(); List <CommentWithInReplyTo> comments = new List <CommentWithInReplyTo>(); List <BlogMLAuthor> authors = new List <BlogMLAuthor>(); List <BlogMLCategory> categories = new List <BlogMLCategory>(); NameValueCollection settings = new NameValueCollection(); string template = null; foreach (var q in query) { // update the blog created date as we find earlier entires if (q.Published < blogCreated) { blogCreated = q.Published; } // create a content holder BlogMLContent content = new BlogMLContent(); content.Text = q.Content; // find categories and the type of entry List <BlogMLCategoryReference> categoryRefs = new List <BlogMLCategoryReference>(); string entryKind = null; // get the type of entry and any post categories foreach (var c in q.Categories) { if (c.Scheme == "http://schemas.google.com/g/2005#kind") { entryKind = c.Term; } else if (c.Scheme == "http://www.blogger.com/atom/ns#") { BlogMLCategoryReference categoryRef = new BlogMLCategoryReference(); categoryRef.Ref = UpdateCategoriesGetRef(ref categories, c.Term, q.Published); categoryRefs.Add(categoryRef); } else { // we've found a category scheme we don't know about LogMessage(string.Format(CultureInfo.CurrentCulture, Properties.Resources.Converter_MessageUnexpectedCategoryScheme, c.Scheme)); } } // process entry based on the entry kind switch (entryKind) { case "http://schemas.google.com/blogger/2008/kind#template": template = q.Content; break; case "http://schemas.google.com/blogger/2008/kind#settings": LogMessage(string.Format(CultureInfo.CurrentCulture, Properties.Resources.Converter_ImportingSettings, q.Id, q.Content)); settings.Add(q.Id, q.Content); break; case "http://schemas.google.com/blogger/2008/kind#post": LogMessage(string.Format(CultureInfo.CurrentCulture, Properties.Resources.Converter_ImportingPost, q.Title)); // get a reference to the author of this entry BlogMLAuthorReference authorReference = new BlogMLAuthorReference(); authorReference.Ref = UpdateAuthorsGetRef(ref authors, q.AuthorName, q.AuthorEmail, q.Published); BlogMLPost post = new BlogMLPost(); post.Approved = true; post.Authors.Add(authorReference); if (categoryRefs.Count > 0) { post.Categories.AddRange(categoryRefs); } post.Content = content; post.DateCreated = q.Published; post.DateModified = q.Updated; post.HasExcerpt = false; post.ID = q.Id; post.PostType = BlogPostTypes.Normal; post.Title = q.Title; posts.Add(q.Id, post); break; case "http://schemas.google.com/blogger/2008/kind#comment": LogMessage(string.Format(CultureInfo.CurrentCulture, Properties.Resources.Converter_ImportingComment, q.Title)); BlogMLComment comment = new BlogMLComment(); comment.Approved = true; comment.Content = content; comment.DateCreated = q.Published; comment.DateModified = q.Updated; comment.ID = q.Id; comment.Title = q.Title; comment.UserEMail = q.AuthorEmail; comment.UserName = q.AuthorName; comment.UserUrl = q.AuthorUri; comments.Add(new CommentWithInReplyTo(comment, q.InReplyTo)); break; default: LogMessage(string.Format(CultureInfo.CurrentCulture, Properties.Resources.Converter_MessageUnexpectedEntryKind, entryKind)); break; } } // add comments to posts foreach (CommentWithInReplyTo comment in comments) { if (posts.ContainsKey(comment.InReplyTo)) { BlogMLPost post = posts[comment.InReplyTo]; LogMessage(string.Format(CultureInfo.CurrentCulture, Properties.Resources.Converter_AttachingComment, comment.Comment.Title, post.Title)); post.Comments.Add(comment.Comment); } else { LogMessage(string.Format(CultureInfo.CurrentCulture, Properties.Resources.Converter_OrphanedComment, comment.Comment.Title)); } } // build the blog LogMessage(Properties.Resources.Converter_BuildingBlogML); BlogMLBlog blog = new BlogMLBlog(); blog.Authors.AddRange(authors); blog.Categories.AddRange(categories); blog.DateCreated = blogCreated; blog.Posts.AddRange(posts.Values); blog.Title = blogTitle; // add blogger settings as extended properties foreach (string name in settings.Keys) { Pair <string, string> pair = new Pair <string, string>(); pair.Key = name; pair.Value = settings[name]; blog.ExtendedProperties.Add(pair); } // output BlogML LogMessage(string.Format(CultureInfo.CurrentCulture, Properties.Resources.Converter_WritingBlogML, _blogmlPath)); XmlWriterSettings writerSettings = new XmlWriterSettings(); writerSettings.CheckCharacters = true; writerSettings.CloseOutput = true; writerSettings.ConformanceLevel = ConformanceLevel.Document; writerSettings.Indent = true; using (XmlWriter writer = XmlWriter.Create(_blogmlPath, writerSettings)) { BlogMLSerializer.Serialize(writer, blog); } }