/*
* RapidMiner
*
* Copyright (C) 2001-2011 by Rapid-I and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapid-i.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.doc;
import java.io.PrintWriter;
import java.io.StringReader;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.rapidminer.tools.LogService;
import com.rapidminer.tools.Tools;
/**
* Formats operator documentation in LaTeX style.
*
* @rapidminer.todo Lookup class when link is found and decide which tag to use (op, ioobj, ...)
* @author Simon Fischer, Ingo Mierswa
*/
public class LatexOperatorDocGenerator extends AbstractOperatorDocGenerator {
public static final String[][] TAGS = { { "", "" }, // operator
{ "\\operator{", "}" }, // operator name
{ "\\group{", "}" }, // group
{ Tools.getLineSeparator() + "\\begin{parameters}", "\\end{parameters}" }, // parameter list
{ "", "" }, // parameter item
{ "\\reqpar[", "]" }, // required parameter
{ "\\optpar[", "]" }, // optional parameter
{ "", "" }, // parameter description
{ "\\paragraph{Short description:} ", "" }, // short description
{ "\\opdescr ", "" }, // operator description
{ "\\begin{opin} ", "\\end{opin}" }, // input classes list
{ "\\begin{opout} ", "\\end{opout}" }, // output classes list
{ "\\item[", "]" }, // IO class
{ Tools.getLineSeparator() + "\\paragraph{Inner operators:}", Tools.getLineSeparator() }, // inner operators
{ Tools.getLineSeparator() + "\\begin{values}", "\\end{values}" }, // value list
{ "", "" }, // value item
{ "\\val[", "]" }, // value name
{ "", "" }, // value description
{ "\\index{", "}" }, // index entry
{ "\\par References: ", "" }, // reference section
{ "\\cite{", "}" }, // reference entry
{ Tools.getLineSeparator() + "\\paragraph{Further information:}", Tools.getLineSeparator() }, // technical information (external references)
{ "\\emph{", "}" + Tools.getLineSeparator() }, // deprecation info
{ Tools.getLineSeparator() + "\\paragraph{Learner capabilities:}", Tools.getLineSeparator() } // learner capabilities
};
public String getOpenTag(int tagNo) {
return TAGS[tagNo][0];
}
public String getCloseTag(int tagNo) {
return TAGS[tagNo][1];
}
public String marginIcon(String iconName) {
String fig = "\\includegraphics{graphics/" + iconName + "}";
return "\\marginpar[\\flushright" + fig + "]{" + fig + "}";
}
public String escape(String toEscape) {
String escaped = toEscape;
escaped = escaped.replaceAll("MACRO_START", "\\\\% \\\\{"); // hack for macro definitions
escaped = escaped.replaceAll("MACRO_END", "\\\\}"); // hack for macro definitions
escaped = escaped.replaceAll("_", "\\\\_");
escaped = escaped.replaceAll("\\$", "\\\\\\$");
escaped = escaped.replaceAll("\u221E", "\\$\\\\infty\\$");
escaped = escaped.replaceAll("ä", "\\\\\"a");
escaped = escaped.replaceAll("ö", "\\\\\"o");
escaped = escaped.replaceAll("ü", "\\\\\"u");
escaped = escaped.replaceAll("Ä", "\\\\\"A");
escaped = escaped.replaceAll("Ö", "\\\\\"O");
escaped = escaped.replaceAll("Ü", "\\\\\"U");
escaped = escaped.replaceAll("ß", "\\\\\"s");
escaped = escaped.replaceAll(" ", "\\\\ ");
escaped = escaped.replaceAll("(\\w)"", "$1''");
escaped = escaped.replaceAll(""", "``");
escaped = escaped.replaceAll("#", "\\\\#");
escaped = escaped.replaceAll("\\[", "\\{\\[\\}");
escaped = escaped.replaceAll("\\]", "\\{\\]\\}");
escaped = escaped.replaceAll("RapidMiner", "\\\\RAPIDMINER");
escaped = escaped.replaceAll("\\\\s", "\\$\\\\backslash\\$s"); // hack for regular expressions (ExampleSource)
escaped = escaped.replaceAll("\\\\t", "\\$\\\\backslash\\$t"); // hack for regular expressions (ExampleSource)
escaped = escaped.replaceAll("\\|", "\\$|\\$");
escaped = escaped.replaceAll("\\^", "");
return escaped;
}
public void beginGroup(String groupName, PrintWriter out) {
out.println("\\pagebreak[4]");
if (groupName != null) {
groupName = groupName.replace(' ', '_');
out.println("\\input{OpGroup" + groupName + ".tex}");
} else {
out.println("\\section{Basic operators}");
}
}
public void endGroup(String groupName, PrintWriter out) {
out.println("\\vfill");
}
public String transformHTMLJavadocComment(String comment, final Class clazz, final String operatorName) {
try {
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
comment = "<body>" + comment + "</body>";
final StringBuffer transformed = new StringBuffer();
final Stack<String> closingTagStack = new Stack<String>();
parser.parse(new InputSource(new StringReader(comment)), new DefaultHandler() {
public void characters(char[] ch, int start, int length) throws SAXException {
transformed.append(ch, start, length);
}
public InputSource resolveEntity(String publicId, String systemId) throws SAXException {
LogService.getGlobal().log("Entity: " + publicId, LogService.STATUS);
String latex;
if (systemId.equals(""")) {
latex = "``";
} else if (systemId.equals("ä")) {
latex = "\\\"a";
} else if (systemId.equals("ö")) {
latex = "\\\"o";
} else if (systemId.equals("ü")) {
latex = "\\\"u";
} else if (systemId.equals("Ä")) {
latex = "\\\"A";
} else if (systemId.equals("Ö")) {
latex = "\\\"O";
} else if (systemId.equals("Ü")) {
latex = "\\\"U";
} else if (systemId.equals("ß")) {
latex = "\\\"s";
} else if (systemId.equals(" ")) {
latex = "\\ ";
} else {
LogService.getGlobal().log("Unknown entity: " + systemId, LogService.WARNING);
latex = systemId;
}
return new InputSource(new StringReader(latex));
}
public void endElement(String uri, String localName, String qName) {
transformed.append(closingTagStack.pop());
}
public void startElement(String uri, String localName, String qName, Attributes attributes) {
qName = qName.toLowerCase();
if (qName.equals("code")) {
transformed.append("\\java{");
closingTagStack.push("}");
} else if (qName.equals("em")) {
transformed.append("\\emph{");
closingTagStack.push("}");
} else if (qName.equals("var")) {
transformed.append("\\para{");
closingTagStack.push("}");
} else if (qName.equals("b")) {
LogService.getGlobal().log(operatorName + " (" + clazz.getName() + "): physical markup used (b,i, or tt).", LogService.WARNING);
transformed.append("\\textbf{");
closingTagStack.push("}");
} else if (qName.equals("i")) {
LogService.getGlobal().log(operatorName + " (" + clazz.getName() + "): physical markup used (b,i, or tt).", LogService.WARNING);
transformed.append("\\textit{");
closingTagStack.push("}");
} else if (qName.equals("tt")) {
LogService.getGlobal().log(operatorName + " (" + clazz.getName() + "): physical markup used (b,i, or tt).", LogService.WARNING);
transformed.append("\\texttt{");
closingTagStack.push("}");
} else if (qName.equals("center")) {
transformed.append(Tools.getLineSeparator() + "\\begin{center}" + Tools.getLineSeparator());
closingTagStack.push(Tools.getLineSeparator() + "\\end{center}" + Tools.getLineSeparator());
} else if (qName.equals("ol")) {
transformed.append(Tools.getLineSeparator() + "\\begin{enumerate}" + Tools.getLineSeparator());
closingTagStack.push(Tools.getLineSeparator() + "\\end{enumerate}" + Tools.getLineSeparator());
} else if (qName.equals("ul")) {
transformed.append(Tools.getLineSeparator() + "\\begin{itemize}" + Tools.getLineSeparator());
closingTagStack.push(Tools.getLineSeparator() + "\\end{itemize}" + Tools.getLineSeparator());
} else if (qName.equals("li")) {
transformed.append(Tools.getLineSeparator() + "\\item ");
closingTagStack.push("");
} else if (qName.equals("dl")) {
transformed.append(Tools.getLineSeparator() + "\\begin{description}" + Tools.getLineSeparator());
closingTagStack.push(Tools.getLineSeparator() + "\\end{description}" + Tools.getLineSeparator());
} else if (qName.equals("dt")) {
transformed.append(Tools.getLineSeparator() + "\\item[");
closingTagStack.push("]");
} else if (qName.equals("dd")) {
// nothing for dd
closingTagStack.push("");
} else if (qName.equals("body")) {
transformed.append("");
closingTagStack.push("");
} else if (qName.equals("sup")) {
transformed.append("$^{");
closingTagStack.push("}$");
} else if (qName.equals("sub")) {
transformed.append("$_{");
closingTagStack.push("}$");
} else if (qName.equals("br")) {
transformed.append("\\par" + Tools.getLineSeparator());
closingTagStack.push("");
} else if (qName.equals("p")) {
transformed.append("\\par" + Tools.getLineSeparator());
closingTagStack.push("");
} else if (qName.equals("a")) {
closingTagStack.push("\\footnote{\\url{" + attributes.getValue("href") + "}}");
} else if (qName.equals("h1") || qName.equals("h2") || qName.equals("h3") || qName.equals("h4") || qName.equals("h5")) {
transformed.append(Tools.getLineSeparator() + "\\paragraph{");
closingTagStack.push("}");
} else if (qName.equals("pre")) {
transformed.append("\\begin{verbatim}");
closingTagStack.push("\\end{verbatim}");
} else {
transformed.append("");
closingTagStack.push("");
LogService.getGlobal().log("Unknown tag: " + qName + " (" + operatorName + " (" + clazz.getName() + "))", LogService.WARNING);
}
}
});
StringBuffer linksReplaced = new StringBuffer();
Pattern pattern = Pattern.compile("\\{@link (.*?)\\}");
Matcher matcher = pattern.matcher(transformed);
while (matcher.find()) {
String classname = matcher.group(1);
int period = classname.lastIndexOf(".");
if (period != -1)
classname = classname.substring(period + 1);
matcher.appendReplacement(linksReplaced, "\\\\op{" + classname + "}");
}
matcher.appendTail(linksReplaced);
return linksReplaced.toString();
} catch (Throwable e) {
LogService.getGlobal().log(operatorName + " (" + clazz.getName() + "): " + e, LogService.ERROR);
return "Cannot parse class comment: " + e;
}
}
}