001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.parsers.creole.visitor.impl;
016    
017    import com.liferay.portal.kernel.util.HtmlUtil;
018    import com.liferay.portal.kernel.util.StringBundler;
019    import com.liferay.portal.kernel.util.StringPool;
020    import com.liferay.portal.parsers.creole.ast.ASTNode;
021    import com.liferay.portal.parsers.creole.ast.BoldTextNode;
022    import com.liferay.portal.parsers.creole.ast.CollectionNode;
023    import com.liferay.portal.parsers.creole.ast.ForcedEndOfLineNode;
024    import com.liferay.portal.parsers.creole.ast.FormattedTextNode;
025    import com.liferay.portal.parsers.creole.ast.HeadingNode;
026    import com.liferay.portal.parsers.creole.ast.HorizontalNode;
027    import com.liferay.portal.parsers.creole.ast.ImageNode;
028    import com.liferay.portal.parsers.creole.ast.ItalicTextNode;
029    import com.liferay.portal.parsers.creole.ast.LineNode;
030    import com.liferay.portal.parsers.creole.ast.ListNode;
031    import com.liferay.portal.parsers.creole.ast.NoWikiSectionNode;
032    import com.liferay.portal.parsers.creole.ast.OrderedListItemNode;
033    import com.liferay.portal.parsers.creole.ast.OrderedListNode;
034    import com.liferay.portal.parsers.creole.ast.ParagraphNode;
035    import com.liferay.portal.parsers.creole.ast.ScapedNode;
036    import com.liferay.portal.parsers.creole.ast.UnformattedTextNode;
037    import com.liferay.portal.parsers.creole.ast.UnorderedListItemNode;
038    import com.liferay.portal.parsers.creole.ast.UnorderedListNode;
039    import com.liferay.portal.parsers.creole.ast.WikiPageNode;
040    import com.liferay.portal.parsers.creole.ast.extension.TableOfContentsNode;
041    import com.liferay.portal.parsers.creole.ast.link.LinkNode;
042    import com.liferay.portal.parsers.creole.ast.link.interwiki.C2InterwikiLinkNode;
043    import com.liferay.portal.parsers.creole.ast.link.interwiki.DokuWikiInterwikiLinkNode;
044    import com.liferay.portal.parsers.creole.ast.link.interwiki.FlickrInterwikiLinkNode;
045    import com.liferay.portal.parsers.creole.ast.link.interwiki.GoogleInterwikiLinkNode;
046    import com.liferay.portal.parsers.creole.ast.link.interwiki.InterwikiLinkNode;
047    import com.liferay.portal.parsers.creole.ast.link.interwiki.JSPWikiInterwikiLinkNode;
048    import com.liferay.portal.parsers.creole.ast.link.interwiki.MeatballInterwikiLinkNode;
049    import com.liferay.portal.parsers.creole.ast.link.interwiki.MediaWikiInterwikiLinkNode;
050    import com.liferay.portal.parsers.creole.ast.link.interwiki.MoinMoinInterwikiLinkNode;
051    import com.liferay.portal.parsers.creole.ast.link.interwiki.OddmuseInterwikiLinkNode;
052    import com.liferay.portal.parsers.creole.ast.link.interwiki.OhanaInterwikiLinkNode;
053    import com.liferay.portal.parsers.creole.ast.link.interwiki.PmWikiInterwikiLinkNode;
054    import com.liferay.portal.parsers.creole.ast.link.interwiki.PukiWikiInterwikiLinkNode;
055    import com.liferay.portal.parsers.creole.ast.link.interwiki.PurpleWikiInterwikiLinkNode;
056    import com.liferay.portal.parsers.creole.ast.link.interwiki.RadeoxInterwikiLinkNode;
057    import com.liferay.portal.parsers.creole.ast.link.interwiki.SnipSnapInterwikiLinkNode;
058    import com.liferay.portal.parsers.creole.ast.link.interwiki.TWikiInterwikiLinkNode;
059    import com.liferay.portal.parsers.creole.ast.link.interwiki.TiddlyWikiInterwikiLinkNode;
060    import com.liferay.portal.parsers.creole.ast.link.interwiki.UsemodInterwikiLinkNode;
061    import com.liferay.portal.parsers.creole.ast.link.interwiki.WikipediaInterwikiLinkNode;
062    import com.liferay.portal.parsers.creole.ast.link.interwiki.XWikiInterwikiLinkNode;
063    import com.liferay.portal.parsers.creole.ast.table.TableDataNode;
064    import com.liferay.portal.parsers.creole.ast.table.TableHeaderNode;
065    import com.liferay.portal.parsers.creole.ast.table.TableNode;
066    import com.liferay.portal.parsers.creole.visitor.ASTVisitor;
067    
068    import java.util.List;
069    import java.util.Stack;
070    
071    /**
072     * @author Miguel Pastor
073     */
074    public class XhtmlTranslationVisitor implements ASTVisitor {
075    
076            public String translate(WikiPageNode wikiPageNode) {
077                    _sb.setIndex(0);
078    
079                    visit(wikiPageNode);
080    
081                    return _sb.toString();
082            }
083    
084            @Override
085            public void visit(BoldTextNode boldTextNode) {
086                    append("<strong>");
087    
088                    if (boldTextNode.hasContent()) {
089                            traverse(boldTextNode.getChildASTNodes());
090                    }
091    
092                    append("</strong>");
093            }
094    
095            @Override
096            public void visit(C2InterwikiLinkNode c2InterwikiLinkNode) {
097                    appendInterwikiLinkNode(c2InterwikiLinkNode);
098            }
099    
100            @Override
101            public void visit(CollectionNode collectionNode) {
102                    for (ASTNode astNode : collectionNode.getASTNodes()) {
103                            astNode.accept(this);
104                    }
105            }
106    
107            @Override
108            public void visit(DokuWikiInterwikiLinkNode dokuWikiInterwikiLinkNode) {
109                    appendInterwikiLinkNode(dokuWikiInterwikiLinkNode);
110            }
111    
112            @Override
113            public void visit(FlickrInterwikiLinkNode flickrInterwikiLinkNode) {
114                    appendInterwikiLinkNode(flickrInterwikiLinkNode);
115            }
116    
117            @Override
118            public void visit(ForcedEndOfLineNode forcedEndOfLineNode) {
119                    append("<br/>");
120            }
121    
122            @Override
123            public void visit(FormattedTextNode formattedTextNode) {
124                    if (formattedTextNode.getContent() != null) {
125                            append(HtmlUtil.escape(formattedTextNode.getContent()));
126                    }
127                    else {
128                            traverse(formattedTextNode.getChildASTNodes());
129                    }
130            }
131    
132            @Override
133            public void visit(GoogleInterwikiLinkNode googleInterwikiLinkNode) {
134                    appendInterwikiLinkNode(googleInterwikiLinkNode);
135            }
136    
137            @Override
138            public void visit(HeadingNode headingNode) {
139                    int level = headingNode.getLevel();
140    
141                    append("<h");
142                    append(level);
143                    append(">");
144    
145                    traverse(headingNode.getChildASTNodes());
146    
147                    append("</h");
148                    append(level);
149                    append(">");
150            }
151    
152            @Override
153            public void visit(HorizontalNode horizontalNode) {
154                    append("<hr/>");
155            }
156    
157            @Override
158            public void visit(ImageNode imageNode) {
159                    append("<img src=\"");
160                    append(HtmlUtil.escape(imageNode.getLink()));
161                    append("\" ");
162    
163                    if (imageNode.hasAltCollectionNode()) {
164                            append("alt=\"");
165    
166                            CollectionNode altCollectionNode = imageNode.getAltNode();
167    
168                            traverse(altCollectionNode.getASTNodes());
169    
170                            append("\"");
171                    }
172    
173                    append("/>");
174            }
175    
176            @Override
177            public void visit(ItalicTextNode italicTextNode) {
178                    append("<em>");
179    
180                    if (italicTextNode.hasContent()) {
181                            traverse(italicTextNode.getChildASTNodes());
182                    }
183    
184                    append("</em>");
185            }
186    
187            @Override
188            public void visit(JSPWikiInterwikiLinkNode jspWikiInterwikiLinkNode) {
189                    appendInterwikiLinkNode(jspWikiInterwikiLinkNode);
190            }
191    
192            @Override
193            public void visit(LineNode lineNode) {
194                    traverse(lineNode.getChildASTNodes(), null, StringPool.SPACE);
195            }
196    
197            @Override
198            public void visit(LinkNode linkNode) {
199                    append("<a href=\"");
200                    append(HtmlUtil.escape(linkNode.getLink()));
201                    append("\">");
202    
203                    if (linkNode.hasAltCollectionNode()) {
204                            CollectionNode altCollectionNode = linkNode.getAltCollectionNode();
205    
206                            traverse(altCollectionNode.getASTNodes());
207                    }
208                    else {
209                            append(HtmlUtil.escape(linkNode.getLink()));
210                    }
211    
212                    append("</a>");
213            }
214    
215            @Override
216            public void visit(ListNode listNode) {
217                    traverse(listNode.getChildASTNodes());
218            }
219    
220            @Override
221            public void visit(MeatballInterwikiLinkNode meatballInterwikiLinkNode) {
222                    appendInterwikiLinkNode(meatballInterwikiLinkNode);
223            }
224    
225            @Override
226            public void visit(MediaWikiInterwikiLinkNode mediaWikiInterwikiLinkNode) {
227                    appendInterwikiLinkNode(mediaWikiInterwikiLinkNode);
228            }
229    
230            @Override
231            public void visit(MoinMoinInterwikiLinkNode moinMoinInterwikiLinkNode) {
232                    appendInterwikiLinkNode(moinMoinInterwikiLinkNode);
233            }
234    
235            @Override
236            public void visit(NoWikiSectionNode noWikiSectionNode) {
237                    append("<pre>");
238                    append(HtmlUtil.escape(noWikiSectionNode.getContent()));
239                    append("</pre>");
240            }
241    
242            @Override
243            public void visit(OddmuseInterwikiLinkNode oddmuseInterwikiLinkNode) {
244                    appendInterwikiLinkNode(oddmuseInterwikiLinkNode);
245            }
246    
247            @Override
248            public void visit(OhanaInterwikiLinkNode ohanaInterwikiLinkNode) {
249                    appendInterwikiLinkNode(ohanaInterwikiLinkNode);
250            }
251    
252            @Override
253            public void visit(OrderedListItemNode orderedListItemNode) {
254                    traverse(orderedListItemNode.getChildASTNodes(), "<li>", "</li>");
255            }
256    
257            @Override
258            public void visit(OrderedListNode orderedListNode) {
259                    append("<ol>");
260    
261                    traverse(orderedListNode.getChildASTNodes());
262    
263                    append("</ol>");
264            }
265    
266            @Override
267            public void visit(ParagraphNode paragraphNode) {
268                    traverse(paragraphNode.getChildASTNodes(), "<p>", "</p>");
269            }
270    
271            @Override
272            public void visit(PmWikiInterwikiLinkNode pmWikiInterwikiLinkNode) {
273                    appendInterwikiLinkNode(pmWikiInterwikiLinkNode);
274            }
275    
276            @Override
277            public void visit(PukiWikiInterwikiLinkNode pukiWikiInterwikiLinkNode) {
278                    appendInterwikiLinkNode(pukiWikiInterwikiLinkNode);
279            }
280    
281            @Override
282            public void visit(PurpleWikiInterwikiLinkNode purpleWikiInterwikiLinkNode) {
283                    appendInterwikiLinkNode(purpleWikiInterwikiLinkNode);
284            }
285    
286            @Override
287            public void visit(RadeoxInterwikiLinkNode radeoxInterwikiLinkNode) {
288                    appendInterwikiLinkNode(radeoxInterwikiLinkNode);
289            }
290    
291            @Override
292            public void visit(ScapedNode scapedNode) {
293                    append(HtmlUtil.escape(scapedNode.getContent()));
294            }
295    
296            @Override
297            public void visit(SnipSnapInterwikiLinkNode snipSnapInterwikiLinkNode) {
298                    appendInterwikiLinkNode(snipSnapInterwikiLinkNode);
299            }
300    
301            @Override
302            public void visit(TableDataNode tableDataNode) {
303                    traverse(tableDataNode.getChildASTNodes(), "<td>", "</td>");
304            }
305    
306            @Override
307            public void visit(TableHeaderNode tableHeaderNode) {
308                    traverse(tableHeaderNode.getChildASTNodes(), "<th>", "</th>");
309            }
310    
311            @Override
312            public void visit(TableNode tableNode) {
313                    append("<table>");
314    
315                    traverseAndWriteForEach(tableNode.getChildASTNodes(), "<tr>", "</tr>");
316    
317                    append("</table>");
318            }
319    
320            @Override
321            public void visit(TableOfContentsNode tableOfContentsNode) {
322            }
323    
324            @Override
325            public void visit(TiddlyWikiInterwikiLinkNode tiddlyWikiInterwikiLinkNode) {
326                    appendInterwikiLinkNode(tiddlyWikiInterwikiLinkNode);
327            }
328    
329            @Override
330            public void visit(TWikiInterwikiLinkNode tWikiInterwikiLinkNode) {
331                    appendInterwikiLinkNode(tWikiInterwikiLinkNode);
332            }
333    
334            @Override
335            public void visit(UnformattedTextNode unformattedTextNode) {
336                    if (unformattedTextNode.hasContent()) {
337                            append(HtmlUtil.escape(unformattedTextNode.getContent()));
338                    }
339                    else {
340                            traverse(unformattedTextNode.getChildASTNodes());
341                    }
342            }
343    
344            @Override
345            public void visit(UnorderedListItemNode unorderedListItemNode) {
346                    traverse(unorderedListItemNode.getChildASTNodes(), "<li>", "</li>");
347            }
348    
349            @Override
350            public void visit(UnorderedListNode unorderedListNode) {
351                    append("<ul>");
352    
353                    traverse(unorderedListNode.getChildASTNodes());
354    
355                    append("</ul>");
356            }
357    
358            @Override
359            public void visit(UsemodInterwikiLinkNode usemodInterwikiLinkNode) {
360                    appendInterwikiLinkNode(usemodInterwikiLinkNode);
361            }
362    
363            @Override
364            public void visit(WikiPageNode wikiPageNode) {
365                    traverse(wikiPageNode.getChildASTNodes());
366            }
367    
368            @Override
369            public void visit(WikipediaInterwikiLinkNode wikipediaInterwikiLinkNode) {
370                    appendInterwikiLinkNode(wikipediaInterwikiLinkNode);
371            }
372    
373            @Override
374            public void visit(XWikiInterwikiLinkNode xWikiInterwikiLinkNode) {
375                    appendInterwikiLinkNode(xWikiInterwikiLinkNode);
376            }
377    
378            protected void append(Object object) {
379                    if (object != null) {
380                            _sb.append(object);
381                    }
382            }
383    
384            protected void appendInterwikiLinkNode(
385                    InterwikiLinkNode interwikiLinkNode) {
386    
387                    append("<a href=\"");
388                    append(HtmlUtil.escape(interwikiLinkNode.getURL()));
389                    append("\">");
390                    append(HtmlUtil.escape(interwikiLinkNode.getTitle()));
391                    append("</a>");
392            }
393    
394            protected void appendLevelTags(int nodeLevel, boolean ordered) {
395                    int diff = nodeLevel - _currentNodeLevel.pop();
396    
397                    if (diff > 0) {
398                            for (int i = 0; i < diff; i++) {
399                                    if (ordered) {
400                                            append("<ol>");
401                                    }
402                                    else {
403                                            append("<ul>");
404                                    }
405                            }
406                    }
407                    else if (diff < 0) {
408                            for (int i = 0; i > diff; i--) {
409                                    if (ordered) {
410                                            append("</ol>");
411                                    }
412                                    else {
413                                            append("</ul>");
414                                    }
415                            }
416                    }
417    
418                    _currentNodeLevel.push(nodeLevel);
419            }
420    
421            protected void traverse(List<ASTNode> astNodes) {
422                    if (astNodes != null) {
423                            for (ASTNode astNode : astNodes) {
424                                    if (astNode != null) {
425                                            astNode.accept(this);
426                                    }
427                            }
428                    }
429            }
430    
431            protected void traverse(List<ASTNode> astNodes, String open, String close) {
432                    if ((astNodes == null) || astNodes.isEmpty()) {
433                            return;
434                    }
435    
436                    append(open);
437    
438                    traverse(astNodes);
439    
440                    append(close);
441            }
442    
443            protected void traverseAndWriteForEach(
444                    List<ASTNode> astNodes, String open, String close) {
445    
446                    for (ASTNode curNode : astNodes) {
447                            append(open);
448    
449                            if (curNode != null) {
450                                    curNode.accept(this);
451                            }
452    
453                            append(close);
454                    }
455            }
456    
457            private Stack<Integer> _currentNodeLevel = new Stack<Integer>();
458            private StringBundler _sb = new StringBundler();
459    
460    }