org.jmol.adapter.readers.xml.XmlReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmol Show documentation
Show all versions of jmol Show documentation
Jmol: an open-source Java viewer for chemical structures in 3D
/* $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)
data = data.substring(data.indexOf("<", 1));
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 + ">"+name+">";
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
}
}