使用 C# 将 Blogspot 博客导出到 HTML/GitHub
LINQ-to-XML 示例。
我终于做到了:我购买了 LINQPad 的代码补全功能,这样我就可以轻松地编写 C# 脚本了。现在,当然,我本可以使用 C# 脚本 免费使用,但是……等等,我为什么没有这样做呢?
无论如何,在我的 上一篇文章中,我详细解释了如何在 GitHub 上设置博客。现在是时候将我旧的 Blogger 博客转换为一个闪亮的新 GitHub 格式了。
要从 Blogger 导出您的博客,请登录 Blogger,进入您的博客控制面板,进入 设置 | 其他 选项卡,然后单击“导出博客”。
您将获得一个 XML 文件,基本上是 Atom 格式。它很难理解,因为它没有任何换行符(除了您的博客模板中的换行符,这些换行符只是为了分散您的注意力)。它是一个 <feed> 根元素,包含许多 <entry> 元素,其中一些包含您的帖子,另一些包含元数据。
这是我编写的代码,用于导出到 GitHub。只需将其粘贴到 LINQPad 或其他工具中,将 filepath
更改为指向您的 xml 文件,然后运行它!
void Main()
{
string filepath = @"C:\Downloads\Blog.xml";
string text = File.ReadAllText(filepath);
XDocument doc = XDocument.Parse(text);
// Use XNamespaces to deal with those pesky "xmlns" attributes.
// The underscore represents the default namespace.
var _ = XNamespace.Get("http://www.w3.org/2005/Atom");
var app = XNamespace.Get("http://purl.org/atom/app#");
var posts = doc.Root.Elements(_+"entry")
// An <entry> is either a post, or some bit of metadata no one cares about.
// Exclude entries that don't have a child like <category term="...#post"/>
.Where(entry => entry.Element(_+"category").Attribute("term").ToString().Contains("#post"))
// Exclude any entries with an <app:draft> element except <app:draft>no</app:draft>
.Where(entry => !entry.Descendants(app+"draft").Any(draft => draft.Value != "no"));
var outfolder = Path.Combine(Path.GetDirectoryName(filepath), Path.GetFileNameWithoutExtension(filepath));
Directory.CreateDirectory(outfolder);
foreach (var entry in posts)
{
// Extract data from XML
DateTime published = DateTime.Parse(entry.Element(_+"published").Value);
DateTime updated = DateTime.Parse(entry.Element(_+"updated").Value);
string title = entry.Element(_+"title").Value;
string content = entry.Element(_+"content").Value;
string type = entry.Element(_+"content").Attribute("type").Value ?? "html";
XElement empty = new XElement("empty");
XAttribute emptA = new XAttribute("empty","");
string originalLink = ((entry.Elements(_+"link")
.FirstOrDefault(e => e.Attribute("rel").Value == "alternate") ?? empty)
.Attribute("href") ?? emptA).Value;
string outFileName = string.Format("{0:yyyy-MM-dd}-{1}.{2}", published,
Path.GetFileNameWithoutExtension(originalLink), type);
var outPath = Path.Combine(outfolder, outFileName);
if (content.Count(c => c == '\n') <= 3)
content = AddLineBreaks(content); // optional
// Write output file (partial HTML for Jekyll)
using (StreamWriter output = File.CreateText(outPath)) {
output.WriteLine("---");
output.WriteLine("title: \"{0}\"", title);
output.WriteLine("layout: post");
output.WriteLine("# Pulled from Blogger. Last updated there on: {0:yyyy-MM-dd}", updated);
output.WriteLine("---");
if (originalLink != "")
output.WriteLine("<small><p><i>This post was imported from "+
"<a href='{0}'>blogspot</a>.</i></p></small>", originalLink);
output.WriteLine(""); // Disable Jekyll/Liquid
output.Write(content);
output.WriteLine("");
}
}
}
它将创建一个以 xml 文件命名的文件夹,并在该文件夹内为每个帖子创建一个 html 文件,如下所示
2007-09-03-hello-no-one.html
2011-07-05-why-wpf-sucks.html
2012-06-07-smart-tabs.html
2013-05-28-onward.html
这些文件名是 Jekyll 的正确格式,因此,如果您要迁移到 GitHub,只需将所有这些文件移动到您的 /_posts
文件夹,提交,就完成了!如果您想要“正确的”HTML 文件,请修改上面的代码以生成正确的代码,例如 <html><head>...</head>...
而不是 Jekyll 前置信息。
哦,顺便说一下,Blogger 导出的 HTML 在您的帖子中根本不包含任何换行符。所以我编写了这个小方法,在适当的位置添加一些换行符
string AddLineBreaks(string content)
{
var sb = new StringBuilder(content.Length + 100);
bool pre = false, fail;
for (UString rest = content; !rest.IsEmpty;) {
if (rest.StartsWith("<pre")) pre = true;
if (rest.StartsWith("</pre")) pre = false;
bool s;
if ((s = rest.StartsWith("<br />")) || rest.StartsWith("<br/>")) {
sb.Append(pre ? "\n" : "<br/>\n");
rest = rest.Substring(s ? 6 : 5);
continue;
}
if (rest.StartsWith("<li>") || rest.StartsWith("<p>") || rest.StartsWith("<tr>") || rest.StartsWith("<pre>") || rest.StartsWith("<blockquote>") || rest.StartsWith("<img"))
sb.Append('\n');
if (rest.StartsWith("</ul>") || rest.StartsWith("</ol>") || rest.StartsWith("</blockquote>"))
sb.Append('\n');
char c = (char)rest.PopFront(out fail);
if (!fail) sb.Append(c);
}
return sb.ToString();
}
这依赖于我的 Loyc.Essentials.dll
库中的 UString
(它是一种字符串切片)。如果您想使用此函数,请从 NuGet 下载 LoycCore。
这段代码对我来说足够好了,希望对您来说也足够好……但我不知道图片是否有效(Blogger 肯定不在导出文件中包含图片)。注意:默认情况下,blogspot 中的 HTML 具有“隐式”换行符功能,其中换行符会自动转换为 <br/>
。我关闭了该功能,因为它经常会破坏非平凡帖子的格式;如果您启用了该选项,我不确定 Blogger 在 XML 文件中提供的 HTML 是否包含这些自动插入的 <br/>
。