/*******************************************************************************
blogger-cli Консольные инструменты по работе с blogger.com
(с) Камнев Георгий Павлович 2011 GPLv2
Данная программа является свободным программным обеспечением. Вы вправе
распространять ее и/или модифицировать в соответствии с условиями версии 2
либо по вашему выбору с условиями более поздней версии
Стандартной Общественной Лицензии GNU, опубликованной Free Software Foundation.
Мы распространяем данную программу в надежде на то, что она будет вам полезной,
однако НЕ ПРЕДОСТАВЛЯЕМ НА НЕЕ НИКАКИХ ГАРАНТИЙ,
в том числе ГАРАНТИИ ТОВАРНОГО СОСТОЯНИЯ ПРИ ПРОДАЖЕ
и ПРИГОДНОСТИ ДЛЯ ИСПОЛЬЗОВАНИЯ В КОНКРЕТНЫХ ЦЕЛЯХ.
Для получения более подробной информации ознакомьтесь
со Стандартной Общественной Лицензией GNU.
Вместе с данной программой вы должны были получить экземпляр
Стандартной Общественной Лицензии GNU.
Если вы его не получили, сообщите об этом в Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*******************************************************************************/
package tv.cofe.blogger;
import com.google.gdata.data.Category;
import com.google.gdata.data.Content;
import com.google.gdata.data.DateTime;
import com.google.gdata.data.Entry;
import com.google.gdata.data.Link;
import com.google.gdata.data.TextConstruct.RssFormat;
import com.google.gdata.data.TextContent;
import com.google.gdata.util.common.xml.XmlWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.sax.SAXSource;
import org.gocha.collection.Convertor;
import org.gocha.files.FileUtil;
import org.gocha.text.IndentStackWriter;
import org.gocha.text.TextUtil;
import org.gocha.xml.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Функции по работе с постом
* @author gocha
*/
public class PostHelper
{
/**
* Возвращает плоскую карту свойств поста.<br/>
* Карта содержит слежующие ключи:
* <b>
* id, title, published, edited, updated, canEdit, draft, categories, self
* </b>
* @param e Пост
* @return Карта свойств
*/
public static Map<String,String> getFlatProperties(Entry e,Convertor<Entry,String> idConvertor,Convertor<DateTime,String> timeConvertor){
if (e == null) {
throw new IllegalArgumentException("e==null");
}
HashMap<String, String> v = new HashMap<String, String>();
StringBuilder sb = new StringBuilder();
v.put("id", idConvertor!=null ? idConvertor.convert(e) : e.getId() );
v.put("title",
e.getTitle() != null
? e.getTitle().getPlainText() : "null");
v.put("published",
e.getPublished() != null ?
(timeConvertor!=null ? timeConvertor.convert(e.getPublished()) : e.getPublished().toStringRfc822())
: "null");
v.put("edited",
e.getEdited() != null ?
(timeConvertor!=null ? timeConvertor.convert(e.getEdited()) : e.getEdited().toStringRfc822())
: "null");
v.put("updated",
e.getUpdated() != null ?
(timeConvertor!=null ? timeConvertor.convert(e.getUpdated()) : e.getUpdated().toStringRfc822())
: "null");
v.put("canEdit", e.getCanEdit() ? "true" : "false");
v.put("draft", e.isDraft() ? "true" : "false");
sb.setLength(0);
int i = -1;
for (Category cat : e.getCategories()) {
i++;
if (i > 0)
sb.append(", ");
sb.append(cat.getTerm());
}
v.put("categories", sb.toString());
Link self = e.getSelfLink();
v.put("self",self==null ? "null" : self.getHref());
return v;
}
protected static String hookRssBody(TextContent txtConent) throws IOException, SAXException{
if (txtConent== null) {
throw new IllegalArgumentException("txtConent==null");
}
if( txtConent.getContent().isEmpty() )return "";
StringWriter strw = new StringWriter();
XmlWriter xmlWriter = new XmlWriter(strw);
txtConent.getContent().generateRss(xmlWriter, "body", RssFormat.FULL_HTML);
xmlWriter.flush();
String xml = strw.toString();
Document xdoc = XMLUtil.parseXML(xml);
Element e = xdoc.getDocumentElement();
return e.getTextContent();
}
protected static String getHtmlBodyOf(TextContent txtContent)
throws IOException, SAXException
{
String body = hookRssBody((TextContent)txtContent);
if( body==null ) throw new Error(CLI.messages().cantHookHtml());
body = body.replace("<", "<");
body = body.replace("&", "&");
body = body.replace(">", ">");
body = body.replace(""", "\"");
return body;
}
/**
* Парсинг html (возможно не валидного) в XML Document
* @param html html разметка
* @return XML Document
* @throws IOException Ошибка XML формата
* @throws SAXException Ошибка XML формата
*/
public static org.w3c.dom.Node parseHtml(String html) {
// return parseHtml_TagSoupImpl(html);
return parseHtml_htmlcleanerImpl(html);
}
private static org.w3c.dom.Node parseHtml_htmlcleanerImpl(String html) {
try{
//---------------------
// HtmlCleaner
org.htmlcleaner.CleanerProperties clProps = new org.htmlcleaner.CleanerProperties();
clProps.setOmitComments(false);
clProps.setOmitDeprecatedTags(false);
clProps.setOmitUnknownTags(false);
// clProps.setOmitDoctypeDeclaration(false);
// clProps.setOmitXmlDeclaration(false);
clProps.setUseEmptyElementTags(true);
clProps.setTreatUnknownTagsAsContent(false);
clProps.setTreatDeprecatedTagsAsContent(false);
org.htmlcleaner.HtmlCleaner cleaner = new org.htmlcleaner.HtmlCleaner(clProps);
org.htmlcleaner.TagNode tagNode = cleaner.clean(html);
org.htmlcleaner.Serializer xmlSer = new org.htmlcleaner.SimpleHtmlSerializer(clProps);
String xml = xmlSer.getAsString(tagNode);
return XMLUtil.parseXML(xml).getDocumentElement();
}catch (Throwable ex) {
throw new Error(ex);
}
}
private static org.w3c.dom.Node parseHtml_TagSoupImpl(String html) {
try {
if (html== null) {
throw new IllegalArgumentException("html==null");
}
org.ccil.cowan.tagsoup.Parser parser = new org.ccil.cowan.tagsoup.Parser();
org.xml.sax.XMLReader reader = parser;
reader.setFeature(org.ccil.cowan.tagsoup.Parser.namespacesFeature, false);
reader.setFeature(org.ccil.cowan.tagsoup.Parser.namespacePrefixesFeature, false);
StringReader strReader = new StringReader(html);
SAXSource source = new SAXSource(reader, new InputSource(strReader));
Transformer transformer = TransformerFactory.newInstance().newTransformer();
DOMResult result = new DOMResult();
transformer.transform(source, result);
Node n = result.getNode();
return n;
} catch (Throwable ex) {
throw new Error(ex);
}
}
/**
* Экспортирует пост в файл html.
* @param target Файл
* @param entry Пост
* @param htmlTmpl Шаблон файла:<br/>
* <pre>
* <!DOCTYPE html>
* <html>
* <head>
* <title><b>{title}</b></title>
* <meta http-equiv="content-type" content="text/html; charset=<b>{charset}</b>"/>
* <b>{htmlMeta}</b>
* </head>
* <body>
* <b>{htmlBody}</b>
* </body>
* </html>
* </pre>
* + Переменные из функции getFlatProperties
* @param metaTmpl Шаблон свойств:<br/>
* <pre>
* <meta name="<b>{key}</b>" content="<b>{value}</b>" />
* </pre>
* @see #getFlatProperties(com.google.gdata.data.Entry, org.gocha.collection.Convertor)
*/
public static void export(File target,Entry entry,String htmlTmpl,String metaTmpl,Convertor<DateTime,String> timeConvertor) {
if (target== null) throw new IllegalArgumentException("target==null");
if (entry== null) throw new IllegalArgumentException("entry==null");
if (htmlTmpl== null) throw new IllegalArgumentException("htmlTmpl==null");
if (metaTmpl== null) throw new IllegalArgumentException("metaTmpl==null");
Content content = entry.getContent();
if( !(content instanceof TextContent) )
throw new Error(
CLI.messages().contentNotInstanceOfText() );
try{
String htmlBody = getHtmlBodyOf((TextContent)content);
Map<String,String> props = getFlatProperties(entry, CLI.postIDConvertor, timeConvertor);
Charset cs = FileUtil.UTF8();
FileOutputStream fout = new FileOutputStream(target);
OutputStreamWriter strW = new OutputStreamWriter(fout, cs);
IndentStackWriter writer = new IndentStackWriter(strW);
HashMap<String,String> t = new HashMap<String, String>();
writer.push();
for(Map.Entry<String,String> kv : props.entrySet()){
t.put( "key", TextUtil.htmlEncode(kv.getKey()) );
t.put( "value", TextUtil.htmlEncode(kv.getValue()) );
writer.println(TextUtil.template(metaTmpl, t));
}
String htmlMeta = writer.pop();
t.putAll(props);
t.put("htmlMeta", htmlMeta);
t.put("htmlBody", htmlBody);
t.put("charset", cs.name());
writer.println(TextUtil.template(htmlTmpl, t));
writer.flush();
strW.flush();
fout.flush();
fout.close();
}catch(Throwable e){
throw new Error(e.getMessage(), e);
}
}
}