📄 xhtmlelementtowikitranslator.java
字号:
/* JSPWiki - a JSP-based WikiWiki clone. Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package com.ecyrd.jspwiki.htmltowiki;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.PrintWriter;import java.io.UnsupportedEncodingException;import java.net.URLDecoder;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedHashMap;import java.util.Map;import org.apache.commons.lang.StringEscapeUtils;import org.jdom.Element;import org.jdom.Attribute;import org.jdom.JDOMException;import org.jdom.Text;import org.jdom.xpath.XPath;/** * Converting XHtml to Wiki Markup. This is the class which does all of the heavy loading. * * @author Sebastian Baltes (sbaltes@gmx.com) */public class XHtmlElementToWikiTranslator{ private static final String UTF8 = "UTF-8"; private XHtmlToWikiConfig m_config; private WhitespaceTrimWriter m_outTimmer; private PrintWriter m_out; private LiStack m_liStack = new LiStack(); private PreStack m_preStack = new PreStack(); /** * Create a new translator using the default config. * * @param base The base element from which to start translating. * @throws IOException If reading of the DOM tree fails. * @throws JDOMException If the DOM tree is faulty. */ public XHtmlElementToWikiTranslator( Element base ) throws IOException, JDOMException { this( base, new XHtmlToWikiConfig() ); } /** * Create a new translator using the specified config. * * @param base The base element from which to start translating. * @param config The config to use. * @throws IOException If reading of the DOM tree fails. * @throws JDOMException If the DOM tree is faulty. */ public XHtmlElementToWikiTranslator( Element base, XHtmlToWikiConfig config ) throws IOException, JDOMException { this.m_config = config; m_outTimmer = new WhitespaceTrimWriter(); m_out = new PrintWriter( m_outTimmer ); print( base ); } /** * FIXME: I have no idea what this does... * * @return Something. */ public String getWikiString() { return m_outTimmer.toString(); } private void print( String s ) { s = StringEscapeUtils.unescapeHtml( s ); m_out.print( s ); } private void print( Object element ) throws IOException, JDOMException { if( element instanceof Text ) { Text t = (Text)element; String s = t.getText(); if( m_preStack.isPreMode() ) { m_out.print( s ); } else { // remove all "line terminator" characters s = s.replaceAll( "[\\r\\n\\f\\u0085\\u2028\\u2029]", "" ); m_out.print( s ); } } else if( element instanceof Element ) { Element base = (Element)element; String n = base.getName().toLowerCase(); if( "imageplugin".equals( base.getAttributeValue( "class" ) ) ) { printImage( base ); } else if( "wikiform".equals( base.getAttributeValue( "class" ) ) ) { // only print the children if the div's class="wikiform", but not the div itself. printChildren( base ); } else { boolean bold = false; boolean italic = false; boolean monospace = false; String cssSpecial = null; String cssClass = base.getAttributeValue( "class" ); // accomodate a FCKeditor bug with Firefox: when a link is removed, it becomes <span class="wikipage">text</span>. boolean ignoredCssClass = cssClass != null && cssClass.matches( "wikipage|createpage|external|interwiki|attachment" ); Map styleProps = null; // Only get the styles if it's not a link element. Styles for link elements are // handled as an AugmentedWikiLink instead. if( !n.equals( "a" ) ) { styleProps = getStylePropertiesLowerCase( base ); } if( styleProps != null ) { String fontFamily = (String)styleProps.get( "font-family" ); String whiteSpace = (String)styleProps.get( "white-space" ); if( fontFamily != null && ( fontFamily.indexOf( "monospace" ) >= 0 && whiteSpace != null && whiteSpace.indexOf( "pre" ) >= 0 ) ) { styleProps.remove( "font-family" ); styleProps.remove( "white-space" ); monospace = true; } String weight = (String)styleProps.remove( "font-weight" ); String style = (String)styleProps.remove( "font-style" ); if( n.equals( "p" ) ) { // change it so we can print out the css styles for <p> n = "div"; } italic = "oblique".equals( style ) || "italic".equals( style ); bold = "bold".equals( weight ) || "bolder".equals( weight ); if( !styleProps.isEmpty() ) { cssSpecial = propsToStyleString( styleProps ); } } if( cssClass != null && !ignoredCssClass ) { if( n.equals( "div" ) ) { m_out.print( "\n%%" + cssClass + " \n" ); } else if( n.equals( "span" ) ) { m_out.print( "%%" + cssClass + " " ); } } if( bold ) { m_out.print( "__" ); } if( italic ) { m_out.print( "''" ); } if( monospace ) { m_out.print( "{{{" ); m_preStack.push(); } if( cssSpecial != null ) { if( n.equals( "div" ) ) { m_out.print( "\n%%(" + cssSpecial + " )\n" ); } else { m_out.print( "%%(" + cssSpecial + " )" ); } } printChildren( base ); if( cssSpecial != null ) { if( n.equals( "div" ) ) { m_out.print( "\n%%\n" ); } else { m_out.print( "%%" ); } } if( monospace ) { m_preStack.pop(); m_out.print( "}}}" ); } if( italic ) { m_out.print( "''" ); } if( bold ) { m_out.print( "__" ); } if( cssClass != null && !ignoredCssClass ) { if( n.equals( "div" ) ) { m_out.print( "\n%%\n" ); } else if( n.equals( "span" ) ) { m_out.print( "%%" ); } } } } } private void printChildren( Element base ) throws IOException, JDOMException { for( Iterator i = base.getContent().iterator(); i.hasNext(); ) { Object c = i.next(); if( c instanceof Element ) { Element e = (Element)c; String n = e.getName().toLowerCase(); if( n.equals( "h1" ) ) { m_out.print( "\n!!! " ); print( e ); m_out.println(); } else if( n.equals( "h2" ) ) { m_out.print( "\n!!! " ); print( e ); m_out.println(); } else if( n.equals( "h3" ) ) { m_out.print( "\n!! " ); print( e ); m_out.println(); } else if( n.equals( "h4" ) ) { m_out.print( "\n! " ); print( e ); m_out.println(); } else if( n.equals( "p" ) ) { if( e.getContentSize() != 0 ) // we don't want to print empty elements: <p></p> { m_out.println(); print( e ); m_out.println(); } } else if( n.equals( "br" ) ) { if( m_preStack.isPreMode() ) { m_out.println(); } else { String parentElementName = base.getName().toLowerCase(); // // To beautify the generated wiki markup, we print a newline character after a linebreak. // It's only safe to do this when the parent element is a <p> or <div>; when the parent // element is a table cell or list item, a newline character would break the markup. // We also check that this isn't being done inside a plugin body. // if( parentElementName.matches( "p|div" ) && !base.getText().matches( "(?s).*\\[\\{.*\\}\\].*" ) ) { m_out.print( " \\\\\n" ); } else { m_out.print( " \\\\" ); } } print( e ); } else if( n.equals( "hr" ) ) { m_out.println(); print( "----" ); print( e ); m_out.println(); } else if( n.equals( "table" ) ) { if( !m_outTimmer.isCurrentlyOnLineBegin() ) { m_out.println(); } print( e ); } else if( n.equals( "tr" ) ) { print( e ); m_out.println(); } else if( n.equals( "td" ) ) { m_out.print( "| " ); print( e ); if( !m_preStack.isPreMode() ) { print( " " ); } } else if( n.equals( "th" ) ) { m_out.print( "|| " ); print( e );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -