Package org.jamwiki.parser.jflex

Source Code of org.jamwiki.parser.jflex.TemplateTag

/**
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, version 2.1, dated February 1999.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the latest version of the GNU Lesser General
* Public License as published by the Free Software Foundation;
*
* 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program (LICENSE.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package org.jamwiki.parser.jflex;

import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils;
import org.jamwiki.WikiBase;
import org.jamwiki.model.Topic;
import org.jamwiki.parser.ParserException;
import org.jamwiki.parser.ParserInput;
import org.jamwiki.parser.ParserOutput;
import org.jamwiki.utils.NamespaceHandler;
import org.jamwiki.utils.Utilities;
import org.jamwiki.utils.WikiLogger;
import org.jamwiki.utils.WikiUtil;

/**
* <code>TemplateTag</code> parses Mediawiki template syntax, which allows
* programmatic structures to be embedded in wiki syntax.
*/
public class TemplateTag implements JFlexParserTag {

  private static final WikiLogger logger = WikiLogger
      .getLogger(TemplateTag.class.getName());
  protected static final String TEMPLATE_INCLUSION = "template-inclusion";
  private static Pattern PARAM_NAME_VALUE_PATTERN = Pattern
      .compile("[\\s]*([A-Za-z0-9_\\ \\-]+)[\\s]*\\=([\\s\\S]*)");

  private final HashMap<String, String> parameterValues = new HashMap<String, String>();

  /**
   * Once the template call has been parsed and the template values have been
   * determined, parse the template body and apply those template values.
   * Parameters may be embedded or have default values, so there is some voodoo
   * magic that happens here to first parse any embedded values, and to apply
   * default values when no template value has been set.
   */
  private String applyParameter(ParserInput parserInput, String param)
      throws ParserException {
    if (this.parameterValues == null) {
      return param;
    }
    String content = param.substring("{{{".length(), param.length()
        - "}}}".length());
    // re-parse in case of embedded templates or params
    content = this.parseTemplateBody(parserInput, content);
    String name = this.parseParamName(content);
    String defaultValue = this.parseParamDefaultValue(parserInput, content);
    String value = this.parameterValues.get(name);
    if (value == null && defaultValue == null) {
      return param;
    }
    return (value == null) ? defaultValue : value;
  }

  /**
   * Parse a call to a Mediawiki template of the form
   * "{{template|param1|param2}}" and return the resulting template output.
   */
  public String parse(JFlexLexer lexer, String raw, Object... args) {
    try {
      lexer.getParserInput().incrementTemplateDepth();
      // validate and extract the template content
      if (StringUtils.isBlank(raw)) {
        throw new Exception("Empty template text");
      }
      if (!raw.startsWith("{{") || !raw.endsWith("}}")) {
        throw new Exception("Invalid template text: " + raw);
      }
      String templateContent = raw.substring("{{".length(), raw.length()
          - "}}".length());
      // parse for nested templates, signatures, etc.
      templateContent = JFlexParserUtil.parseFragment(lexer.getParserInput(),
          templateContent, lexer.getMode());
      // update the raw value to handle cases such as a signature in the
      // template content
      raw = "{{" + templateContent + "}}";
      // check for magic word or parser function
      String[] parserFunctionInfo = ParserFunctionUtil
          .parseParserFunctionInfo(templateContent);
      if (MagicWordUtil.isMagicWord(templateContent)
          || parserFunctionInfo != null) {
        if (lexer.getMode() <= JFlexParser.MODE_MINIMAL) {
          lexer.getParserInput().decrementTemplateDepth();
          return raw;
        }
        lexer.getParserInput().decrementTemplateDepth();
        if (MagicWordUtil.isMagicWord(templateContent)) {
          return MagicWordUtil.processMagicWord(lexer.getParserInput(),
              templateContent);
        } else {
          return ParserFunctionUtil.processParserFunction(lexer
              .getParserInput(), parserFunctionInfo[0], parserFunctionInfo[1]);
        }
      }
      // extract the template name
      String name = this.parseTemplateName(templateContent);
      boolean inclusion = false;
      if (name.startsWith(NamespaceHandler.NAMESPACE_SEPARATOR)) {
        name = name.substring(1);
        inclusion = true;
      }
      // get the parsed template body
      Topic templateTopic = WikiBase.getDataHandler().lookupTopic(
          lexer.getParserInput().getVirtualWiki(), name, false, null);
      this.processTemplateMetadata(lexer.getParserInput(), lexer
          .getParserOutput(), templateTopic, raw, name);
      if (lexer.getMode() <= JFlexParser.MODE_MINIMAL) {
        lexer.getParserInput().decrementTemplateDepth();
        return raw;
      }
      // make sure template was not redirected
      // if (templateTopic != null && templateTopic.getTopicType() ==
      // Topic.TYPE_REDIRECT) {
      // templateTopic = WikiUtil.findRedirectedTopic(templateTopic, 0);
      // name = templateTopic.getName();
      // }
      // if (templateTopic != null && templateTopic.getTopicType() ==
      // Topic.TYPE_REDIRECT) {
      // // redirection target does not exist
      // templateTopic = null;
      // }
      if (inclusion) {
        String output = this.processTemplateInclusion(lexer.getParserInput(),
            lexer.getParserOutput(), lexer.getMode(), templateTopic, raw, name);
        lexer.getParserInput().decrementTemplateDepth();
        return output;
      }
      String output = this.processTemplateContent(lexer.getParserInput(), lexer
          .getParserOutput(), templateTopic, templateContent, name);
      lexer.getParserInput().decrementTemplateDepth();
      return output;
    } catch (Throwable t) {
      logger.info("Unable to parse " + raw, t);
      return raw;
    }
  }

  /**
   * Given template parameter content of the form "name" or "name|default",
   * return the default value if it exists.
   */
  private String parseParamDefaultValue(ParserInput parserInput, String raw)
      throws ParserException {
    List<String> tokens = JFlexParserUtil.tokenizeParamString(raw);
    if (tokens.size() < 2) {
      return null;
    }
    // table elements mess up default processing, so just return anything after
    // the first parameter to avoid having to implement special table logic
    String param1 = tokens.get(0);
    String value = raw.substring(param1.length() + 1);
    return JFlexParserUtil.parseFragment(parserInput, value,
        JFlexParser.MODE_PREPROCESS);
  }

  /**
   * Given template parameter content of the form "name" or "name|default",
   * return the parameter name.
   */
  private String parseParamName(String raw) throws ParserException {
    int pos = raw.indexOf('|');
    String name = ((pos != -1) ? raw.substring(0, pos) : raw).trim();
    if (StringUtils.isBlank(name)) {
      // FIXME - no need for an exception
      throw new ParserException("No parameter name specified");
    }
    return name;
  }

  /**
   * After template parameter values have been set, process the template body
   * and replace parameters with parameter values or defaults, processing any
   * embedded parameters or templates.
   */
  private String parseTemplateBody(ParserInput parserInput, String content)
      throws ParserException {
    StringBuilder output = new StringBuilder();
    int pos = 0;
    while (pos < content.length()) {
      String substring = content.substring(pos);
      if (substring.startsWith("{{{")) {
        // template
        int endPos = Utilities.findMatchingEndTag(content, pos, "{{{", "}}}");
        if (endPos != -1) {
          String param = content.substring(pos, endPos);
          output.append(this.applyParameter(parserInput, param));
        }
        pos = endPos;
      } else {
        output.append(content.charAt(pos));
        pos++;
      }
    }
    return JFlexParserUtil.parseFragment(parserInput, output.toString(),
        JFlexParser.MODE_PREPROCESS);
  }

  /**
   * Given a template call of the form "{{template|param|param}}", return the
   * template name.
   */
  private String parseTemplateName(String raw) throws ParserException {
    String name = raw;
    int pos = raw.indexOf('|');
    if (pos != -1) {
      name = name.substring(0, pos);
    }
    name = Utilities.decodeTopicName(name.trim(), true);
    if (StringUtils.isBlank(name)) {
      // FIXME - no need for an exception
      throw new ParserException("No template name specified");
    }
    if (name.startsWith(NamespaceHandler.NAMESPACE_SEPARATOR)) {
      if (name.length() == 1) {
        // FIXME - no need for an exception
        throw new ParserException("No template name specified");
      }
    } else if (!name.startsWith(NamespaceHandler.NAMESPACE_TEMPLATE
        + NamespaceHandler.NAMESPACE_SEPARATOR)) {
      name = NamespaceHandler.NAMESPACE_TEMPLATE
          + NamespaceHandler.NAMESPACE_SEPARATOR + StringUtils.capitalize(name);
    }
    return name;
  }

  /**
   * Given a template call of the form "{{name|param=value|param=value}}" parse
   * the parameter names and values.
   */
  private void parseTemplateParameterValues(ParserInput parserInput,
      String templateContent) throws ParserException {
    List<String> tokens = JFlexParserUtil.tokenizeParamString(templateContent);
    if (tokens.isEmpty()) {
      throw new ParserException("No template name found in " + templateContent);
    }
    int count = -1;
    for (String token : tokens) {
      count++;
      if (count == 0) {
        // first token is template name
        continue;
      }
      String[] nameValue = this.tokenizeNameValue(token);
      String name = (StringUtils.isBlank(nameValue[0]) ? Integer
          .toString(count) : nameValue[0].trim());
      String value = (nameValue[1] == null) ? null : nameValue[1].trim();
      this.parameterValues.put(name, value);
    }
  }

  /**
   * Given a template call of the form "{{name|param|param}}" return the parsed
   * output.
   */
  private String processTemplateContent(ParserInput parserInput,
      ParserOutput parserOutput, Topic templateTopic, String templateContent,
      String name) throws ParserException {
    if (templateTopic == null) {
      return "[[" + name + "]]";
    }
    // set template parameter values
    this.parseTemplateParameterValues(parserInput, templateContent);
    return this.parseTemplateBody(parserInput, templateTopic.getTopicContent());
  }

  /**
   * Given a template call of the form "{{:name}}" parse the template inclusion.
   */
  private String processTemplateInclusion(ParserInput parserInput,
      ParserOutput parserOutput, int mode, Topic templateTopic, String raw,
      String name) throws ParserException {
    if (templateTopic == null) {
      return "[[" + name + "]]";
    }
    // FIXME - disable section editing
    parserInput.getTempParams().put(TEMPLATE_INCLUSION, "true");
    return (StringUtils.isBlank(templateTopic.getTopicContent())) ? templateTopic
        .getTopicContent()
        : JFlexParserUtil.parseFragment(parserInput, templateTopic
            .getTopicContent(), mode);
  }

  /**
   * Process template values, setting link and other metadata output values.
   */
  private void processTemplateMetadata(ParserInput parserInput,
      ParserOutput parserOutput, Topic templateTopic, String raw, String name) {
    name = (templateTopic != null) ? templateTopic.getName() : name;
    parserOutput.addLink(name);
    parserOutput.addTemplate(name);
  }

  /**
   *
   */
  private String[] tokenizeNameValue(String content) {
    String[] results = new String[2];
    results[0] = null;
    results[1] = content;
    Matcher m = PARAM_NAME_VALUE_PATTERN.matcher(content);
    if (m.matches()) {
      results[0] = m.group(1);
      results[1] = m.group(2);
    }
    return results;
  }
}
TOP

Related Classes of org.jamwiki.parser.jflex.TemplateTag

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.