org.openscience.cdk.io.cml.CMLHandler Maven / Gradle / Ivy
/* Copyright (C) 1997-2007 Egon Willighagen
*
* 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.openscience.cdk.io.cml;
import java.util.Hashtable;
import java.util.Map;
import org.openscience.cdk.interfaces.IChemFile;
import org.openscience.cdk.tools.ILoggingTool;
import org.openscience.cdk.tools.LoggingToolFactory;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
/**
* SAX2 implementation for CML XML fragment reading. CML Core is supported
* as well is the CRML module.
*
* Data is stored into the Chemical Document Object which is passed when
* instantiating this class. This makes it possible that programs that do not
* use CDK for internal data storage, use this CML library.
*
* @cdk.module io
* @cdk.githash
*
* @author Egon Willighagen
**/
public class CMLHandler extends DefaultHandler {
private ICMLModule conv;
private static ILoggingTool logger = LoggingToolFactory.createLoggingTool(CMLHandler.class);
private boolean debug = true;
private Map userConventions;
private CMLStack xpath;
private CMLStack conventionStack;
private CMLModuleStack moduleStack;
/**
* Constructor for the CMLHandler.
*
* @param chemFile The document in which data is stored
**/
public CMLHandler(IChemFile chemFile) {
conv = new CMLCoreModule(chemFile);
userConventions = new Hashtable();
xpath = new CMLStack();
conventionStack = new CMLStack();
moduleStack = new CMLModuleStack();
}
public void registerConvention(String convention, ICMLModule conv) {
userConventions.put(convention, conv);
}
/**
* Implementation of the characters() procedure overwriting the DefaultHandler interface.
*
* @param ch characters to handle
*/
@Override
public void characters(char ch[], int start, int length) {
if (debug) logger.debug(new String(ch, start, length));
conv.characterData(xpath, ch, start, length);
}
public void doctypeDecl(String name, String publicId, String systemId) throws Exception {}
/**
* Calling this procedure signals the end of the XML document.
*/
@Override
public void endDocument() {
conv.endDocument();
}
@Override
public void endElement(String uri, String local, String raw) {
if (debug) logger.debug("" + raw + ">");
conv.endElement(xpath, uri, local, raw);
xpath.pop();
conventionStack.pop();
moduleStack.pop();
conv = moduleStack.current();
}
@Override
public void startDocument() {
conv.startDocument();
conventionStack.push("CML");
moduleStack.push(conv);
}
@Override
public void startElement(String uri, String local, String raw, Attributes atts) {
xpath.push(local);
if (debug) logger.debug("<", raw, "> -> ", xpath);
// Detect CML modules, like CRML and CCML
if (local.startsWith("reaction")) {
// e.g. reactionList, reaction -> CRML module
logger.info("Detected CRML module");
if (!conventionStack.current().equals("CMLR")) {
conv = new CMLReactionModule(conv);
}
conventionStack.push("CMLR");
} else if (uri == null || uri.length() == 0 || uri.startsWith("http://www.xml-cml.org/")) {
// assume CML Core
// Detect conventions
String convName = "";
for (int i = 0; i < atts.getLength(); i++) {
if (atts.getQName(i).equals("convention")) {
convName = atts.getValue(i);
}
}
if (convName.length() > 0) {
if (convName.equals(conventionStack.current())) {
logger.debug("Same convention as parent");
} else {
logger.info("New Convention: ", convName);
if (convName.equals("CML")) {
/*
* Don't reset the convention handler to CMLCore,
* becuase all handlers should extend this handler, and
* use it for any content other then specifically put
* into the specific convention
*/
} else if (convName.equals("PDB")) {
conv = new PDBConvention(conv);
} else if (convName.equals("PMP")) {
conv = new PMPConvention(conv);
} else if (convName.equals("MDLMol")) {
if (debug) logger.debug("MDLMolConvention instantiated...");
conv = new MDLMolConvention(conv);
} else if (convName.equals("JMOL-ANIMATION")) {
conv = new JMOLANIMATIONConvention(conv);
} else if (convName.equals("qsar:DescriptorValue")) {
conv = new QSARConvention(conv);
} else if (userConventions.containsKey(convName)) {
//unknown convention. userConvention?
ICMLModule newconv = (ICMLModule) userConventions.get(convName);
newconv.inherit(conv);
conv = newconv;
} else {
logger.warn("Detected unknown convention: ", convName);
}
}
conventionStack.push(convName);
} else {
// no convention set/reset: take convention of parent
conventionStack.push(conventionStack.current());
}
} else {
conv = new OtherNamespace();
conventionStack.push("Other");
}
moduleStack.push(conv);
if (debug) logger.debug("ConventionStack: ", conventionStack);
conv.startElement(xpath, uri, local, raw, atts);
}
}