All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nuiton.jrst.JRSTGenerator Maven / Gradle / Ivy

There is a newer version: 2.4
Show newest version
/*
 * #%L
 * JRst :: Api
 * %%
 * Copyright (C) 2004 - 2010 CodeLutin
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser 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 General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */


package org.nuiton.jrst;

import java.io.IOException;
import java.io.Writer;
import java.net.URL;
import java.util.LinkedList;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.Text;
import org.dom4j.io.DocumentResult;
import org.dom4j.io.DocumentSource;
import org.nuiton.jrst.legacy.DocumentHandler;
import org.nuiton.jrst.legacy.DocumentWalker;
import org.nuiton.util.FasterCachedResourceResolver;
import org.xml.sax.ContentHandler;

import static org.nuiton.jrst.legacy.ReStructuredText.ADDRESS;
import static org.nuiton.jrst.legacy.ReStructuredText.AUTHOR;
import static org.nuiton.jrst.legacy.ReStructuredText.AUTHORS;
import static org.nuiton.jrst.legacy.ReStructuredText.BULLET_LIST;
import static org.nuiton.jrst.legacy.ReStructuredText.CLASSIFIER;
import static org.nuiton.jrst.legacy.ReStructuredText.CONTACT;
import static org.nuiton.jrst.legacy.ReStructuredText.COPYRIGHT;
import static org.nuiton.jrst.legacy.ReStructuredText.DATE;
import static org.nuiton.jrst.legacy.ReStructuredText.DEFINITION;
import static org.nuiton.jrst.legacy.ReStructuredText.DEFINITION_LIST;
import static org.nuiton.jrst.legacy.ReStructuredText.DOCINFO;
import static org.nuiton.jrst.legacy.ReStructuredText.EMPHASIS;
import static org.nuiton.jrst.legacy.ReStructuredText.ENUMERATED_LIST;
import static org.nuiton.jrst.legacy.ReStructuredText.FIELD_BODY;
import static org.nuiton.jrst.legacy.ReStructuredText.FIELD_LIST;
import static org.nuiton.jrst.legacy.ReStructuredText.FIELD_NAME;
import static org.nuiton.jrst.legacy.ReStructuredText.LIST_ITEM;
import static org.nuiton.jrst.legacy.ReStructuredText.LITERAL;
import static org.nuiton.jrst.legacy.ReStructuredText.LITERAL_BLOCK;
import static org.nuiton.jrst.legacy.ReStructuredText.ORGANIZATION;
import static org.nuiton.jrst.legacy.ReStructuredText.PARAGRAPH;
import static org.nuiton.jrst.legacy.ReStructuredText.REVISION;
import static org.nuiton.jrst.legacy.ReStructuredText.SECTION;
import static org.nuiton.jrst.legacy.ReStructuredText.STATUS;
import static org.nuiton.jrst.legacy.ReStructuredText.STRONG;
import static org.nuiton.jrst.legacy.ReStructuredText.TABLE;
import static org.nuiton.jrst.legacy.ReStructuredText.TITLE;
import static org.nuiton.jrst.legacy.ReStructuredText.TITLE_CHAR;
import static org.nuiton.jrst.legacy.ReStructuredText.TRANSITION;
import static org.nuiton.jrst.legacy.ReStructuredText.VERSION;

/**
 * Cette classe contient plusieurs methodes pour générer, soit en utilisant une
 * feuille de style {@link #generate(Document, URL, Writer)}, soit un
 * {@link ContentHandler} avec {@link #generate(Document, ContentHandler)}, soit
 * {@link org.nuiton.jrst.legacy.DocumentHandler} avec {@link #generate(Document, ContentHandler)} ou
 * bien regénérer du RST avec {@link #generate(Document)} dans les deux derniers
 * cas il faut passer un {@link Writer} en parametre du constructeur.
 * 

* On peut aussi transformer le {@link Document} en un autre {@link Document} * avec {@link #transform(Document, URL)} * * Created: 30 oct. 06 00:14:18 * * @author poussin * @version $Revision$ * * Last update: $Date$ * by : $Author$ */ public class JRSTGenerator implements DocumentHandler { static boolean DEBUG = true; static private Log log = LogFactory.getLog(JRSTGenerator.class); protected Writer out; protected int sectionLevel; protected int indent; protected String listType = "bullet|enumerated|..."; protected int enumStart = 1; protected URIResolver uriResolver; public JRSTGenerator() { } public JRSTGenerator(Writer out) { this.out = out; } /** * @return the uriResolver */ public URIResolver getUriResolver() { return uriResolver; } /** * @param uriResolver * the uriResolver to set */ public void setUriResolver(URIResolver uriResolver) { this.uriResolver = uriResolver; } /** * Generate using this class as handler, this generate RST text to out * passed in constructor * * @param doc document to transform * @throws IOException */ public void generate(Document doc) throws IOException { generate(doc, this); } public void generate(Document doc, DocumentHandler handler) { DocumentWalker walker = new DocumentWalker(handler); walker.walk(doc); } /** * Generate using handler passed in argument * * @param doc document * @param handler saxon content handler * @throws IOException * @throws TransformerException */ public void generate(Document doc, ContentHandler handler) throws IOException, TransformerException { // load the transformer using JAXP TransformerFactory factory = TransformerFactory.newInstance(); if (uriResolver != null) { factory.setURIResolver(uriResolver); } Transformer transformer = factory.newTransformer(); // now lets style the given document DocumentSource source = new DocumentSource(doc); SAXResult result = new SAXResult(handler); transformer.transform(source, result); } /** * Used writer passed in construction class * * @param doc document to transform * @param stylesheet to apply * @throws IOException * @throws TransformerException */ public void generate(Document doc, URL stylesheet) throws IOException, TransformerException { generate(doc, stylesheet, out); } /** * Generate out from document using stylesheet * * @param doc document to transform * @param stylesheet to apply * @param out output * @throws IOException * @throws TransformerException */ public void generate(Document doc, URL stylesheet, Writer out) throws IOException, TransformerException { // load the transformer using JAXP TransformerFactory factory = TransformerFactory.newInstance(); if (uriResolver != null) { factory.setURIResolver(uriResolver); } else { factory.setURIResolver(new FasterCachedResourceResolver(stylesheet.toString())); } Transformer transformer = factory.newTransformer(new StreamSource( stylesheet.openStream())); // now lets style the given document DocumentSource source = new DocumentSource(doc); StreamResult result = new StreamResult(out); transformer.transform(source, result); out.flush(); } /** * Transform doc in another XML document. * * @param doc document to transform * @param stylesheet to apply * @return the transformed document * @throws TransformerException * @throws IOException */ public Document transform(Document doc, URL stylesheet) throws TransformerException, IOException { if (log.isInfoEnabled()) { log.debug("Transform document using : " + stylesheet); } // load the transformer using JAXP TransformerFactory factory = TransformerFactory.newInstance(); if (uriResolver != null) { factory.setURIResolver(uriResolver); } else { factory.setURIResolver(new FasterCachedResourceResolver(stylesheet.toString())); } Transformer transformer = factory.newTransformer(new StreamSource( stylesheet.openStream())); // now lets style the given document DocumentSource source = new DocumentSource(doc); DocumentResult result = new DocumentResult(); transformer.transform(source, result); // return the transformed document Document transformedDoc = result.getDocument(); return transformedDoc; } protected String string(String s, int number) { String result = ""; for (int i = 0; i < number; i++) { result += s; } return result; } protected String enumtype(int i, String type) { String result = null; if ("arabic".equals(type)) { result = String.valueOf(i); } else if ("loweralpha".equals(type)) { result = String.valueOf((char) ((int) 'a' + i)); } else if ("upperalpha".equals(type)) { result = String.valueOf((char) ((int) 'A' + i)); } else if ("lowerroman".equals(type) || "upperroman".equals(type)) { String[] c = new String[] { "i", "v", "x", "l", "c", "d", "m" }; int[] d = new int[] { 1, 5, 10, 50, 100, 500, 1000 }; result = ""; for (int a = 0; a < c.length; a++) { result = string(c[a], i / d[a]) + result; i = i % d[a]; } if ("upperroman".equals(type)) { result = result.toUpperCase(); } } return result; } /** * Determine la longueur du text dans l'element * <emphasis>toto</emphasis> qui donne *toto* retournera 6 * * @param e element * @return la longueur du text dans l'element. */ @SuppressWarnings("unchecked") protected int inlineLength(Element e) { int result = 0; LinkedList elems = new LinkedList(); elems.addAll(e.content()); while (elems.peek() != null) { Node elem = elems.poll(); switch (elem.getNodeType()) { case Node.ELEMENT_NODE: elems.addAll(((Element) elem).content()); if (EMPHASIS.equals(elem.getName())) { result += 2; } else if (STRONG.equals(elem.getName())) { result += 4; } else if (LITERAL.equals(elem.getName())) { result += 4; } // perhaps do footnote_refence, ... break; case Node.TEXT_NODE: result += elem.getText().length(); break; } } return result; } /* * (non-Javadoc) * * @see org.nuiton.jrst.legacy.DocumentHandler#startDocument(org.dom4j.Document) */ @Override public void startDocument(Document doc) { } /* * (non-Javadoc) * * @see org.nuiton.jrst.legacy.DocumentHandler#endDocument(org.dom4j.Document) */ @Override public void endDocument(Document doc) { } /* * (non-Javadoc) * * @see org.nuiton.jrst.legacy.DocumentHandler#endElement(org.dom4j.Element) */ @Override public void endElement(Element e) { boolean needNewLine = false; if (SECTION.equals(e.getName())) { sectionLevel--; needNewLine = true; } else if (PARAGRAPH.equals(e.getName())) { newLine(); needNewLine = true; } else if (TITLE.equals(e.getName())) { newLine(); if (sectionLevel == 0) { write(string("=", inlineLength(e))); } else { String c = TITLE_CHAR.substring(sectionLevel, sectionLevel + 1); write(string(c, inlineLength(e))); } newLine(); needNewLine = true; } else if (EMPHASIS.equals(e.getName())) { write("*"); } else if (STRONG.equals(e.getName())) { write("**"); } else if (LITERAL.equals(e.getName())) { write("``"); } else if (DOCINFO.equals(e.getName())) { needNewLine = true; } else if (LITERAL_BLOCK.equals(e.getName())) { indent--; newLine(); needNewLine = true; } else if (TABLE.equals(e.getName())) { // TODO now we take table as LITERAL_BLOCK, but in near // futur we must parse correctly TABLE (show JRSTReader and // JRSTLexer too) newLine(); needNewLine = true; } else if (BULLET_LIST.equals(e.getName())) { needNewLine = true; } else if (ENUMERATED_LIST.equals(e.getName())) { needNewLine = true; } else if (FIELD_LIST.equals(e.getName())) { needNewLine = true; } else if (FIELD_BODY.equals(e.getName())) { indent--; } else if (DEFINITION_LIST.equals(e.getName())) { needNewLine = true; } else if (DEFINITION.equals(e.getName())) { indent--; } else if (LIST_ITEM.equals(e.getName())) { indent--; } else if (AUTHOR.equals(e.getName())) { newLine(); indent--; } else if (AUTHORS.equals(e.getName())) { newLine(); indent--; } else if (ORGANIZATION.equals(e.getName())) { newLine(); indent--; } else if (ADDRESS.equals(e.getName())) { newLine(); indent--; } else if (CONTACT.equals(e.getName())) { newLine(); indent--; } else if (VERSION.equals(e.getName())) { newLine(); indent--; } else if (REVISION.equals(e.getName())) { newLine(); indent--; } else if (STATUS.equals(e.getName())) { newLine(); indent--; } else if (DATE.equals(e.getName())) { newLine(); indent--; } else if (COPYRIGHT.equals(e.getName())) { newLine(); indent--; } if (needNewLine) { // on ajoute une nouvelle ligne que si on est pas le dernier // fils, cela evite que le fils, le pere, et le grand-pere ne // demande tous une nouvelle ligne et donc au lieu d'en avoir // une comme on le souhaite on en est 3 voir plus Element parent = e.getParent(); Node lastNode = parent.node(parent.nodeCount() - 1); if (lastNode != e) { // write("** new line ** " + e.getName() + ":" + // lastNode.getName()); newLine(); } } } /* * (non-Javadoc) * * @see org.nuiton.jrst.legacy.DocumentHandler#startElement(org.dom4j.Element) */ @Override public void startElement(Element e) { if (SECTION.equals(e.getName())) { sectionLevel++; } else if (TITLE.equals(e.getName())) { if (sectionLevel == 0) { write(string("=", inlineLength(e))); newLine(); } } else if (PARAGRAPH.equals(e.getName())) { Element parent = e.getParent(); if (!((LIST_ITEM.equals(parent.getName()) || FIELD_BODY .equals(parent.getName())) && parent.node(0) == e)) { writeIndent(); } } else if (TRANSITION.equals(e.getName())) { write(string("-", 80)); newLine(); newLine(); } else if (EMPHASIS.equals(e.getName())) { write("*"); } else if (STRONG.equals(e.getName())) { write("**"); } else if (LITERAL.equals(e.getName())) { write("``"); } else if (AUTHOR.equals(e.getName())) { write(":Author: "); indent++; } else if (AUTHORS.equals(e.getName())) { write(":Authors: "); indent++; } else if (ORGANIZATION.equals(e.getName())) { write(":Organization: "); indent++; } else if (ADDRESS.equals(e.getName())) { write(":Address: "); indent++; } else if (CONTACT.equals(e.getName())) { write(":Contact: "); indent++; } else if (VERSION.equals(e.getName())) { write(":Version: "); indent++; } else if (REVISION.equals(e.getName())) { write(":Revision: "); indent++; } else if (STATUS.equals(e.getName())) { write(":Status: "); indent++; } else if (DATE.equals(e.getName())) { write(":Date: "); indent++; } else if (COPYRIGHT.equals(e.getName())) { write(":Copyright: "); indent++; } else if (FIELD_NAME.equals(e.getName())) { writeIndent(":"); } else if (FIELD_BODY.equals(e.getName())) { write(": "); indent++; } else if (CLASSIFIER.equals(e.getName())) { write(" : "); } else if (DEFINITION.equals(e.getName())) { // pour une fois on est obligé de passer une ligne dans le // start, car on ne sait pas determiner la fin des classifiers // qui doivent etre tous sur la ligne du TERM newLine(); indent++; } else if (LITERAL_BLOCK.equals(e.getName())) { write("::"); newLine(); newLine(); indent++; } else if (TABLE.equals(e.getName())) { // TODO now we take table as LITERAL_BLOCK, but in near // futur we must parse correctly TABLE (show JRSTReader and // JRSTLexer too) } else if (BULLET_LIST.equals(e.getName())) { listType = BULLET_LIST; } else if (ENUMERATED_LIST.equals(e.getName())) { listType = ENUMERATED_LIST; enumStart = Integer.parseInt(e.attributeValue("start")); } else if (LIST_ITEM.equals(e.getName())) { if (BULLET_LIST.equals(listType)) { writeIndent("- "); } else if (ENUMERATED_LIST.equals(listType)) { writeIndent(enumtype(enumStart++, e.getParent().attributeValue( "enumtype")) + ". "); } indent++; } } /* * (non-Javadoc) * * @see org.nuiton.jrst.legacy.DocumentHandler#text(org.dom4j.Text) */ @Override public void text(Text t) { if (LITERAL_BLOCK.equals(t.getParent().getName())) { writeIndent(t.getText()); } else { write(t.getText()); } } protected void newLine() { write("\n"); } protected void write(String text) { write(text, false); } protected void writeIndent() { write("", true); } protected void writeIndent(String text) { write(text, true); } /** * Ecrit le text, si indent est vrai, alors chaque ligne est indentée * * @param text text to write * @param doIndent do indent */ protected void write(String text, boolean doIndent) { try { String blank = ""; if (doIndent) { blank = string(" ", indent); } out.write(blank); for (char c : text.toCharArray()) { out.write(c); if (c == '\n') { out.write(blank); } } } catch (IOException eee) { if (log.isWarnEnabled()) { log.warn("TODO untreated error", eee); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy