DigestHandler.java :  » Scripting » Pnuts » pnuts » xml » Java Open Source

Java Open Source » Scripting » Pnuts 
Pnuts » pnuts » xml » DigestHandler.java
/*
 * @(#)DigestHandler.java 1.2 04/12/06
 *
 * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
 *
 * See the file "LICENSE.txt" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */
package pnuts.xml;

import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;
import java.util.*;
import java.io.*;

/**
 * <code>DigestHandler</code> provides a base implementation for <code>DigestReader</code> class.
 */
public class DigestHandler extends DefaultHandler {

  private SAXAttributeMap attributeMap;
  private boolean useLocalNames;
  private List stack;
  private StringBuffer sbuf;
  private Object value;

  private List valueStack;
  private List paths;
  private String path;

  Stack listPaths;
  Stack listValues;

  private RuleSet ruleSet;

  /**
   * Constructor
   */
  public DigestHandler(){
    this(new SimpleRuleSet());
  }

  public DigestHandler(RuleSet ruleSet){
    this.ruleSet = ruleSet;
  }

  void setRuleSet(RuleSet ruleSet){
    this.ruleSet = ruleSet;
  }

  /**
   * Changes the setting of which of {qualified | local} names are used in
   * callback handlers.  When localName is used, the SAX parser should be
   * namespace aware.
   *
   * @param useLocalNames use local names instead of quarified names. 
   *    If this method is called with true, a Map object that is passed to
   *    DigestAction.start() method will contain {localName->value} mappings.
   */
  public void setUseLocalNames(boolean useLocalNames){
    this.useLocalNames = useLocalNames;
  }

  /**
   * Checks if the current setting uses local names instead of qualified names;
   *
   * @return true if the current setting uses local names instead of qualified names. 
   */
  public boolean isUseLocalNames(){
    return useLocalNames;
  }

  /*
   * The inital value.
   */
  public Object getValue(){
    return value;
  }

  /**
   * Sets the initial value, which is to be modified during the parsing.
   *
   * @param value the intial value
   */
  public void setValue(Object value){
    this.value = value;
  }

  void initialize(){
    path = "";
    stack = new ArrayList();
    sbuf = new StringBuffer(64);
    paths = new ArrayList();
    valueStack = new ArrayList();
    listPaths = new Stack();
    listValues = new Stack();
    pushValue("", value);
    if (useLocalNames){
      attributeMap = new LocalNameMap();
    } else {
      attributeMap = new SAXAttributeMap();
    }
  }

  /**
   * Adds a rule.
   *
   * @param action the action to be invoked at the begining/end of the element.
   * @param path the path identifier. as a '/'-separated QName list.
   */
  public void addRule(DigestAction action, String path){
    addRule(action, path, null);
  }

  /**
   * Adds a rule.
   *
   * @param action the action to be invoked at the begining/end of the element.
   * @param path the path identifier. as a '/'-separated QName list.
   * @param keyword the key to access the intermediate/final result.
   */
  public void addRule(DigestAction action, String path, String keyword){
    if (action != null){
      action.handler = this;
      ruleSet.add(path, action, keyword);
    }
  }

  String getKey(String path){
    String base = getStackTopPath();
    if (sameBranch(path, base) && base.length() + 1 < path.length()){
      return path.substring(base.length() + 1);
    } else {
      int idx = path.lastIndexOf('/');
      if (idx > 0){
        return path.substring(idx + 1);
      } else {
        return path;
      }
    }
  }

  static boolean sameBranch(String longer, String shorter){
    int idx = longer.indexOf(shorter);
    if (idx < 0){
      return false;
    }
    int len2 = shorter.length();
    if (longer.length() == len2){
      return true;
    }
    return (longer.charAt(len2) == '/');
  }

  public void startElement (String uri,
                String localName,
                String qName,
                Attributes attributes)
    throws org.xml.sax.SAXException
    {
      stack.add(qName);

      String _path = this.path;
      StringBuffer sb = new StringBuffer(_path);
      sb.append('/');
      sb.append(qName);
      final String path = this.path = sb.toString();

      int pos = paths.size() - 1;
      while (pos > 0 && !sameBranch(path, (String)paths.get(pos))){
        popValue();
        pos--;
      }
      attributeMap.setAttributes(attributes);
      final String defaultKey = getKey(path);
      try {
        ruleSet.scan(path, stack, new TargetHandler(){
            public void handle(DigestAction action, String keyword) throws Exception {
              if (keyword == null){
                keyword = defaultKey;
              }
              action.start(path, keyword, attributeMap, getStackTopValue());
            }
          });
      } catch (Exception e){
        throw new SAXException(e);
      }
    }

  public void endElement (String uri, String localName, String qName)
    throws org.xml.sax.SAXException
    {
      final String path = this.path;
      String valuePath = getStackTopPath();

      int pos = paths.size() - 1;
      while (pos > 0 && !sameBranch(path, valuePath)){
        popValue();
        pos--;
        valuePath = getStackTopPath();
        break;
      }

      final String defaultKey = getKey(path);
      final String text = sbuf.toString().trim();
      try {
        ruleSet.scan(path, stack, new TargetHandler(){
            public void handle(DigestAction action, String keyword) throws Exception {
              if (keyword == null){
                keyword = defaultKey;
              }
              action.end(path, keyword, text, getStackTopValue());
            }
          });
      } catch (Exception e){
        throw new SAXException(e);
      }
      sbuf.setLength(0);

      stack.remove(stack.size() - 1);
      int idx = path.lastIndexOf('/');
      if (idx > 0){
        this.path = path.substring(0, idx);
      } else {
        this.path = "";
      }
    }

  Object getStackTopValue(){
    return valueStack.get(valueStack.size() - 1);
  }

  String getStackTopPath(){
    return (String)paths.get(paths.size() - 1);
  }

  void pushValue(String path, Object value){
    paths.add(path);
    valueStack.add(value);
  }

  Object popValue(){
    paths.remove(paths.size() - 1);
    Object value = valueStack.remove(valueStack.size() - 1);
    if (!listValues.isEmpty() && value == listValues.peek()){
      listPaths.pop();
      listValues.pop();
    }
    return value;
  }

  /**
   * Registers <em>list</em> for the specified <em>path</em>.
   * The registered <em>list</em> is unregistered when different branch from the one
   * the list is registered with, or an element of parent path is found by the parser.
   */
  public synchronized void registerListPath(String path, Object list){
    listPaths.push(path);
    listValues.push(list);
  }

  /**
   * Checks if the list registered with <em>path</em> is still managed by the DigestReader.
   *
   * @param path the path
   * @return true if it is still managed by the DigestReader.
   */
  public boolean listAlive(String path){
    return listPaths.size() > 0 && listPaths.peek().equals(path);
  }

  /**
   * Returns the most recent managed list.
   *
   * @return the list object
   */
  public Object currentListValue(){
    return listValues.peek();
  }

  public void characters (char ch[], int start, int length)
    throws org.xml.sax.SAXException
    {
      sbuf.append(ch, start, length);
    }

  public void startDocument() throws org.xml.sax.SAXException {
    initialize();
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.