Package net.sourceforge.chaperon.ant

Source Code of net.sourceforge.chaperon.ant.ChaperonFragmentParse

/*
*  Copyright (C) Chaperon. All rights reserved.                              
*  -------------------------------------------------------------------------
*  This software is published under the terms of the Apache Software License
*  version 1.1, a copy of which has been included  with this distribution in
*  the LICENSE file.                                                        
*/
package net.sourceforge.chaperon.ant;

import java.io.*;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.apache.xml.serialize.Method;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;
import net.sourceforge.chaperon.parser.output.EventQueue;
import net.sourceforge.chaperon.parser.output.SAXEventAdapter;
import net.sourceforge.chaperon.parser.ParserException;
import net.sourceforge.chaperon.parser.Parser;
import net.sourceforge.chaperon.parser.ParserTable;

/**
* A ant task for parsing fragment in a xml file
*
* @author Stephan Michels
* @version %version%
*/
public class ChaperonFragmentParse extends MatchingTask
{
  private File destDir = null;

  private File baseDir = null;

  private String parsertableFilename = null;

  private String targetExtension = ".xml";
  private Vector params = new Vector();

  private File inFile = null;

  private File outFile = null;

  private String encoding = null;
  private boolean ignorableTokens = false;
  private boolean indent = false;

  private FileUtils fileUtils;

  private int msgLevel = Project.MSG_ERR;
  private AntLogger logger;

  private Parser parser;
  private SAXEventAdapter adapter;

  /**
   * Constructs the task
   */
  public ChaperonFragmentParse()
  {
    fileUtils = FileUtils.newFileUtils();
  }

  /**
   * Executes the task
   *
   * @throws BuildException
   */
  public void execute() throws BuildException
  {
    logger = new AntLogger(this, msgLevel);
    parser = new Parser();
    parser.enableLogging(logger)

    DirectoryScanner scanner;
    String[] list;
    String[] dirs;

    if (parsertableFilename == null)
      throw new BuildException("no parsertable specified", location);

    if (baseDir == null)
      baseDir = project.resolveFile(".");

    File parsertableFile = project.resolveFile(parsertableFilename);

    if (!parsertableFile.exists())
    {
      parsertableFile = fileUtils.resolveFile(baseDir, parsertableFilename);
      if (parsertableFile.exists())
      {
        log("DEPRECATED - the parsertable attribute should be relative to the project\'s");
        log("             basedir, not the tasks\'s basedir.");
      }
    }

    if ((inFile != null) && (outFile != null))
    {
      process(inFile, outFile, parsertableFile);
      return;
    }

    if (destDir == null)
    {
      String msg = "destdir attributes must be set!";

      throw new BuildException(msg);
    }
    scanner = getDirectoryScanner(baseDir);
    log("Transforming into " + destDir, Project.MSG_INFO);

    list = scanner.getIncludedFiles();
    for (int i = 0; i < list.length; ++i)
      process(baseDir, list[i], destDir, parsertableFile);

    dirs = scanner.getIncludedDirectories();
    for (int j = 0; j < dirs.length; ++j)
    {
      list = new File(baseDir, dirs[j]).list();
      for (int i = 0; i < list.length; ++i)
        process(baseDir, list[i], destDir, parsertableFile);
    }
  }

  /**
   * Set the base directory.
   *
   * @param dir Base directory
   */
  public void setBasedir(File dir)
  {
    baseDir = dir;
  }

  /**
   * Set the destination directory into which the result
   * files should be copied to
   *
   * @param dir Destination directory
   */
  public void setDestdir(File dir)
  {
    destDir = dir;
  }

  /**
   * Set the desired file extension to be used for the target
   *
   * @param name The extension to use
   */
  public void setExtension(String name)
  {
    targetExtension = name;
  }

  /**
   * Sets the parsertable to use for parsing relative to the base directory
   * of this task.
   *
   * @param parsertableFilename File name of the parser table
   */
  public void setParserTable(String parsertableFilename)
  {
    this.parsertableFilename = parsertableFilename;
  }

  /**
   * Sets an output file
   *
   * @param outFile The output file   
   */
  public void setOut(File outFile)
  {
    this.outFile = outFile;
  }

  /**
   * Sets an input xml file to be parsed
   *
   * @param inFile The input file
   */
  public void setIn(File inFile)
  {
    this.inFile = inFile;
  }

  /**
   * Sets the message level
   *
   * @param inFile The grammar file
   */
  public void setMsglevel(String msgLevel)
  {
    if (msgLevel.equalsIgnoreCase("debug"))
      this.msgLevel = Project.MSG_DEBUG;
    else if (msgLevel.equalsIgnoreCase("verbose"))
      this.msgLevel = Project.MSG_VERBOSE;
    else if (msgLevel.equalsIgnoreCase("info"))
      this.msgLevel = Project.MSG_INFO;
    else if (msgLevel.equalsIgnoreCase("warn"))
      this.msgLevel = Project.MSG_WARN;
    else if (msgLevel.equalsIgnoreCase("error"))
      this.msgLevel = Project.MSG_ERR;
  }

  /**
   * Sets the encoding for the input file
   *
   * @param encoding Encoding of the document
   */
  public void setEncoding(String encoding)
  {
    this.encoding = encoding;
  }

  /**
   * Set if the output document should include
   * the ignorable tokens
   *
   * @param ignorableTokens If the output document should include
   *                        the ignorable tokens
   */
  public void setIgnorabletokens(boolean ignorableTokens)
  {
    this.ignorableTokens = ignorableTokens;
  }

  /**
   * Set if the output document should be indented
   *
   * @param ignorableTokens If the output document should be indented
   *                        the ignorable tokens
   */
  public void setIndent(boolean indent)
  {
    this.indent = indent;
  }

  /**
   * Processes the given input XML file and stores the result
   * in the given resultFile.
   *
   * @param baseDir Base directory
   * @param xmlFile File, which should parsed
   * @param destDir Destination directory
   * @param parsertableFile Parser table file
   *
   * @throws BuildException
   */
  private void process(File baseDir, String xmlFile, File destDir,
                       File parsertableFile) throws BuildException
  {
    String fileExt = targetExtension;
    File outFile = null;
    File inFile = null;

    try
    {
      long parsertableLastModified = parsertableFile.lastModified();

      inFile = new File(baseDir, xmlFile);
      int dotPos = xmlFile.lastIndexOf('.');

      if (dotPos > 0)
        outFile = new File(destDir,
                           xmlFile.substring(0, xmlFile.lastIndexOf('.'))
                           + fileExt);
      else
        outFile = new File(destDir, xmlFile + fileExt);

      if (!inFile.exists())
      {
        log("File " + inFile + " doesn't exists");
        return;
      }

      if (!parsertableFile.exists())
      {
        log("File " + parsertableFile + " doesn't exists");
        return;
      }

      if ((inFile.lastModified() > outFile.lastModified())
              || (parsertableLastModified > outFile.lastModified()))
      {
        ensureDirectoryFor(outFile);
        log("Parsing files from " + destDir);

        ObjectInputStream in = new ObjectInputStream(new FileInputStream(parsertableFile));
        ParserTable parsertable = (ParserTable)in.readObject();
        in.close();

        OutputFormat format = new OutputFormat(Method.XML, "ASCII", indent); // Serialize DOM

        if (indent)
        {
          format.setIndenting(true);
          format.setIndent(1);
        }
        else
          format.setPreserveSpace(true);

        StringWriter stringOut = new StringWriter(); // Writer will be a String
        XMLSerializer serial = new XMLSerializer(stringOut, format);

        XMLReader xmlreader = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
        xmlreader.setContentHandler(new FragmentParser(serial.asContentHandler(), parser,
                                                       parsertable, ignorableTokens));
        try
        {
          xmlreader.parse(inFile.toString());
        }
        catch (SAXParseException se)
        {
          log("The grammar file is not valid: " + se.getMessage());
          return;
        }

        FileOutputStream outputstream = new FileOutputStream(outFile);
        PrintWriter printstream = new PrintWriter(outputstream);

        printstream.println(stringOut.toString());
        printstream.flush();
        printstream.close();
      }
    }
    catch (Exception ex)
    {
      log("Failed to process " + inFile, Project.MSG_INFO);
      if (outFile != null)
        outFile.delete();

      if (ex instanceof ParserException)
      {
        log(ex.toString());
        throw new BuildException("Parsing faild");
      }
      else
      {
        ex.printStackTrace();
        throw new BuildException(ex);
      }
    }
  }

  /**
   * Processes the given input XML file and stores the result
   * in the given resultFile.
   *
   * @param inFile The text file, which should parsed
   * @param outFile The output file
   * @param parsertableFile Parser table file
   *
   * @throws BuildException
   */
  private void process(File inFile, File outFile,
                       File parsertableFile) throws BuildException
  {
    try
    {
      long parsertableLastModified = parsertableFile.lastModified();

      log("In file " + inFile + " time: " + inFile.lastModified(),
          Project.MSG_DEBUG);
      log("Out file " + outFile + " time: " + outFile.lastModified(),
          Project.MSG_DEBUG);
      log("Parsertable file " + parsertableFile + " time: "
          + parsertableLastModified, Project.MSG_DEBUG);

      if (!inFile.exists())
      {
        log("File " + inFile + " doesn't exists");
        return;
      }

      if (!parsertableFile.exists())
      {
        log("File " + parsertableFile + " doesn't exists");
        return;
      }

      if ((inFile.lastModified() > outFile.lastModified())
              || (parsertableLastModified > outFile.lastModified()))
      {
        ensureDirectoryFor(outFile);
        log("Parsing file " + inFile + " to " + outFile, Project.MSG_INFO);

        ObjectInputStream in = new ObjectInputStream(new FileInputStream(parsertableFile));
        ParserTable parsertable = (ParserTable)in.readObject();
        in.close();

        OutputFormat format = new OutputFormat(Method.XML, "ASCII", indent); // Serialize DOM

        if (indent)
        {
          format.setIndenting(true);
          format.setIndent(1);
        }
        else
          format.setPreserveSpace(true);

        StringWriter stringOut = new StringWriter(); // Writer will be a String
        XMLSerializer serial = new XMLSerializer(stringOut, format);

        XMLReader xmlreader = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
        xmlreader.setContentHandler(new FragmentParser(serial.asContentHandler(), parser,
                                                       parsertable, ignorableTokens));
        try
        {
          xmlreader.parse(inFile.toString());
        }
        catch (SAXParseException se)
        {
          log("The grammar file is not valid: " + se.getMessage());
          return;
        }

        FileOutputStream outputstream = new FileOutputStream(outFile);
        PrintWriter printstream = new PrintWriter(outputstream);

        printstream.println(stringOut.toString());
        printstream.flush();
        printstream.close();
      }
    }
    catch (Exception ex)
    {
      log("Failed to process " + inFile, Project.MSG_INFO);
      if (outFile != null)
        outFile.delete();

      if (ex instanceof ParserException)
      {
        log(ex.toString());
        throw new BuildException("Parsing faild");
      }
      else
      {
        ex.printStackTrace();
        throw new BuildException(ex);
      }
    }
  }

  /**
   * Ensures the directory for the output
   *
   * @param targetFile The directory
   *
   * @throws BuildException
   */
  private void ensureDirectoryFor(File targetFile) throws BuildException
  {
    File directory = new File(targetFile.getParent());

    if ((!directory.exists()) && (!directory.mkdirs()))
      throw new BuildException("Unable to create directory: "
                               + directory.getAbsolutePath());
  }

  private class FragmentParser implements ContentHandler
  {
    private String EXTRACT_URI = "http://chaperon.sourceforge.net/schema/textfragment/1.0";
    private String EXTRACT_ELEMENT = "textfragment";

    private ContentHandler handler = null;
    private Parser parser = null;
    private ParserTable parsertable = null;
    private boolean ignorabletokens = false;
    private int extractLevel = 0;
    private StringBuffer text;

    public FragmentParser(ContentHandler handler, Parser parser, ParserTable parsertable, boolean ignorabletokens)
    {
      this.handler = handler;
      this.parser = parser;
      this.parsertable = parsertable;
      this.ignorabletokens = ignorabletokens;
    }

    public void setDocumentLocator(Locator locator)
    {
      handler.setDocumentLocator(locator);
    }

    public void startDocument() throws SAXException
    {
      handler.startDocument();
    }

    public void endDocument() throws SAXException
    {
      handler.endDocument();
    }

    public void startPrefixMapping(String prefix, String uri) throws SAXException
    {
      if (extractLevel==0)
        handler.startPrefixMapping(prefix, uri);
    }

    public void endPrefixMapping(String prefix) throws SAXException
    {
      if (extractLevel==0)
        handler.endPrefixMapping(prefix);
    }

    public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException
    {
      if (extractLevel > 0)
        text.append(ch, start, length);
      else
        handler.characters(ch, start, length);
    }

    public void processingInstruction(String target, String data) throws SAXException
    {
      if (extractLevel==0)
        handler.processingInstruction(target, data);
    }

    public void skippedEntity(String name) throws SAXException
    {
      if (extractLevel==0)
        handler.skippedEntity(name);
    }

    /**
     * Receive notification of the beginning of an element.
     *
     * @param uri The Namespace URI, or the empty string if the element has no
     *            Namespace URI or if Namespace
     *            processing is not being performed.
     * @param loc The local name (without prefix), or the empty string if
     *            Namespace processing is not being performed.
     * @param raw The raw XML 1.0 name (with prefix), or the empty string if
     *            raw names are not available.
     * @param a The attributes attached to the element. If there are no
     *          attributes, it shall be an empty Attributes object.
     */
    public void startElement(String uri, String loc, String raw,
                             Attributes a) throws SAXException
    {
      if (this.EXTRACT_URI.equals(uri) && this.EXTRACT_ELEMENT.equals(loc))
      {
        extractLevel++;
        text = new StringBuffer();
      }
      else
        if (extractLevel==0)
          handler.startElement(uri, loc, raw, a);
    }

    /**
     * Receive notification of the end of an element.
     *
     * @param uri The Namespace URI, or the empty string if the element has no
     *            Namespace URI or if Namespace
     *            processing is not being performed.
     * @param loc The local name (without prefix), or the empty string if
     *            Namespace processing is not being performed.
     * @param raw The raw XML 1.0 name (with prefix), or the empty string if
     *            raw names are not available.
     */
    public void endElement(String uri, String loc,
                           String raw) throws SAXException
    {
      if (this.EXTRACT_URI.equals(uri) && this.EXTRACT_ELEMENT.equals(loc))
      {
        extractLevel--;

        try
        {
          EventQueue queue = parser.parse(parsertable, new ByteArrayInputStream(text.toString().getBytes()));

          SAXEventAdapter adapter = new SAXEventAdapter(handler, ignorabletokens, true);
          queue.fireEvents(adapter);
        }
        catch (ParserException pe)
        {
          pe.printStackTrace();
        }

        text = null;
      }
      else
        if (extractLevel==0)
          handler.endElement(uri, loc, raw);
    }

    /**
     * Receive notification of character data.
     *
     * @param c The characters from the XML document.
     * @param start The start position in the array.
     * @param len The number of characters to read from the array.
     */
    public void characters(char c[], int start, int len) throws SAXException
    {
      if (extractLevel > 0)
        text.append(c, start, len);
      else
        handler.characters(c, start, len);
    }
  }
}
TOP

Related Classes of net.sourceforge.chaperon.ant.ChaperonFragmentParse

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.