- 책 또는 웹사이트의 내용을 복제하여 다른 곳에 게시하는 것을 금지합니다.
- 책 또는 웹사이트의 내용을 발췌, 요약하여 강의 자료, 발표 자료, 블로그 포스팅 등으로 만드는 것을 금지합니다.
저는 블로그 도구로 테터툴즈를 사용해왔습니다. 텍스트큐브로 업데이트하지 않고, 그냥 방치해둔 것이 꽤 오래된 것 같습니다.
이번에 블로그를 Jekyll로 옮기면서 댓글 시스템은 Disqus를 사용하기로 했습니다.
Disqus는 댓글을 WordPress eXtended RSS(WXR) 형식으로 만들면 데이터를 임포트할 수 있습니다(Disqus -> Admin -> Discussions -> Import -> Generic (WXR)).
WXR 파일은 확장자만 wxr일 뿐 내용은 XML입니다.
댓글 데이터를 Disqus로 이전하기 위해 Node.js로 테터툴즈 백업 XML 파일을 WXR 형식으로 변환하는 코드를 만들어봤습니다.
app.jsvar builder = require('xmlbuilder')
, fs = require('fs')
, libxmljs = require('libxmljs')
, moment = require('moment');
var blogDomain = 'example.com';
var xmlDoc = libxmljs.parseXml(fs.readFileSync('Tattertools.xml', 'utf8'));
var posts = [];
xmlDoc.root().childNodes().forEach(function (e) {
if (e.name() == 'post') {
var slogan = e.attr('slogan').value();
var post = { url: '/blog/entry/' + slogan, title: e.get('title').text(), comments: [] };
e.childNodes().forEach(function (e) {
if (e.name() == 'comment') {
var subComments = [];
e.childNodes().forEach(function (e) {
if (e.name() == 'comment') {
subComments.push({
name: e.get('commenter').get('name').text(),
content: e.get('content').text(),
date: moment.unix(e.get('written').text()).format('YYYY-MM-DD HH:mm:ss')
});
}
})
post.comments.push({
name: e.get('commenter').get('name').text(),
content: e.get('content').text(),
date: moment.unix(e.get('written').text()).format('YYYY-MM-DD HH:mm:ss'),
subComments: subComments
});
}
});
posts.push(post);
}
});
var wxr = builder.create('rss', {'version': '1.0', 'encoding': 'UTF-8'})
.att('version', '2.0')
.att('xmlns:content', 'http://purl.org/rss/1.0/modules/content/')
.att('xmlns:dsq', 'http://www.disqus.com/')
.att('xmlns:dc', 'http://purl.org/dc/elements/1.1/')
.att('xmlns:wp', 'http://wordpress.org/export/1.0/');
var channel = wxr.ele('channel');
posts.forEach(function (e) {
if (e.comments.length > 0) {
var item = channel.ele('item');
item.ele('link', 'http://' + blogDomain + e.url);
item.ele('title', e.title);
item.ele('dsq:thread_identifier', e.url);
item.ele('wp:comment_status', 'open');
var id = 1;
e.comments.forEach(function (e) {
var parentId;
var comment = item.ele('wp:comment');
comment.ele('wp:comment_id', id);
comment.ele('wp:comment_author', e.name);
comment.ele('wp:comment_date_gmt', e.date);
comment.ele('wp:comment_content').dat(e.content);
comment.ele('wp:comment_approved', 1);
comment.ele('wp:comment_parent', 0);
var parentId = id;
id++;
if (e.subComments) {
e.subComments.forEach(function (e) {
var comment = item.ele('wp:comment');
comment.ele('wp:comment_id', id);
comment.ele('wp:comment_author', e.name);
comment.ele('wp:comment_date_gmt', e.date);
comment.ele('wp:comment_content').dat(e.content);
comment.ele('wp:comment_approved', 1);
comment.ele('wp:comment_parent', parentId);
id++;
});
}
});
}
});
var text = wxr.end({ pretty: true });
console.log(text);
fs.writeFileSync('comments.wxr', text);
Node.js에는 편리한 모듈이 정말 많아서 간편하게 코드를 만들 수 있었습니다. XML을 읽을 때에는 libxmljs, XML을 생성할 때에는 xmlbuilder를 사용했습니다.
아래는 변환된 예제 WXR 파일입니다.
comments.wxr<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dsq="http://www.disqus.com/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:wp="http://wordpress.org/export/1.0/">
<channel>
<item>
<link>http://example.com/blog/entry/hello</link>
<title>Hello</title>
<dsq:thread_identifier>/blog/entry/hello</dsq:thread_identifier>
<wp:comment_status>open</wp:comment_status>
<wp:comment>
<wp:comment_id>1</wp:comment_id>
<wp:comment_author>foo</wp:comment_author>
<wp:comment_author_email></wp:comment_author_email>
<wp:comment_date_gmt>2010-09-20 13:19:10</wp:comment_date_gmt>
<wp:comment_content><![CDATA[Hello]]></wp:comment_content>
<wp:comment_approved>1</wp:comment_approved>
<wp:comment_parent>0</wp:comment_parent>
</wp:comment>
<wp:comment>
<wp:comment_id>2</wp:comment_id>
<wp:comment_author>bar</wp:comment_author>
<wp:comment_author_email></wp:comment_author_email>
<wp:comment_date_gmt>2010-09-21 22:32:05</wp:comment_date_gmt>
<wp:comment_content><![CDATA[Hello foo]]></wp:comment_content>
<wp:comment_approved>1</wp:comment_approved>
<wp:comment_parent>1</wp:comment_parent>
</wp:comment>
</item>
</channel>
</rss>
여기서 가장 중요한 부분은 <wp:comment_id>
입니다. 1부터 시작하며 절대 중복되면 안됩니다.
<wp:comment_date_gmt>
는 GMT로 넣어줘야 합니다. KST(한국 표준시)로 넣으면 안됩니다. 날짜 형식은 2010-09-20 13:19:10처럼 YYYY-MM-DD HH:mm:ss
형식이고, moment 모듈로 손쉽게 변환할 수 있습니다.
<wp:comment_content>
는 댓글 내용인데 댓글에 개행이나 특수문자가 들어갈 수 있으므로 <![CDATA[ ]]>
로 만들어줍니다.
테터툴즈에서는 댓글에 1단계 하위 댓글이 가능합니다. 이 부분은 <wp:comment_parent>
로 표현해주면 됩니다.
Disqus에서 임포트 할 때 주의할 점은, 한번 임포트 한 댓글은 완전히 삭제할 수 없고 계속 남아있다는 것입니다. 즉 <wp:comment_id>
에 설정한 댓글 ID를 계속 점유하고 있습니다. 문법이 맞지 않거나 기타 이유로 임포트에 실패한 뒤 다시 임포트를 시도할 경우 댓글 ID가 중복되면 댓글이 생성되지 않습니다.
실패할 때마다 일일이 댓글 ID를 증가시켜주려면 상당히 귀찮으므로 Disqus에서 테스트용 사이트를 생성하여 사용하면 편리합니다. 임포트에 실패하면 테스트 사이트를 삭제한 뒤 다시 생성하여 시도해봅니다. 에러 없이 완벽하게 임포트가 되면 그때 실제 사이트에 임포트합니다.
저작권 안내
이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.- 블로그, 게시판 등에 퍼가는 것을 금지합니다.
- 비공개 포스트에 퍼가는 것을 금지합니다.
- 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
- 링크 및 SNS 공유는 허용합니다.