/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library 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 library 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. */ package com.liferay.wiki.engine.creole.internal.parser.visitor; import com.liferay.portal.kernel.util.HtmlUtil; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.wiki.engine.creole.internal.parser.ast.ASTNode; import com.liferay.wiki.engine.creole.internal.parser.ast.BoldTextNode; import com.liferay.wiki.engine.creole.internal.parser.ast.CollectionNode; import com.liferay.wiki.engine.creole.internal.parser.ast.ForcedEndOfLineNode; import com.liferay.wiki.engine.creole.internal.parser.ast.FormattedTextNode; import com.liferay.wiki.engine.creole.internal.parser.ast.HeadingNode; import com.liferay.wiki.engine.creole.internal.parser.ast.HorizontalNode; import com.liferay.wiki.engine.creole.internal.parser.ast.ImageNode; import com.liferay.wiki.engine.creole.internal.parser.ast.ItalicTextNode; import com.liferay.wiki.engine.creole.internal.parser.ast.LineNode; import com.liferay.wiki.engine.creole.internal.parser.ast.ListNode; import com.liferay.wiki.engine.creole.internal.parser.ast.NoWikiInlineNode; import com.liferay.wiki.engine.creole.internal.parser.ast.NoWikiSectionNode; import com.liferay.wiki.engine.creole.internal.parser.ast.OrderedListItemNode; import com.liferay.wiki.engine.creole.internal.parser.ast.OrderedListNode; import com.liferay.wiki.engine.creole.internal.parser.ast.ParagraphNode; import com.liferay.wiki.engine.creole.internal.parser.ast.ScapedNode; import com.liferay.wiki.engine.creole.internal.parser.ast.UnformattedTextNode; import com.liferay.wiki.engine.creole.internal.parser.ast.UnorderedListItemNode; import com.liferay.wiki.engine.creole.internal.parser.ast.UnorderedListNode; import com.liferay.wiki.engine.creole.internal.parser.ast.WikiPageNode; import com.liferay.wiki.engine.creole.internal.parser.ast.extension.TableOfContentsNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.LinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.C2InterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.DokuWikiInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.FlickrInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.GoogleInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.InterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.JSPWikiInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.MeatballInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.MediaWikiInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.MoinMoinInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.OddmuseInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.OhanaInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.PmWikiInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.PukiWikiInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.PurpleWikiInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.RadeoxInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.SnipSnapInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.TWikiInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.TiddlyWikiInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.UsemodInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.WikipediaInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.link.interwiki.XWikiInterwikiLinkNode; import com.liferay.wiki.engine.creole.internal.parser.ast.table.TableDataNode; import com.liferay.wiki.engine.creole.internal.parser.ast.table.TableHeaderNode; import com.liferay.wiki.engine.creole.internal.parser.ast.table.TableNode; import java.util.List; import java.util.Stack; /** * @author Miguel Pastor */ public class XhtmlTranslationVisitor implements ASTVisitor { public String translate(WikiPageNode wikiPageNode) { _sb.setIndex(0); visit(wikiPageNode); return _sb.toString(); } @Override public void visit(BoldTextNode boldTextNode) { append("<strong>"); if (boldTextNode.hasContent()) { traverse(boldTextNode.getChildASTNodes()); } append("</strong>"); } @Override public void visit(C2InterwikiLinkNode c2InterwikiLinkNode) { appendInterwikiLinkNode(c2InterwikiLinkNode); } @Override public void visit(CollectionNode collectionNode) { for (ASTNode astNode : collectionNode.getASTNodes()) { astNode.accept(this); } } @Override public void visit(DokuWikiInterwikiLinkNode dokuWikiInterwikiLinkNode) { appendInterwikiLinkNode(dokuWikiInterwikiLinkNode); } @Override public void visit(FlickrInterwikiLinkNode flickrInterwikiLinkNode) { appendInterwikiLinkNode(flickrInterwikiLinkNode); } @Override public void visit(ForcedEndOfLineNode forcedEndOfLineNode) { append("<br/>"); } @Override public void visit(FormattedTextNode formattedTextNode) { if (formattedTextNode.getContent() != null) { append(HtmlUtil.escape(formattedTextNode.getContent())); } else { traverse(formattedTextNode.getChildASTNodes()); } } @Override public void visit(GoogleInterwikiLinkNode googleInterwikiLinkNode) { appendInterwikiLinkNode(googleInterwikiLinkNode); } @Override public void visit(HeadingNode headingNode) { int level = headingNode.getLevel(); append("<h"); append(level); append(">"); traverse(headingNode.getChildASTNodes()); append("</h"); append(level); append(">"); } @Override public void visit(HorizontalNode horizontalNode) { append("<hr/>"); } @Override public void visit(ImageNode imageNode) { append("<img src=\""); append(HtmlUtil.escape(imageNode.getLink())); append("\" "); if (imageNode.hasAltCollectionNode()) { append("alt=\""); CollectionNode altCollectionNode = imageNode.getAltNode(); traverse(altCollectionNode.getASTNodes()); append("\""); } append("/>"); } @Override public void visit(ItalicTextNode italicTextNode) { append("<em>"); if (italicTextNode.hasContent()) { traverse(italicTextNode.getChildASTNodes()); } append("</em>"); } @Override public void visit(JSPWikiInterwikiLinkNode jspWikiInterwikiLinkNode) { appendInterwikiLinkNode(jspWikiInterwikiLinkNode); } @Override public void visit(LineNode lineNode) { traverse(lineNode.getChildASTNodes(), null, StringPool.SPACE); } @Override public void visit(LinkNode linkNode) { append("<a href=\""); append(HtmlUtil.escape(linkNode.getLink())); append("\">"); if (linkNode.hasAltCollectionNode()) { CollectionNode altCollectionNode = linkNode.getAltCollectionNode(); traverse(altCollectionNode.getASTNodes()); } else { append(HtmlUtil.escape(linkNode.getLink())); } append("</a>"); } @Override public void visit(ListNode listNode) { traverse(listNode.getChildASTNodes()); } @Override public void visit(MeatballInterwikiLinkNode meatballInterwikiLinkNode) { appendInterwikiLinkNode(meatballInterwikiLinkNode); } @Override public void visit(MediaWikiInterwikiLinkNode mediaWikiInterwikiLinkNode) { appendInterwikiLinkNode(mediaWikiInterwikiLinkNode); } @Override public void visit(MoinMoinInterwikiLinkNode moinMoinInterwikiLinkNode) { appendInterwikiLinkNode(moinMoinInterwikiLinkNode); } @Override public void visit(NoWikiInlineNode noWikiInlineNode) { append("<tt>"); append(HtmlUtil.escape(noWikiInlineNode.getContent())); append("</tt>"); } @Override public void visit(NoWikiSectionNode noWikiSectionNode) { append("<pre>"); append(HtmlUtil.escape(noWikiSectionNode.getContent())); append("</pre>"); } @Override public void visit(OddmuseInterwikiLinkNode oddmuseInterwikiLinkNode) { appendInterwikiLinkNode(oddmuseInterwikiLinkNode); } @Override public void visit(OhanaInterwikiLinkNode ohanaInterwikiLinkNode) { appendInterwikiLinkNode(ohanaInterwikiLinkNode); } @Override public void visit(OrderedListItemNode orderedListItemNode) { traverse(orderedListItemNode.getChildASTNodes(), "<li>", "</li>"); } @Override public void visit(OrderedListNode orderedListNode) { append("<ol>"); traverse(orderedListNode.getChildASTNodes()); append("</ol>"); } @Override public void visit(ParagraphNode paragraphNode) { traverse(paragraphNode.getChildASTNodes(), "<p>", "</p>"); } @Override public void visit(PmWikiInterwikiLinkNode pmWikiInterwikiLinkNode) { appendInterwikiLinkNode(pmWikiInterwikiLinkNode); } @Override public void visit(PukiWikiInterwikiLinkNode pukiWikiInterwikiLinkNode) { appendInterwikiLinkNode(pukiWikiInterwikiLinkNode); } @Override public void visit(PurpleWikiInterwikiLinkNode purpleWikiInterwikiLinkNode) { appendInterwikiLinkNode(purpleWikiInterwikiLinkNode); } @Override public void visit(RadeoxInterwikiLinkNode radeoxInterwikiLinkNode) { appendInterwikiLinkNode(radeoxInterwikiLinkNode); } @Override public void visit(ScapedNode scapedNode) { append(HtmlUtil.escape(scapedNode.getContent())); } @Override public void visit(SnipSnapInterwikiLinkNode snipSnapInterwikiLinkNode) { appendInterwikiLinkNode(snipSnapInterwikiLinkNode); } @Override public void visit(TableDataNode tableDataNode) { traverse(tableDataNode.getChildASTNodes(), "<td>", "</td>"); } @Override public void visit(TableHeaderNode tableHeaderNode) { traverse(tableHeaderNode.getChildASTNodes(), "<th>", "</th>"); } @Override public void visit(TableNode tableNode) { append("<table>"); traverseAndWriteForEach(tableNode.getChildASTNodes(), "<tr>", "</tr>"); append("</table>"); } @Override public void visit(TableOfContentsNode tableOfContentsNode) { } @Override public void visit(TiddlyWikiInterwikiLinkNode tiddlyWikiInterwikiLinkNode) { appendInterwikiLinkNode(tiddlyWikiInterwikiLinkNode); } @Override public void visit(TWikiInterwikiLinkNode tWikiInterwikiLinkNode) { appendInterwikiLinkNode(tWikiInterwikiLinkNode); } @Override public void visit(UnformattedTextNode unformattedTextNode) { if (unformattedTextNode.hasContent()) { append(HtmlUtil.escape(unformattedTextNode.getContent())); } else { traverse(unformattedTextNode.getChildASTNodes()); } } @Override public void visit(UnorderedListItemNode unorderedListItemNode) { traverse(unorderedListItemNode.getChildASTNodes(), "<li>", "</li>"); } @Override public void visit(UnorderedListNode unorderedListNode) { append("<ul>"); traverse(unorderedListNode.getChildASTNodes()); append("</ul>"); } @Override public void visit(UsemodInterwikiLinkNode usemodInterwikiLinkNode) { appendInterwikiLinkNode(usemodInterwikiLinkNode); } @Override public void visit(WikiPageNode wikiPageNode) { traverse(wikiPageNode.getChildASTNodes()); } @Override public void visit(WikipediaInterwikiLinkNode wikipediaInterwikiLinkNode) { appendInterwikiLinkNode(wikipediaInterwikiLinkNode); } @Override public void visit(XWikiInterwikiLinkNode xWikiInterwikiLinkNode) { appendInterwikiLinkNode(xWikiInterwikiLinkNode); } protected void append(Object object) { if (object != null) { _sb.append(object); } } protected void appendInterwikiLinkNode( InterwikiLinkNode interwikiLinkNode) { append("<a href=\""); append(HtmlUtil.escape(interwikiLinkNode.getURL())); append("\">"); append(HtmlUtil.escape(interwikiLinkNode.getTitle())); append("</a>"); } protected void appendLevelTags(int nodeLevel, boolean ordered) { int diff = nodeLevel - _currentNodeLevel.pop(); if (diff > 0) { for (int i = 0; i < diff; i++) { if (ordered) { append("<ol>"); } else { append("<ul>"); } } } else if (diff < 0) { for (int i = 0; i > diff; i--) { if (ordered) { append("</ol>"); } else { append("</ul>"); } } } _currentNodeLevel.push(nodeLevel); } protected void traverse(List<ASTNode> astNodes) { if (astNodes != null) { for (ASTNode astNode : astNodes) { if (astNode != null) { astNode.accept(this); } } } } protected void traverse(List<ASTNode> astNodes, String open, String close) { if ((astNodes == null) || astNodes.isEmpty()) { return; } append(open); traverse(astNodes); append(close); } protected void traverseAndWriteForEach( List<ASTNode> astNodes, String open, String close) { for (ASTNode curNode : astNodes) { append(open); if (curNode != null) { curNode.accept(this); } append(close); } } private final Stack<Integer> _currentNodeLevel = new Stack<>(); private final StringBundler _sb = new StringBundler(); }