/*
* Copyright (C) 2010 eXo Platform SAS.
*
* This 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 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wikbook.xwiki;
import org.w3c.dom.Document;
import org.wikbook.core.Utils;
import org.wikbook.core.model.DocbookBuilder;
import org.wikbook.core.WikbookException;
import org.wikbook.core.model.content.block.AdmonitionKind;
import org.wikbook.core.model.content.block.LanguageSyntax;
import org.wikbook.core.model.content.block.ListKind;
import org.wikbook.core.model.content.inline.TextFormat;
import org.wikbook.core.xml.OutputFormat;
import org.wikbook.core.xml.XML;
import org.xwiki.rendering.block.Block;
import org.xwiki.rendering.listener.Format;
import org.xwiki.rendering.listener.HeaderLevel;
import org.xwiki.rendering.listener.ListType;
import org.xwiki.rendering.listener.Listener;
import org.xwiki.rendering.listener.MetaData;
import org.xwiki.rendering.listener.reference.ResourceReference;
import org.xwiki.rendering.listener.reference.ResourceType;
import org.xwiki.rendering.syntax.Syntax;
import javax.xml.transform.Transformer;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;
import java.io.IOException;
import java.io.StringReader;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
/**
* @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
* @version $Revision$
*/
class XDOMTransformer implements Listener
{
/** . */
private static final Map<String, AdmonitionKind> admonitions = new HashMap<String, AdmonitionKind>();
/** . */
private static final EnumMap<Format, TextFormat> formatMapping = new EnumMap<Format, TextFormat>(Format.class);
/** . */
private static final EnumMap<ListType, ListKind> mapping = new EnumMap<ListType, ListKind>(ListType.class);
static
{
mapping.put(ListType.BULLETED, ListKind.BULLETED);
mapping.put(ListType.NUMBERED, ListKind.NUMBERED);
}
static
{
admonitions.put("note", AdmonitionKind.NOTE);
admonitions.put("info", AdmonitionKind.NOTE);
admonitions.put("important", AdmonitionKind.IMPORTANT);
admonitions.put("tip", AdmonitionKind.TIP);
admonitions.put("caution", AdmonitionKind.CAUTION);
admonitions.put("warning", AdmonitionKind.WARNING);
}
static
{
formatMapping.put(Format.BOLD, TextFormat.BOLD);
formatMapping.put(Format.ITALIC, TextFormat.ITALIC);
formatMapping.put(Format.MONOSPACE, TextFormat.MONOSPACE);
formatMapping.put(Format.SUPERSCRIPT, TextFormat.SUPERSCRIPT);
formatMapping.put(Format.SUBSCRIPT, TextFormat.SUBSCRIPT);
formatMapping.put(Format.UNDERLINED, TextFormat.UNDERLINE);
formatMapping.put(Format.STRIKEDOUT, TextFormat.STRIKE);
}
/** . */
private DocbookBuilder builder;
/** . */
final AbstractXDOMDocbookBuilderContext context;
public XDOMTransformer(AbstractXDOMDocbookBuilderContext context, DocbookBuilder builder)
{
this.context = context;
this.builder = builder;
}
public void beginDocument(MetaData metaData)
{
}
public void endDocument(MetaData metaData)
{
}
public void beginMetaData(MetaData metaData)
{
}
public void endMetaData(MetaData metaData)
{
}
public void beginParagraph(Map<String, String> parameters)
{
builder.beginParagraph();
}
public void endParagraph(Map<String, String> parameters)
{
builder.endParagraph();
}
//
public void beginSection(Map<String, String> parameters)
{
builder.beginSection();
}
public void endSection(Map<String, String> parameters)
{
builder.endSection();
}
public void beginHeader(HeaderLevel level, String id, Map<String, String> parameters)
{
builder.beginHeader();
}
public void endHeader(HeaderLevel level, String id, Map<String, String> parameters)
{
builder.endHeader();
}
//
public void onWord(String word)
{
builder.onText(word);
}
public void onSpace()
{
builder.onText(" ");
}
public void onNewLine()
{
// For now we dont take in account line breaks
builder.onText(" ");
}
public void onSpecialSymbol(char symbol)
{
// For now it will be ok
builder.onText(Character.toString(symbol));
}
public void beginFormat(Format format, Map<String, String> parameters)
{
TextFormat textFormat = formatMapping.get(format);
if (textFormat == null)
{
context.onValidationError("Format " + format + " is not yet supported");
}
else
{
builder.beginFormat(textFormat);
}
}
public void endFormat(Format format, Map<String, String> parameters)
{
TextFormat textFormat = formatMapping.get(format);
if (textFormat == null)
{
context.onValidationError("Format " + format + " is not yet supported");
}
else
{
builder.endFormat(textFormat);
}
}
//
public void beginList(ListType listType, Map<String, String> parameters)
{
String style = parameters.get("style");
ListKind lk = mapping.get(listType);
builder.beginList(lk, style);
}
public void endList(ListType listType, Map<String, String> parameters)
{
String style = parameters.get("style");
ListKind lk = mapping.get(listType);
builder.endList(lk, style);
}
public void beginListItem()
{
builder.beginListItem();
}
public void endListItem()
{
builder.endListItem();
}
//
public void onMacro(String id, Map<String, String> macroParameters, String content, boolean isInline)
{
_onMacro(id, macroParameters, content, builder.isInlineContext());
}
private void _onMacro(String id, Map<String, String> macroParameters, String content, boolean isInline)
{
AdmonitionKind admonition = admonitions.get(id);
if (admonition != null)
{
WikiLoader loader = new WikiLoader(context);
Block block = loader.load(new StringReader(content), context.syntaxStack.getLast());
//
builder.beginAdmonition(admonition);
block.traverse(this);
builder.endAdmonition(admonition);
}
else if ("screen".equals(id))
{
builder.beginScreen();
builder.onText(content);
builder.endScreen();
}
else if ("anchor".equals(id))
{
String anchor = macroParameters.get("id");
// Special confluence support for anchor:foo
if (anchor == null)
{
anchor = macroParameters.get("value");
}
//
builder.onAnchor(anchor);
}
else if ("docbook".equals(id))
{
try
{
Transformer transformer = XML.createTransformer(new OutputFormat(2, true));
// Perform identity transformation
DOMResult result = new DOMResult();
//
transformer.transform(new StreamSource(new StringReader(content)), result);
//
builder.onDocbook(((Document)result.getNode()).getDocumentElement());
}
catch (Exception e)
{
throw new WikbookException(e);
}
}
else if ("code".equals(id) || "java".equals(id) || "xml".equals(id))
{
LanguageSyntax languageSyntax = LanguageSyntax.UNKNOWN;
if ("java".equals(id))
{
languageSyntax = LanguageSyntax.JAVA;
}
else if ("xml".equals(id))
{
languageSyntax = LanguageSyntax.XML;
}
else
{
String language = macroParameters.get("language");
if ("java".equalsIgnoreCase(language))
{
languageSyntax = LanguageSyntax.JAVA;
}
else if ("groovy".equalsIgnoreCase(language))
{
languageSyntax = LanguageSyntax.JAVA;
}
else if ("xml".equalsIgnoreCase(language))
{
languageSyntax = LanguageSyntax.XML;
}
String href = macroParameters.get("href");
if (href != null)
{
try
{
content = Utils.read(Utils.read(context.resolveResource(org.wikbook.core.ResourceType.DEFAULT, href), context.getCharsetName()));
}
catch (IOException e)
{
content = Utils.toString(e);
}
}
// Support Confluence code:java and code:xml
if (language == null)
{
String value = macroParameters.get("value");
if (value != null)
{
if ("java".equalsIgnoreCase(value))
{
languageSyntax = LanguageSyntax.JAVA;
}
else if ("groovy".equalsIgnoreCase(value))
{
languageSyntax = LanguageSyntax.JAVA;
}
else if ("xml".equalsIgnoreCase(value))
{
languageSyntax = LanguageSyntax.XML;
}
}
}
}
//
Integer indent = null;
if (macroParameters.get("indent") != null)
{
try
{
indent = Integer.parseInt(macroParameters.get("indent"));
}
catch (NumberFormatException e)
{
e.printStackTrace();
}
}
//
builder.onCode(
languageSyntax,
indent,
content
);
}
else if ("example".equals(id))
{
// if (isInline)
// {
// throw new UnsupportedOperationException();
// }
WikiLoader loader = new WikiLoader(context);
Block block = loader.load(new StringReader(content), context.syntaxStack.getLast());
builder.beginExample(macroParameters.get("title"));
block.traverse(this);
builder.endExample(macroParameters.get("title"));
}
else if ("noformat".equals(id))
{
builder.onVerbatim(content);
}
else
{
context.onValidationError("Unsupported macro " + id);
}
}
//
public void beginLink(ResourceReference link, boolean isFreeStandingURI, Map<String, String> parameters)
{
if (link.getType() == ResourceType.URL)
{
String ref = link.getReference();
org.wikbook.core.model.content.inline.LinkType type;
if (ref.startsWith("#"))
{
ref = ref.substring(1);
type = org.wikbook.core.model.content.inline.LinkType.ANCHOR;
}
else
{
type = org.wikbook.core.model.content.inline.LinkType.URL;
}
builder.beginLink(type, ref);
}
else
{
context.onValidationError("Unsupported link type " + link.getType());
}
}
public void endLink(ResourceReference link, boolean isFreeStandingURI, Map<String, String> parameters)
{
if (link.getType() == ResourceType.URL)
{
String ref = link.getReference();
org.wikbook.core.model.content.inline.LinkType type;
if (ref.startsWith("#"))
{
ref = ref.substring(1);
type = org.wikbook.core.model.content.inline.LinkType.ANCHOR;
}
else
{
type = org.wikbook.core.model.content.inline.LinkType.URL;
}
builder.endLink(type, ref);
}
else
{
context.onValidationError("Unsupported link type " + link.getType());
}
}
//
public void beginTable(Map<String, String> parameters)
{
String title = parameters.get("title");
builder.beginTable(title);
}
public void beginTableRow(Map<String, String> parameters)
{
builder.beginTableRow(parameters);
}
public void beginTableCell(Map<String, String> parameters)
{
builder.beginTableCell(parameters);
}
public void beginTableHeadCell(Map<String, String> parameters)
{
builder.beginTableHeadCell(parameters);
}
public void endTable(Map<String, String> parameters)
{
String title = parameters.get("title");
builder.endTable(title);
}
public void endTableRow(Map<String, String> parameters)
{
builder.endTableRow(parameters);
}
public void endTableCell(Map<String, String> parameters)
{
builder.endTableCell(parameters);
}
public void endTableHeadCell(Map<String, String> parameters)
{
builder.endTableHeadCell(parameters);
}
//
public void beginGroup(Map<String, String> parameters)
{
builder.beginGroup();
}
public void endGroup(Map<String, String> parameters)
{
builder.endGroup();
}
//
public void beginDefinitionList(Map<String, String> parameters)
{
String title = parameters.get("title");
builder.beginDefinitionList(title);
}
public void beginDefinitionTerm()
{
builder.beginDefinitionTerm();
}
public void endDefinitionTerm()
{
builder.endDefinitionTerm();
}
public void beginDefinitionDescription()
{
builder.beginDefinitionDescription();
}
public void endDefinitionDescription()
{
builder.endDefinitionDescription();
}
public void endDefinitionList(Map<String, String> parameters)
{
String title = parameters.get("title");
builder.endDefinitionList(title);
}
//
public void beginMacroMarker(String name, Map<String, String> macroParameters, String content, boolean isInline)
{
context.onValidationError("Not supported");
}
public void endMacroMarker(String name, Map<String, String> macroParameters, String content, boolean isInline)
{
context.onValidationError("Not supported");
}
public void beginQuotation(Map<String, String> parameters)
{
builder.beginQuotation();
}
public void endQuotation(Map<String, String> parameters)
{
builder.endQuotation();
}
public void beginQuotationLine()
{
}
public void endQuotationLine()
{
}
public void onId(String name)
{
context.onValidationError("Not supported");
}
public void onHorizontalLine(Map<String, String> parameters)
{
}
public void onEmptyLines(int count)
{
// Nothing to do really
}
public void onVerbatim(String protectedString, boolean isInline, Map<String, String> parameters)
{
builder.onVerbatim(protectedString);
}
public void onRawText(String rawContent, Syntax syntax)
{
context.onValidationError("Not supported");
}
public void onImage(ResourceReference image, boolean isFreeStandingURI, Map<String, String> parameters)
{
builder.onImage(image.getReference(), parameters);
}
}