All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jmol.adapter.readers.xml.XmlReader Maven / Gradle / Ivy

There is a newer version: 14.31.10
Show newest version
/* $RCSfile$
 * $Author: hansonr $
 * $Date: 2006-08-02 11:48:43 -0500 (Wed, 02 Aug 2006) $
 * $Revision: 5364 $
 *
 * Copyright (C) 2003-2005  Miguel, Jmol Development, www.jmol.org
 *
 * Contact: [email protected]
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library 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 library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.jmol.adapter.readers.xml;

import java.io.BufferedInputStream;
import java.util.Hashtable;
import java.util.Map;

import javajs.util.Rdr;
import javajs.util.SB;

import org.jmol.adapter.smarter.Atom;
import org.jmol.adapter.smarter.AtomSetCollection;
import org.jmol.adapter.smarter.AtomSetCollectionReader;
import org.jmol.adapter.smarter.Resolver;
import org.jmol.api.Interface;
import org.jmol.util.Logger;

/**
 * A generic XML reader template -- by itself, does nothing.
 * 
 * The actual readers are XmlCmlReader, XmlMolproReader (which is an extension
 * of XmlCmlReader), XmlChem3dReader, and XmlOdysseyReader.
 * 
 * 
 * XmlReader takes all XML streams, whether from a file reader or from DOM.
 * 
 * This class functions as a resolver, since it: (1) identifying the specific
 * strain of XML to be handled, and (2) passing the responsibility on to the
 * correct format-specific XML readers. There are parallel entry points and
 * handler methods for reader and DOM. Each format-specific XML reader then
 * assigns its own handler to manage the parsing of elements.
 * 
 * In addition, this class handles generic XML tag parsing.
 * 
 * XmlHandler extends DefaultHandler is the generic interface to both reader and
 * DOM element parsing.
 * 
 * XmlCmlReader extends XmlReader
 * 
 * XmlMolproReader extends XmlCmlReader. If you feel like expanding on that,
 * feel free.
 * 
 * XmlChem3dReader extends XmlReader. That one is simple; no need to expand on
 * it at this time.
 * 
 * XmlOdysseyReader extends XmlReader. That one is simple; no need to expand on
 * it at this time.
 * 
 * Note that the tag processing routines are shared between SAX and DOM
 * processors. This means that attributes must be transformed from either
 * Attributes (SAX) or JSObjects (DOM) to Hashtable name:value pairs. This is
 * taken care of in JmolXmlHandler for all readers.
 * 
 * TODO 27/8/06:
 * 
 * Several aspects of CifReader are NOT YET implemented here. These include
 * loading a specific model when there are several, applying the symmetry, and
 * loading fractional coordinates. [DONE for CML reader 2/2007 RMH]
 * 
 * 
 * Test files:
 * 
 * molpro: vib.xml odyssey: water.xodydata cml: a wide variety of files in
 * data-files.
 * 
 * -Bob Hanson
 * 
 */

public class XmlReader extends AtomSetCollectionReader {

  protected Atom atom;
  //protected String[] domAttributes;
  protected XmlReader parent; // XmlReader itself; to be assigned by the subReader
  public Map atts;

  /////////////// file reader option //////////////

  @Override
  public void initializeReader() throws Exception {
    initCML();
  }

  protected void initCML() {
    atts = new Hashtable();
    setMyError(parseXML());
    continuing = false;
  }

  private void setMyError(String err) {
    if (err != null
        && (asc == null || asc.errorMessage == null)) {
      asc = new AtomSetCollection("xml", this, null, null);
      asc.errorMessage = err;
    }
  }

  private String parseXML() {
    Object saxReader = null;

    /**
     * @j2sNative
     * 
     * 
     * 
     */
    {
      try {
        javax.xml.parsers.SAXParserFactory spf = javax.xml.parsers.SAXParserFactory
            .newInstance();
        spf.setNamespaceAware(true);
        javax.xml.parsers.SAXParser saxParser = spf.newSAXParser();
        saxReader = saxParser.getXMLReader();
        if (debugging)
          Logger.debug("Using JAXP/SAX XML parser.");
      } catch (Exception e) {
        if (debugging)
          Logger.debug("Could not instantiate JAXP/SAX XML reader: "
            + ((parent == null ? this : parent).vwr.isJS? e : e.getMessage()));
      }
      if (saxReader == null)
        return "No XML reader found";
    }
    return selectReaderAndGo(saxReader);
  }

  private String selectReaderAndGo(Object saxReader) {
    asc = new AtomSetCollection(readerName, this, null, null);
    String className = null;
    XmlReader thisReader = null;
    int pt = readerName.indexOf("(");
    String name = (pt < 0 ? readerName : readerName.substring(0, pt));
    className = Resolver.getReaderClassBase(name);
    if ((thisReader = (XmlReader) getInterface(className)) == null)
      return "File reader was not found: " + className;
    try {
      thisReader.processXml(this, saxReader);
    } catch (Exception e) {
      return "Error reading XML: " + ((parent == null ? vwr : parent.vwr).isJS ? e : e.getMessage());
    }
    return null;
  }

  /**
   * 
   * @param parent
   * @param saxReader
   * @throws Exception
   */
  protected void processXml(XmlReader parent, Object saxReader)
      throws Exception {
    processXml2(parent, saxReader);
  }

  protected void processXml2(XmlReader parent, Object saxReader) throws Exception {
    this.parent = parent;
    asc = parent.asc;
    reader = parent.reader;
    atts = parent.atts;
    if (saxReader == null) {
      //domAttributes = getDOMAttributes();
      attribs = new Object[1];
      attArgs = new Object[1];
      domObj = new Object[1];
      Object o = "";
      byte[] data = null;
      /**
       * 
       * @j2sNative
       * 
       *            o = this.reader.lock.lock; if (o.$in) data = o.$in.buf;
       */
      {
      }
      if (o instanceof BufferedInputStream)
        o = Rdr.StreamToUTF8String(Rdr.getBIS(data));
      /**
       * 
       * @j2sNative
       * 
       *            this.domObj[0] = this.createDomNodeJS("xmlReader",o);
       *            this.walkDOMTree(); this.createDomNodeJS("xmlReader",null);
       * 
       */
      {
        walkDOMTree();
      }
    } else {
      ((XmlHandler) Interface.getOption("adapter.readers.xml.XmlHandler", vwr,
          "file")).parseXML(this, saxReader, reader);
    }
  }
  
  /**
   * @param id  
   * @param data 
   */
  void createDomNodeJS(String id, Object data) {
    // no doubt there is a more efficient way to do this.
    // Firefox, at least, does not recognize "/>" in HTML blocks
    // that are added this way.
    
    @SuppressWarnings("unused")
    Object applet = parent.vwr.html5Applet;
    /**
     * note that there is no need to actually load it into the document
     * 
     * @j2sNative
     * 
     // id = applet._id + "_" + id;
     // var d = document.getElementById(id);
     // if (d)
     //   document.body.removeChild(d);
      if (!data)
        return;
      if (data.indexOf("") >= 0) {
        var D = data.split("/>");
        for (var i = D.length - 1; --i >= 0;) {
          var s = D[i];
          var pt = s.lastIndexOf("<") + 1;
          var pt2 = pt;
          var len = s.length;
          var name = "";
          while (++pt2 < len) {
            if (" \t\n\r".indexOf(s.charAt(pt2))>= 0) {
              var name = s.substring(pt, pt2);
              D[i] = s + ">";
              break;
            }     
          }
        }
        data = D.join('');
      }
      var d = document.createElement("_xml");
      d.innerHTML = data;
      return d;
     * 
     */
    {
      // only called by j2s
    }
      
  }
  
  @Override
  public void applySymmetryAndSetTrajectory() {
    try {
      if (parent == null)
        applySymTrajASCR();
      else
        parent.applySymmetryAndSetTrajectory();
    } catch (Exception e) {
      System.out.println((parent == null ? this : parent).vwr.isJS? e : e.getMessage());
      Logger.error("applySymmetry failed: " + e);
    }
  }

  /////////////// DOM option //////////////

  @Override
  protected void processDOM(Object DOMNode) {
    domObj = new Object[] { DOMNode };
    setMyError(selectReaderAndGo(null));
  }

//  protected String[] getDOMAttributes() {
//    // different subclasses will implement this differently
//    return new String[] { "id" };
//  }

  ////////////////////////////////////////////////////////////////

  /**
   * 
   * @param localName
   * @param nodeName TODO
   */
  protected void processStartElement(String localName, String nodeName) {
    /* 
     * specific to each xml reader
     */
  }

  /*
   *  keepChars is used to signal 
   *  that characters between end tags should be kept
   *  
   */

  protected boolean keepChars;
  protected SB chars = SB.newN(2000);

  protected void setKeepChars(boolean TF) {
    keepChars = TF;
    chars.setLength(0);
  }

  /**
   * 
   * @param localName
   */
  void processEndElement(String localName) {
    /* 
     * specific to each xml reader
     */
  }

  //////////////////// DOM or JavaScript parsing /////////////////

  // walk DOM tree given by JSObject. For every element, call
  // startElement with the appropriate strings etc., and then
  // endElement when the element is closed.

  private Object[] domObj = new Object[1];
  private Object[] attribs;
  private Object[] attArgs;
  private Object[] nullObj = new Object[0];

  private void walkDOMTree() {
    String localName;
    /**
     * @j2sNative
     * 
     * localName = "nodeName";
     * 
     */
    {
      localName = "localName";
    }
    String nodeName = ((String) jsObjectGetMember(domObj, localName));
    localName = fixLocal(nodeName);
    if (localName == null)
      return;
    if (localName.equals("#text")) {
      if (keepChars)
        chars.append((String) jsObjectGetMember(domObj, "data"));
      return;
    }
    localName = localName.toLowerCase();
    nodeName = nodeName.toLowerCase();
    attribs[0] = jsObjectGetMember(domObj, "attributes");
    getDOMAttributesA(attribs);
    processStartElement(localName, nodeName);
    boolean haveChildren;
    /**
     * @j2sNative
     * 
     *            haveChildren = this.domObj[0].hasChildNodes;
     * 
     */
    {
      haveChildren = ((Boolean) jsObjectCall(domObj, "hasChildNodes", null))
          .booleanValue();
    }
    if (haveChildren) {
      Object nextNode = jsObjectGetMember(domObj, "firstChild");
      while (nextNode != null) {
        domObj[0] = nextNode;
        walkDOMTree();
        domObj[0] = nextNode;
        nextNode = jsObjectGetMember(domObj, "nextSibling");
      }
    }
    processEndElement(localName);
  }

  private String fixLocal(String name) {
    /**
     * @j2sNative
     * 
     *            var pt = (name== null ? -1 : name.indexOf(":")); return (pt >=
     *            0 ? name.substring(pt+1) : name);
     */
    {
      return name;
    }
  }

  private void getDOMAttributesA(Object[] attributes) {
    
    atts.clear();
    if (attributes == null)
      return;

    /**
     * @j2sNative
     * 
     * 
     *            var nodes = attributes[0]; for (var i = nodes.length; --i >=
     *            0;) { var key = this.fixLocal(nodes[i].name);
     *            this.atts.put(key.toLowerCase(), nodes[i].value); }
     *            return;
     * 
     * 
     * 
     */
    {
      
      // Java only -- no longer loading only specific values
      
      Number N = (Number) jsObjectGetMember(attributes, "length");
      int n  = (N == null ? 0 : N.intValue());
      for (int i = n; --i >= 0;) {
        attArgs[0] = Integer.valueOf(i);
        attArgs[0] = jsObjectCall(attributes, "item", attArgs);
        if (attArgs[0] != null) {
          String attValue = (String) jsObjectGetMember(attArgs, "value");
          if (attValue != null)
            atts.put(((String) jsObjectGetMember(attArgs, "name")).toLowerCase(), attValue);
        }
      }
    }
  }

  /**
   * @j2sIgnore
   * 
   * @param jsObject
   * @param method
   * @param args
   * @return object
   */
  private Object jsObjectCall(Object[] jsObject, String method, Object[] args) {
    {
    return parent.vwr.apiPlatform.getJsObjectInfo(jsObject, method,
        args == null ? nullObj : args);
    }
  }

  private Object jsObjectGetMember(Object[] jsObject, String name) {
    /**
     * @j2sNative
     * 
     * return jsObject[0][name]; 
     * 
     */
    {
    return parent.vwr.apiPlatform.getJsObjectInfo(jsObject, name, null);
    }
  }

  public void endDocument() {
    // CML reader uses this
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy