/* $Revision$ $Author$ $Date$ * * Copyright (C) 1997-2007 Egon Willighagen <egonw@users.sf.net> * * Contact: cdk-devel@lists.sourceforge.net * * This program 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. * All we ask is that proper credit is given for our work, which includes * - but is not limited to - adding the above copyright notice to the beginning * of your source code files, and to any copyright notice that you may distribute * with programs based on this work. * * This program 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 program; 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.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import javax.vecmath.Point2d; import javax.vecmath.Point3d; import javax.vecmath.Vector3d; import org.openscience.cdk.CDKConstants; import org.openscience.cdk.dict.DictRef; import org.openscience.cdk.geometry.CrystalGeometryTools; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IBond; import org.openscience.cdk.interfaces.IChemFile; import org.openscience.cdk.interfaces.IChemModel; import org.openscience.cdk.interfaces.IChemSequence; import org.openscience.cdk.interfaces.ICrystal; import org.openscience.cdk.interfaces.IMolecule; import org.openscience.cdk.interfaces.IMoleculeSet; import org.openscience.cdk.interfaces.IMonomer; import org.openscience.cdk.interfaces.IPseudoAtom; import org.openscience.cdk.interfaces.IReaction; import org.openscience.cdk.interfaces.IReactionSet; import org.openscience.cdk.interfaces.IStrand; import org.openscience.cdk.tools.ILoggingTool; import org.openscience.cdk.tools.LoggingToolFactory; import org.openscience.cdk.tools.manipulator.AtomContainerManipulator; import org.openscience.cdk.tools.manipulator.BondManipulator; import org.xml.sax.Attributes; /** * Core CML 1.x and 2.x elements are parsed by this class. * * <p>Please file a bug report if this parser fails to parse * a certain element or attribute value in a valid CML document. * * @cdk.module io * @cdk.githash * * @author Egon Willighagen <egonw@sci.kun.nl> **/ public class CMLCoreModule implements ICMLModule { protected ILoggingTool logger; protected final String SYSTEMID = "CML-1999-05-15"; // protected IChemicalDocumentObject cdo; // data model to store things into protected IChemFile currentChemFile; protected IAtomContainer currentMolecule; protected IMoleculeSet currentMoleculeSet; protected IChemModel currentChemModel; protected IChemSequence currentChemSequence; protected IReactionSet currentReactionSet; protected IReaction currentReaction; protected IAtom currentAtom; protected IBond currentBond; protected IStrand currentStrand; protected IMonomer currentMonomer; protected Map<String, IAtom> atomEnumeration; protected List<String> moleculeCustomProperty; // helper fields protected int formulaCounter; protected int atomCounter; protected List<String> elsym; protected List<String> eltitles; protected List<String> elid; protected List<String> formula; protected List<String> formalCharges; protected List<String> partialCharges; protected List<String> isotope; protected List<String> atomicNumbers; protected List<String> exactMasses; protected List<String> x3; protected List<String> y3; protected List<String> z3; protected List<String> x2; protected List<String> y2; protected List<String> xfract; protected List<String> yfract; protected List<String> zfract; protected List<String> hCounts; protected List<String> atomParities; protected List<String> atomDictRefs; protected List<String> spinMultiplicities; protected List<String> occupancies; protected Map<Integer,List<String>> atomCustomProperty; protected int bondCounter; protected List<String> bondid; protected List<String> bondARef1; protected List<String> bondARef2; protected List<String> order; protected List<String> bondStereo; protected List<String> bondDictRefs; protected List<String> bondElid; protected List<Boolean> bondAromaticity; protected Map<String,Map<String,String>> bondCustomProperty; protected boolean stereoGiven; protected String inchi; protected int curRef; protected int CurrentElement; protected String BUILTIN; protected String DICTREF; protected String elementTitle; protected String currentChars; protected double[] unitcellparams; protected int crystalScalar; // private Vector3d aAxis; // private Vector3d bAxis; // private Vector3d cAxis; boolean cartesianAxesSet = false; public CMLCoreModule(IChemFile chemFile) { logger = LoggingToolFactory.createLoggingTool(CMLCoreModule.class); this.currentChemFile = chemFile; } public CMLCoreModule(ICMLModule conv) { logger = LoggingToolFactory.createLoggingTool(CMLCoreModule.class); inherit(conv); } public void inherit(ICMLModule convention) { if (convention instanceof CMLCoreModule) { CMLCoreModule conv = (CMLCoreModule)convention; // copy the data model this.currentChemFile = conv.currentChemFile; this.currentMolecule = conv.currentMolecule; this.currentMoleculeSet = conv.currentMoleculeSet; this.currentChemModel = conv.currentChemModel; this.currentChemSequence = conv.currentChemSequence; this.currentReactionSet = conv.currentReactionSet; this.currentReaction = conv.currentReaction; this.currentAtom = conv.currentAtom; this.currentStrand = conv.currentStrand; this.currentMonomer = conv.currentMonomer; this.atomEnumeration = conv.atomEnumeration; this.moleculeCustomProperty = conv.moleculeCustomProperty; // copy the intermediate fields this.logger = conv.logger; this.BUILTIN = conv.BUILTIN; this.atomCounter = conv.atomCounter; this.formulaCounter = conv.formulaCounter; this.elsym = conv.elsym; this.eltitles = conv.eltitles; this.elid = conv.elid; this.formalCharges = conv.formalCharges; this.partialCharges = conv.partialCharges; this.isotope = conv.isotope; this.atomicNumbers = conv.atomicNumbers; this.exactMasses = conv.exactMasses; this.x3 = conv.x3; this.y3 = conv.y3; this.z3 = conv.z3; this.x2 = conv.x2; this.y2 = conv.y2; this.xfract = conv.xfract; this.yfract = conv.yfract; this.zfract = conv.zfract; this.hCounts = conv.hCounts; this.atomParities = conv.atomParities; this.atomDictRefs = conv.atomDictRefs; this.spinMultiplicities = conv.spinMultiplicities; this.occupancies = conv.occupancies; this.bondCounter = conv.bondCounter; this.bondid = conv.bondid; this.bondARef1 = conv.bondARef1; this.bondARef2 = conv.bondARef2; this.order = conv.order; this.bondStereo = conv.bondStereo; this.bondCustomProperty = conv.bondCustomProperty; this.atomCustomProperty = conv.atomCustomProperty; this.bondDictRefs = conv.bondDictRefs; this.bondAromaticity = conv.bondAromaticity; this.curRef = conv.curRef; this.unitcellparams = conv.unitcellparams; this.inchi = conv.inchi; } else { logger.warn("Cannot inherit information from module: ", convention.getClass().getName()); } } public IChemFile returnChemFile() { return currentChemFile; } /** * Clean all data about parsed data. */ protected void newMolecule() { newMoleculeData(); newAtomData(); newBondData(); newCrystalData(); newFormulaData(); } /** * Clean all data about the molecule itself. */ protected void newMoleculeData() { this.inchi = null; } /** * Clean all data about read formulas. */ protected void newFormulaData() { formulaCounter = 0; formula = new ArrayList<String>(); } /** * Clean all data about read atoms. */ protected void newAtomData() { atomCounter = 0; elsym = new ArrayList<String>(); elid = new ArrayList<String>(); eltitles = new ArrayList<String>(); formalCharges = new ArrayList<String>(); partialCharges = new ArrayList<String>(); isotope = new ArrayList<String>(); atomicNumbers = new ArrayList<String>(); exactMasses = new ArrayList<String>(); x3 = new ArrayList<String>(); y3 = new ArrayList<String>(); z3 = new ArrayList<String>(); x2 = new ArrayList<String>(); y2 = new ArrayList<String>(); xfract = new ArrayList<String>(); yfract = new ArrayList<String>(); zfract = new ArrayList<String>(); hCounts = new ArrayList<String>(); atomParities = new ArrayList<String>(); atomDictRefs = new ArrayList<String>(); spinMultiplicities = new ArrayList<String>(); occupancies = new ArrayList<String>(); atomCustomProperty = new HashMap<Integer,List<String>>(); } /** * Clean all data about read bonds. */ protected void newBondData() { bondCounter = 0; bondid = new ArrayList<String>(); bondARef1 = new ArrayList<String>(); bondARef2 = new ArrayList<String>(); order = new ArrayList<String>(); bondStereo = new ArrayList<String>(); bondCustomProperty = new Hashtable<String,Map<String,String>>(); bondDictRefs = new ArrayList<String>(); bondElid = new ArrayList<String>(); bondAromaticity = new ArrayList<Boolean>(); } /** * Clean all data about read bonds. */ protected void newCrystalData() { unitcellparams = new double[6]; cartesianAxesSet = false; crystalScalar = 0; // aAxis = new Vector3d(); // bAxis = new Vector3d(); // cAxis = new Vector3d(); } public void startDocument() { logger.info("Start XML Doc"); // cdo.startDocument(); currentChemSequence = currentChemFile.getBuilder().newChemSequence(); currentChemModel = currentChemFile.getBuilder().newChemModel(); currentMoleculeSet = currentChemFile.getBuilder().newMoleculeSet(); currentMolecule = currentChemFile.getBuilder().newMolecule(); atomEnumeration = new HashMap<String, IAtom>(); moleculeCustomProperty = new ArrayList<String>(); newMolecule(); BUILTIN = ""; curRef = 0; } public void endDocument() { // cdo.endDocument(); if (currentReactionSet != null && currentReactionSet.getReactionCount() == 0 && currentReaction != null) { logger.debug("Adding reaction to ReactionSet"); currentReactionSet.addReaction(currentReaction); } if (currentReactionSet != null && currentChemModel.getReactionSet() == null) { logger.debug("Adding SOR to ChemModel"); currentChemModel.setReactionSet(currentReactionSet); } if (currentMoleculeSet != null && currentMoleculeSet.getMoleculeCount() != 0) { logger.debug("Adding reaction to MoleculeSet"); currentChemModel.setMoleculeSet(currentMoleculeSet); } if (currentChemSequence.getChemModelCount() == 0) { logger.debug("Adding ChemModel to ChemSequence"); currentChemSequence.addChemModel(currentChemModel); } if (currentChemFile.getChemSequenceCount() == 0) { // assume there is one non-animation ChemSequence // addChemSequence(currentChemSequence); currentChemFile.addChemSequence(currentChemSequence); } logger.info("End XML Doc"); } public void startElement(CMLStack xpath, String uri, String local, String raw, Attributes atts) { String name = local; logger.debug("StartElement"); currentChars = ""; BUILTIN = ""; DICTREF = ""; for (int i=0; i<atts.getLength(); i++) { String qname = atts.getQName(i); if (qname.equals("builtin")) { BUILTIN = atts.getValue(i); logger.debug(name, "->BUILTIN found: ", atts.getValue(i)); } else if (qname.equals("dictRef")) { DICTREF = atts.getValue(i); logger.debug(name, "->DICTREF found: ", atts.getValue(i)); } else if (qname.equals("title")) { elementTitle = atts.getValue(i); logger.debug(name, "->TITLE found: ", atts.getValue(i)); } else { logger.debug("Qname: ", qname); } } if ("atom".equals(name)) { atomCounter++; for (int i = 0; i < atts.getLength(); i++) { String att = atts.getQName(i); String value = atts.getValue(i); if (att.equals("id")) { // this is supported in CML 1.x elid.add(value); } // this is supported in CML 2.0 else if (att.equals("elementType")) { elsym.add(value); } // this is supported in CML 2.0 else if (att.equals("title")) { eltitles.add(value); } // this is supported in CML 2.0 else if (att.equals("x2")) { x2.add(value); } // this is supported in CML 2.0 else if (att.equals("xy2")) { StringTokenizer tokenizer = new StringTokenizer(value); x2.add(tokenizer.nextToken()); y2.add(tokenizer.nextToken()); } // this is supported in CML 2.0 else if (att.equals("xyzFract")) { StringTokenizer tokenizer = new StringTokenizer(value); xfract.add(tokenizer.nextToken()); yfract.add(tokenizer.nextToken()); zfract.add(tokenizer.nextToken()); } // this is supported in CML 2.0 else if (att.equals("xyz3")) { StringTokenizer tokenizer = new StringTokenizer(value); x3.add(tokenizer.nextToken()); y3.add(tokenizer.nextToken()); z3.add(tokenizer.nextToken()); } // this is supported in CML 2.0 else if (att.equals("y2")) { y2.add(value); } // this is supported in CML 2.0 else if (att.equals("x3")) { x3.add(value); } // this is supported in CML 2.0 else if (att.equals("y3")) { y3.add(value); } // this is supported in CML 2.0 else if (att.equals("z3")) { z3.add(value); } // this is supported in CML 2.0 else if (att.equals("xFract")) { xfract.add(value); } // this is supported in CML 2.0 else if (att.equals("yFract")) { yfract.add(value); } // this is supported in CML 2.0 else if (att.equals("zFract")) { zfract.add(value); } // this is supported in CML 2.0 else if (att.equals("formalCharge")) { formalCharges.add(value); } // this is supported in CML 2.0 else if (att.equals("hydrogenCount")) { hCounts.add(value); } else if (att.equals("isotopeNumber")) { isotope.add(value); } else if (att.equals("dictRef")) { logger.debug("ocupaccy: "+value); atomDictRefs.add(value); } else if (att.equals("spinMultiplicity")) { spinMultiplicities.add(value); } else if (att.equals("occupancy")) { occupancies.add(value); } else { logger.warn("Unparsed attribute: " + att); } } } else if ("atomArray".equals(name) && !xpath.endsWith("formula", "atomArray")) { boolean atomsCounted = false; for (int i = 0; i < atts.getLength(); i++) { String att = atts.getQName(i); int count = 0; if (att.equals("atomID")) { count = addArrayElementsTo(elid, atts.getValue(i)); } else if (att.equals("elementType")) { count = addArrayElementsTo(elsym, atts.getValue(i)); } else if (att.equals("x2")) { count = addArrayElementsTo(x2, atts.getValue(i)); } else if (att.equals("y2")) { count = addArrayElementsTo(y2, atts.getValue(i)); } else if (att.equals("x3")) { count = addArrayElementsTo(x3, atts.getValue(i)); } else if (att.equals("y3")) { count = addArrayElementsTo(y3, atts.getValue(i)); } else if (att.equals("z3")) { count = addArrayElementsTo(z3, atts.getValue(i)); } else if (att.equals("xFract")) { count = addArrayElementsTo(xfract, atts.getValue(i)); } else if (att.equals("yFract")) { count = addArrayElementsTo(yfract, atts.getValue(i)); } else if (att.equals("zFract")) { count = addArrayElementsTo(zfract, atts.getValue(i)); } else { logger.warn("Unparsed attribute: " + att); } if (!atomsCounted) { atomCounter += count; atomsCounted = true; } } } else if ("bond".equals(name)) { bondCounter++; for (int i = 0; i < atts.getLength(); i++) { String att = atts.getQName(i); logger.debug("B2 ", att, "=", atts.getValue(i)); if (att.equals("id")) { bondid.add(atts.getValue(i)); logger.debug("B3 ", bondid); } else if (att.equals("atomRefs") || // this is CML 1.x support att.equals("atomRefs2")) { // this is CML 2.0 support // expect exactly two references try { StringTokenizer st = new StringTokenizer( atts.getValue(i) ); bondARef1.add((String)st.nextElement()); bondARef2.add((String)st.nextElement()); } catch (Exception e) { logger.error("Error in CML file: ", e.getMessage()); logger.debug(e); } } else if (att.equals("order")) { // this is CML 2.0 support order.add(atts.getValue(i).trim()); } else if (att.equals("dictRef")) { bondDictRefs.add(atts.getValue(i).trim()); } } stereoGiven = false; curRef = 0; } else if ("bondArray".equals(name)) { boolean bondsCounted = false; for (int i = 0; i < atts.getLength(); i++) { String att = atts.getQName(i); int count = 0; if (att.equals("bondID")) { count = addArrayElementsTo(bondid, atts.getValue(i)); } else if (att.equals("atomRefs1")) { count = addArrayElementsTo(bondARef1, atts.getValue(i)); } else if (att.equals("atomRefs2")) { count = addArrayElementsTo(bondARef2, atts.getValue(i)); } else if (att.equals("atomRef1")) { count = addArrayElementsTo(bondARef1, atts.getValue(i)); } else if (att.equals("atomRef2")) { count = addArrayElementsTo(bondARef2, atts.getValue(i)); } else if (att.equals("order")) { count = addArrayElementsTo(order, atts.getValue(i)); } else { logger.warn("Unparsed attribute: " + att); } if (!bondsCounted) { bondCounter += count; bondsCounted = true; } } curRef = 0; } else if ("bondStereo".equals(name)) { for (int i = 0; i < atts.getLength(); i++) { if (atts.getQName(i).equals("dictRef")) { if (atts.getValue(i).startsWith("cml:")) bondStereo.add(atts.getValue(i).substring(4)); stereoGiven=true; } } } else if ("bondType".equals(name)) { for (int i = 0; i < atts.getLength(); i++) { if (atts.getQName(i).equals("dictRef")) { if (atts.getValue(i).equals("cdk:aromaticBond")) bondAromaticity.add(Boolean.TRUE); } } } else if ("molecule".equals(name)) { newMolecule(); BUILTIN = ""; // cdo.startObject("Molecule"); if (currentChemModel == null) currentChemModel = currentChemFile.getBuilder().newChemModel(); if (currentMoleculeSet == null) currentMoleculeSet = currentChemFile.getBuilder().newMoleculeSet(); currentMolecule = currentChemFile.getBuilder().newMolecule(); for (int i = 0; i < atts.getLength(); i++) { if (atts.getQName(i).equals("id")) { // cdo.setObjectProperty("Molecule", "id", atts.getValue(i)); currentMolecule.setID(atts.getValue(i)); } else if (atts.getQName(i).equals("dictRef")) { // cdo.setObjectProperty("Molecule", "dictRef", atts.getValue(i)); currentMolecule.setProperty(new DictRef(DICTREF, atts.getValue(i)), atts.getValue(i)); } } } else if ("crystal".equals(name)) { newCrystalData(); // cdo.startObject("Crystal"); currentMolecule = currentChemFile.getBuilder().newCrystal(currentMolecule); for (int i = 0; i < atts.getLength(); i++) { String att = atts.getQName(i); if (att.equals("z")) { // cdo.setObjectProperty("Crystal", "z", atts.getValue(i)); ((ICrystal)currentMolecule).setZ(Integer.parseInt(atts.getValue(i))); } } } else if ("symmetry".equals(name)) { for (int i = 0; i < atts.getLength(); i++) { String att = atts.getQName(i); if (att.equals("spaceGroup")) { // cdo.setObjectProperty("Crystal", "spacegroup", atts.getValue(i)); ((ICrystal)currentMolecule).setSpaceGroup(atts.getValue(i)); } } } else if ("identifier".equals(name)) { if (atts.getValue("convention") != null && atts.getValue("convention").equals("iupac:inchi") && atts.getValue("value") != null) { // cdo.setObjectProperty("Molecule", "inchi", atts.getValue("value")); currentMolecule.setProperty(CDKConstants.INCHI, atts.getValue("value")); } } else if ("scalar".equals(name)) { if (xpath.endsWith("crystal", "scalar")) crystalScalar++; } else if ("label".equals(name)) { if (xpath.endsWith("atomType", "label")) { // cdo.setObjectProperty("Atom", "atomTypeLabel", atts.getValue("value")); currentAtom.setAtomTypeName(atts.getValue("value")); } } else if ("list".equals(name)) { // cdo.startObject("MoleculeSet"); if (DICTREF.equals("cdk:model")) { currentChemModel = currentChemFile.getBuilder().newChemModel(); // see if there is an ID attribute for (int i = 0; i < atts.getLength(); i++) { String att = atts.getQName(i); if (att.equals("id")) { currentChemModel.setID(atts.getValue(i)); } } } else if (DICTREF.equals("cdk:moleculeSet")) { currentMoleculeSet = currentChemFile.getBuilder().newMoleculeSet(); // see if there is an ID attribute for (int i = 0; i < atts.getLength(); i++) { String att = atts.getQName(i); if (att.equals("id")) { currentMoleculeSet.setID(atts.getValue(i)); } } currentMolecule = currentChemFile.getBuilder().newMolecule(); } else { // the old default currentMoleculeSet = currentChemFile.getBuilder().newMoleculeSet(); // see if there is an ID attribute for (int i = 0; i < atts.getLength(); i++) { String att = atts.getQName(i); if (att.equals("id")) { currentMoleculeSet.setID(atts.getValue(i)); } } currentMolecule = currentChemFile.getBuilder().newMolecule(); } }else if ("formula".equals(name)){ formulaCounter++; for (int i = 0; i < atts.getLength(); i++) { String att = atts.getQName(i); String value = atts.getValue(i); if (att.equals("concise")) { formula.add(value); } } } } public void endElement(CMLStack xpath, String uri, String name, String raw) { logger.debug("EndElement: ", name); String cData = currentChars; if ("bond".equals(name)) { if (!stereoGiven) bondStereo.add(""); if (bondCounter > bondDictRefs.size()) bondDictRefs.add(null); if (bondCounter > bondAromaticity.size()) bondAromaticity.add(null); } else if ("atom".equals(name)) { if (atomCounter > eltitles.size()) { eltitles.add(null); } if (atomCounter > hCounts.size()) { hCounts.add(null); } if (atomCounter > atomDictRefs.size()) { atomDictRefs.add(null); } if (atomCounter > isotope.size()) { isotope.add(null); } if (atomCounter > atomicNumbers.size()) { atomicNumbers.add(null); } if (atomCounter > exactMasses.size()) { exactMasses.add(null); } if (atomCounter > spinMultiplicities.size()) { spinMultiplicities.add(null); } if (atomCounter > occupancies.size()) { occupancies.add(null); } if (atomCounter > formalCharges.size()) { /* while strictly undefined, assume zero formal charge when no number is given */ formalCharges.add("0"); } /* It may happen that not all atoms have associated 2D or 3D coordinates. accept that */ if (atomCounter > x2.size() && x2.size() != 0) { /* apparently, the previous atoms had atomic coordinates, add 'null' for this atom */ x2.add(null); y2.add(null); } if (atomCounter > x3.size() && x3.size() != 0) { /* apparently, the previous atoms had atomic coordinates, add 'null' for this atom */ x3.add(null); y3.add(null); z3.add(null); } if (atomCounter > xfract.size() && xfract.size() != 0) { /* apparently, the previous atoms had atomic coordinates, add 'null' for this atom */ xfract.add(null); yfract.add(null); zfract.add(null); } } else if ("molecule".equals(name)) { storeData(); // cdo.endObject("Molecule"); if (currentMolecule instanceof IMolecule) { logger.debug("Adding molecule to set"); currentMoleculeSet.addMolecule((IMolecule)currentMolecule); logger.debug("#mols in set: " + currentMoleculeSet.getMoleculeCount()); } else if (currentMolecule instanceof ICrystal) { logger.debug("Adding crystal to chemModel"); currentChemModel.setCrystal((ICrystal)currentMolecule); currentChemSequence.addChemModel(currentChemModel); } } else if ("crystal".equals(name)) { if (crystalScalar > 0) { // convert unit cell parameters to cartesians Vector3d[] axes = CrystalGeometryTools.notionalToCartesian( unitcellparams[0], unitcellparams[1], unitcellparams[2], unitcellparams[3], unitcellparams[4], unitcellparams[5] ); cartesianAxesSet = true; // cdo.startObject("a-axis"); // cdo.setObjectProperty("a-axis", "x", new Double(aAxis.x).toString()); // cdo.setObjectProperty("a-axis", "y", new Double(aAxis.y).toString()); // cdo.setObjectProperty("a-axis", "z", new Double(aAxis.z).toString()); // cdo.endObject("a-axis"); // cdo.startObject("b-axis"); // cdo.setObjectProperty("b-axis", "x", new Double(bAxis.x).toString()); // cdo.setObjectProperty("b-axis", "y", new Double(bAxis.y).toString()); // cdo.setObjectProperty("b-axis", "z", new Double(bAxis.z).toString()); // cdo.endObject("b-axis"); // cdo.startObject("c-axis"); // cdo.setObjectProperty("c-axis", "x", new Double(cAxis.x).toString()); // cdo.setObjectProperty("c-axis", "y", new Double(cAxis.y).toString()); // cdo.setObjectProperty("c-axis", "z", new Double(cAxis.z).toString()); // cdo.endObject("c-axis"); ((ICrystal)currentMolecule).setA(axes[0]); ((ICrystal)currentMolecule).setB(axes[1]); ((ICrystal)currentMolecule).setC(axes[2]); } else { logger.error("Could not find crystal unit cell parameters"); } // cdo.endObject("Crystal"); } else if ("list".equals(name)) { // cdo.endObject("MoleculeSet"); // FIXME: I really should check the DICTREF, but there is currently // no mechanism for storing these for use with endTag() :( // So, instead, for now, just see if it already has done the setting // to work around duplication if (currentChemModel.getMoleculeSet() != currentMoleculeSet) { currentChemModel.setMoleculeSet(currentMoleculeSet); currentChemSequence.addChemModel(currentChemModel); } } else if ("coordinate3".equals(name)) { if (BUILTIN.equals("xyz3")) { logger.debug("New coord3 xyz3 found: ", currentChars); try { StringTokenizer st = new StringTokenizer(currentChars); x3.add(st.nextToken()); y3.add(st.nextToken()); z3.add(st.nextToken()); logger.debug("coord3 x3.length: ", x3.size()); logger.debug("coord3 y3.length: ", y3.size()); logger.debug("coord3 z3.length: ", z3.size()); } catch (Exception exception) { logger.error( "CMLParsing error while setting coordinate3!"); logger.debug(exception); } } else { logger.warn("Unknown coordinate3 BUILTIN: " + BUILTIN); } } else if ("string".equals(name)) { if (BUILTIN.equals("elementType")) { logger.debug("Element: ", cData.trim()); elsym.add(cData); } else if (BUILTIN.equals("atomRef")) { curRef++; logger.debug("Bond: ref #", curRef); if (curRef == 1) { bondARef1.add(cData.trim()); } else if (curRef == 2) { bondARef2.add(cData.trim()); } } else if (BUILTIN.equals("order")) { logger.debug("Bond: order ", cData.trim()); order.add(cData.trim()); } else if (BUILTIN.equals("formalCharge")) { // NOTE: this combination is in violation of the CML DTD!!! logger.warn("formalCharge BUILTIN accepted but violating CML DTD"); logger.debug("Charge: ", cData.trim()); String charge = cData.trim(); if (charge.startsWith("+") && charge.length() > 1) { charge = charge.substring(1); } formalCharges.add(charge); } } else if ("float".equals(name)) { if (BUILTIN.equals("x3")) { x3.add(cData.trim()); } else if (BUILTIN.equals("y3")) { y3.add(cData.trim()); } else if (BUILTIN.equals("z3")) { z3.add(cData.trim()); } else if (BUILTIN.equals("x2")) { x2.add(cData.trim()); } else if (BUILTIN.equals("y2")) { y2.add(cData.trim()); } else if (BUILTIN.equals("order")) { // NOTE: this combination is in violation of the CML DTD!!! order.add(cData.trim()); } else if (BUILTIN.equals("charge") || BUILTIN.equals("partialCharge")) { partialCharges.add(cData.trim()); } } else if ("integer".equals(name)) { if (BUILTIN.equals("formalCharge")) { formalCharges.add(cData.trim()); } } else if ("coordinate2".equals(name)) { if (BUILTIN.equals("xy2")) { logger.debug("New coord2 xy2 found.", cData); try { StringTokenizer st = new StringTokenizer(cData); x2.add(st.nextToken()); y2.add(st.nextToken()); } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 175, 1); } } } else if ("stringArray".equals(name)) { if (BUILTIN.equals("id") || BUILTIN.equals("atomId") || BUILTIN.equals("atomID")) { // invalid according to CML1 DTD but found in OpenBabel 1.x output try { boolean countAtoms = (atomCounter == 0) ? true : false; StringTokenizer st = new StringTokenizer(cData); while (st.hasMoreTokens()) { if (countAtoms) { atomCounter++; } String token = st.nextToken(); logger.debug("StringArray (Token): ", token); elid.add(token); } } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 186, 1); } } else if (BUILTIN.equals("elementType")) { try { boolean countAtoms = (atomCounter == 0) ? true : false; StringTokenizer st = new StringTokenizer(cData); while (st.hasMoreTokens()) { if (countAtoms) { atomCounter++; } elsym.add(st.nextToken()); } } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 194, 1); } } else if (BUILTIN.equals("atomRefs")) { curRef++; logger.debug("New atomRefs found: ", curRef); try { boolean countBonds = (bondCounter == 0) ? true : false; StringTokenizer st = new StringTokenizer(cData); while (st.hasMoreTokens()) { if (countBonds) { bondCounter++; } String token = st.nextToken(); logger.debug("Token: ", token); if (curRef == 1) { bondARef1.add(token); } else if (curRef == 2) { bondARef2.add(token); } } } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 194, 1); } } else if (BUILTIN.equals("atomRef")) { curRef++; logger.debug("New atomRef found: ", curRef); // this is CML1 stuff, we get things like: /* <bondArray> <stringArray builtin="atomRef">a2 a2 a2 a2 a3 a3 a4 a4 a5 a6 a7 a9</stringArray> <stringArray builtin="atomRef">a9 a11 a12 a13 a5 a4 a6 a9 a7 a8 a8 a10</stringArray> <stringArray builtin="order">1 1 1 1 2 1 2 1 1 1 2 2</stringArray> </bondArray> */ try { boolean countBonds = (bondCounter == 0) ? true : false; StringTokenizer st = new StringTokenizer(cData); while (st.hasMoreTokens()) { if (countBonds) { bondCounter++; } String token = st.nextToken(); logger.debug("Token: ", token); if (curRef == 1) { bondARef1.add(token); } else if (curRef == 2) { bondARef2.add(token); } } } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 194, 1); } } else if (BUILTIN.equals("order")) { logger.debug("New bond order found."); try { StringTokenizer st = new StringTokenizer(cData); while (st.hasMoreTokens()) { String token = st.nextToken(); logger.debug("Token: ", token); order.add(token); } } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 194, 1); } } } else if ("integerArray".equals(name)) { logger.debug("IntegerArray: builtin = ", BUILTIN); if (BUILTIN.equals("formalCharge")) { try { StringTokenizer st = new StringTokenizer(cData); while (st.hasMoreTokens()) { String token = st.nextToken(); logger.debug("Charge added: ", token); formalCharges.add(token); } } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 205, 1); } } } else if ("scalar".equals(name)) { if (xpath.endsWith("crystal", "scalar")) { logger.debug("Going to set a crystal parameter: " + crystalScalar, " to ", cData); try { unitcellparams[crystalScalar-1] = Double.parseDouble(cData.trim()); } catch (NumberFormatException exception) { logger.error("Content must a float: " + cData); } } else if (xpath.endsWith("bond", "scalar")) { if (DICTREF.equals("mdl:stereo")) { bondStereo.add(cData.trim()); stereoGiven=true; }else{ Map<String,String> bp = bondCustomProperty.get(bondid.get(bondid.size()-1)); if (bp == null) { bp = new Hashtable<String, String>(); bondCustomProperty.put(bondid.get(bondid.size()-1), bp); } bp.put(elementTitle, cData.trim()); } } else if (xpath.endsWith("atom", "scalar")) { if (DICTREF.equals("cdk:partialCharge")) { partialCharges.add(cData.trim()); } else if (DICTREF.equals("cdk:atomicNumber")) { atomicNumbers.add(cData.trim()); } else if (DICTREF.equals("cdk:isotopicMass")) { exactMasses.add(cData.trim()); }else { if(atomCustomProperty.get(Integer.valueOf(atomCounter-1))==null) atomCustomProperty.put(Integer.valueOf(atomCounter-1),new ArrayList<String>()); atomCustomProperty.get(Integer.valueOf(atomCounter-1)).add(elementTitle); atomCustomProperty.get(Integer.valueOf(atomCounter-1)).add(cData.trim()); } } else if (xpath.endsWith("molecule", "scalar")) { if (DICTREF.equals("pdb:id")) { // cdo.setObjectProperty("Molecule", DICTREF, cData); currentMolecule.setProperty(new DictRef(DICTREF, cData), cData); } else if (DICTREF.equals("cdk:molecularProperty")) { currentMolecule.setProperty(elementTitle, cData); }else{ moleculeCustomProperty.add(elementTitle); moleculeCustomProperty.add(cData.trim()); } } else if (xpath.endsWith("reaction", "scalar")) { if (DICTREF.equals("cdk:reactionProperty")) { currentReaction.setProperty(elementTitle, cData); } } else { logger.warn("Ignoring scalar: " + xpath); } } else if ("floatArray".equals(name)) { if (BUILTIN.equals("x3")) { try { StringTokenizer st = new StringTokenizer(cData); while (st.hasMoreTokens()) x3.add(st.nextToken()); } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 205, 1); } } else if (BUILTIN.equals("y3")) { try { StringTokenizer st = new StringTokenizer(cData); while (st.hasMoreTokens()) y3.add(st.nextToken()); } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 213, 1); } } else if (BUILTIN.equals("z3")) { try { StringTokenizer st = new StringTokenizer(cData); while (st.hasMoreTokens()) z3.add(st.nextToken()); } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 221, 1); } } else if (BUILTIN.equals("x2")) { logger.debug("New floatArray found."); try { StringTokenizer st = new StringTokenizer(cData); while (st.hasMoreTokens()) x2.add(st.nextToken()); } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 205, 1); } } else if (BUILTIN.equals("y2")) { logger.debug("New floatArray found."); try { StringTokenizer st = new StringTokenizer(cData); while (st.hasMoreTokens()) y2.add(st.nextToken()); } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 454, 1); } } else if (BUILTIN.equals("partialCharge")) { logger.debug("New floatArray with partial charges found."); try { StringTokenizer st = new StringTokenizer(cData); while (st.hasMoreTokens()) partialCharges.add(st.nextToken()); } catch (Exception e) { notify("CMLParsing error: " + e, SYSTEMID, 462, 1); } } } else if ("basic".equals(name)) { // assuming this is the child element of <identifier> this.inchi = cData; } else if ("name".equals(name)) { if (xpath.endsWith("molecule", "name")) { if (DICTREF.length() > 0) { // cdo.setObjectProperty("Molecule", DICTREF, cData); currentMolecule.setProperty(new DictRef(DICTREF, cData), cData); } else { // cdo.setObjectProperty("Molecule", "Name", cData); currentMolecule.setProperty(CDKConstants.TITLE, cData); } } }else if ("formula".equals(name)) { currentMolecule.setProperty(CDKConstants.FORMULA, cData); }else { logger.warn("Skipping element: " + name); } currentChars = ""; BUILTIN = ""; elementTitle = ""; } public void characterData(CMLStack xpath, char[] ch, int start, int length) { currentChars = currentChars + new String(ch, start, length); logger.debug("CD: ", currentChars); } protected void notify(String message, String systemId, int line, int column) { logger.debug("Message: ", message); logger.debug("SystemId: ", systemId); logger.debug("Line: ", line); logger.debug("Column: ", column); } protected void storeData() { if (inchi != null) { // cdo.setObjectProperty("Molecule", "inchi", inchi); currentMolecule.setProperty(CDKConstants.INCHI, inchi); } if (formula != null){ currentMolecule.setProperty(CDKConstants.FORMULA, formula); } Iterator<String> customs=moleculeCustomProperty.iterator(); while(customs.hasNext()){ String x = customs.next(); String y = customs.next(); currentMolecule.setProperty(x,y); } storeAtomData(); storeBondData(); convertCMLToCDKHydrogenCounts(); } private void convertCMLToCDKHydrogenCounts() { for (IAtom atom : currentMolecule.atoms()) { if (atom.getHydrogenCount() != null) { int explicitHCount = AtomContainerManipulator.countExplicitHydrogens(currentMolecule, atom); if (explicitHCount != 0) { atom.setHydrogenCount(atom.getHydrogenCount() - explicitHCount); } } } } protected void storeAtomData() { logger.debug("No atoms: ", atomCounter); if (atomCounter == 0) { return; } boolean hasID = false; boolean has3D = false; boolean has3Dfract = false; boolean has2D = false; boolean hasFormalCharge = false; boolean hasPartialCharge = false; boolean hasHCounts = false; boolean hasSymbols = false; boolean hasTitles = false; boolean hasIsotopes = false; boolean hasAtomicNumbers = false; boolean hasExactMasses = false; boolean hasDictRefs = false; boolean hasSpinMultiplicities = false; boolean hasOccupancies = false; if (elid.size() == atomCounter) { hasID = true; } else { logger.debug("No atom ids: " + elid.size(), " != " + atomCounter); } if (elsym.size() == atomCounter) { hasSymbols = true; } else { logger.debug( "No atom symbols: " + elsym.size(), " != " + atomCounter); } if (eltitles.size() == atomCounter) { hasTitles = true; } else { logger.debug( "No atom titles: " + eltitles.size(), " != " + atomCounter); } if ((x3.size() == atomCounter) && (y3.size() == atomCounter) && (z3.size() == atomCounter)) { has3D = true; } else { logger.debug( "No 3D info: " + x3.size(), " " + y3.size(), " " + z3.size(), " != " + atomCounter); } if ((xfract.size() == atomCounter) && (yfract.size() == atomCounter) && (zfract.size() == atomCounter)) { has3Dfract = true; } else { logger.debug( "No 3D fractional info: " + xfract.size(), " " + yfract.size(), " " + zfract.size(), " != " + atomCounter); } if ((x2.size() == atomCounter) && (y2.size() == atomCounter)) { has2D = true; } else { logger.debug( "No 2D info: " + x2.size(), " " + y2.size(), " != " + atomCounter); } if (formalCharges.size() == atomCounter) { hasFormalCharge = true; } else { logger.debug( "No formal Charge info: " + formalCharges.size(), " != " + atomCounter); } if (partialCharges.size() == atomCounter) { hasPartialCharge = true; } else { logger.debug( "No partial Charge info: " + partialCharges.size(), " != " + atomCounter); } if (hCounts.size() == atomCounter) { hasHCounts = true; } else { logger.debug( "No hydrogen Count info: " + hCounts.size(), " != " + atomCounter); } if (spinMultiplicities.size() == atomCounter) { hasSpinMultiplicities = true; } else { logger.debug( "No spinMultiplicity info: " + spinMultiplicities.size(), " != " + atomCounter); } if (occupancies.size() == atomCounter) { hasOccupancies = true; } else { logger.debug( "No occupancy info: " + occupancies.size(), " != " + atomCounter); } if (atomDictRefs.size() == atomCounter) { hasDictRefs = true; } else { logger.debug( "No dictRef info: " + atomDictRefs.size(), " != " + atomCounter); } if (isotope.size() == atomCounter) { hasIsotopes = true; } else { logger.debug( "No isotope info: " + isotope.size(), " != " + atomCounter); } if (atomicNumbers.size() == atomCounter) { hasAtomicNumbers = true; } else { logger.debug( "No atomicNumbers info: " + atomicNumbers.size(), " != " + atomCounter); } if (exactMasses.size() == atomCounter) { hasExactMasses = true; } else { logger.debug( "No atomicNumbers info: " + atomicNumbers.size(), " != " + atomCounter); } for (int i = 0; i < atomCounter; i++) { logger.info("Storing atom: ", i); // cdo.startObject("Atom"); currentAtom = currentChemFile.getBuilder().newAtom("H"); logger.debug("Atom # " + atomCounter); if (hasID) { // cdo.setObjectProperty("Atom", "id", (String)elid.get(i)); logger.debug("id: ", (String)elid.get(i)); currentAtom.setID((String)elid.get(i)); atomEnumeration.put((String)elid.get(i), currentAtom); } if (hasTitles) { if (hasSymbols) { String symbol = (String)elsym.get(i); if (symbol.equals("Du") || symbol.equals("Dummy")) { // cdo.setObjectProperty("PseudoAtom", "label", (String)eltitles.get(i)); if (!(currentAtom instanceof IPseudoAtom)) { currentAtom = currentChemFile.getBuilder().newPseudoAtom(currentAtom); if (hasID) atomEnumeration.put((String)elid.get(i), currentAtom); } ((IPseudoAtom)currentAtom).setLabel((String)eltitles.get(i)); } else { // cdo.setObjectProperty("Atom", "title", (String)eltitles.get(i)); // FIXME: huh? if (eltitles.get(i) != null) currentAtom.setProperty(CDKConstants.TITLE, (String)eltitles.get(i)); } } else { // cdo.setObjectProperty("Atom", "title", (String)eltitles.get(i)); // FIXME: huh? if (eltitles.get(i) != null) currentAtom.setProperty(CDKConstants.TITLE, (String)eltitles.get(i)); } } // store optional atom properties if (hasSymbols) { String symbol = (String)elsym.get(i); if (symbol.equals("Du") || symbol.equals("Dummy")) { symbol = "R"; } // cdo.setObjectProperty("Atom", "type", symbol); if (symbol.equals("R") && !(currentAtom instanceof IPseudoAtom)) { currentAtom = currentChemFile.getBuilder().newPseudoAtom(currentAtom); if (hasID) atomEnumeration.put((String)elid.get(i), currentAtom); } currentAtom.setSymbol(symbol); } if (has3D) { // cdo.setObjectProperty("Atom", "x3", (String)x3.get(i)); // cdo.setObjectProperty("Atom", "y3", (String)y3.get(i)); // cdo.setObjectProperty("Atom", "z3", (String)z3.get(i)); if (x3.get(i) != null && y3.get(i) != null && z3.get(i) != null) { currentAtom.setPoint3d( new Point3d( Double.parseDouble((String)x3.get(i)), Double.parseDouble((String)y3.get(i)), Double.parseDouble((String)z3.get(i)) ) ); } } if (has3Dfract) { // ok, need to convert fractional into eucledian coordinates // cdo.setObjectProperty("Atom", "xFract", (String)xfract.get(i)); // cdo.setObjectProperty("Atom", "yFract", (String)yfract.get(i)); // cdo.setObjectProperty("Atom", "zFract", (String)zfract.get(i)); currentAtom.setFractionalPoint3d( new Point3d( Double.parseDouble((String)xfract.get(i)), Double.parseDouble((String)yfract.get(i)), Double.parseDouble((String)zfract.get(i)) ) ); } if (hasFormalCharge) { // cdo.setObjectProperty("Atom", "formalCharge", // (String)formalCharges.get(i)); currentAtom.setFormalCharge(Integer.parseInt((String)formalCharges.get(i))); } if (hasPartialCharge) { logger.debug("Storing partial atomic charge..."); // cdo.setObjectProperty("Atom", "partialCharge", // (String)partialCharges.get(i)); currentAtom.setCharge(Double.parseDouble((String)partialCharges.get(i))); } if (hasHCounts) { // cdo.setObjectProperty("Atom", "hydrogenCount", (String)hCounts.get(i)); // FIXME: the hCount in CML is the total of implicit *and* explicit String hCount = hCounts.get(i); if (hCount != null) { currentAtom.setHydrogenCount(Integer.parseInt(hCount)); } else { currentAtom.setHydrogenCount((Integer)CDKConstants.UNSET); } } if (has2D) { if (x2.get(i) != null && y2.get(i) != null) { // cdo.setObjectProperty("Atom", "x2", (String)x2.get(i)); // cdo.setObjectProperty("Atom", "y2", (String)y2.get(i)); currentAtom.setPoint2d( new Point2d( Double.parseDouble((String)x2.get(i)), Double.parseDouble((String)y2.get(i)) ) ); } } if (hasDictRefs) { // cdo.setObjectProperty("Atom", "dictRef", (String)atomDictRefs.get(i)); if (atomDictRefs.get(i) != null) currentAtom.setProperty("org.openscience.cdk.dict", (String)atomDictRefs.get(i)); } if (hasSpinMultiplicities && spinMultiplicities.get(i) != null) { // cdo.setObjectProperty("Atom", "spinMultiplicity", (String)spinMultiplicities.get(i)); int unpairedElectrons = Integer.parseInt((String)spinMultiplicities.get(i))-1; for (int sm=0; sm<unpairedElectrons; sm++) { currentMolecule.addSingleElectron(currentChemFile.getBuilder().newSingleElectron(currentAtom)); } } if (hasOccupancies && occupancies.get(i) != null) { // cdo.setObjectProperty("Atom", "occupanciy", (String)occupancies.get(i)); // FIXME: this has no ChemFileCDO equivalent, not even if spelled correctly } if (hasIsotopes) { // cdo.setObjectProperty("Atom", "massNumber", (String)isotope.get(i)); if (isotope.get(i) != null) currentAtom.setMassNumber((int)Double.parseDouble((String)isotope.get(i))); } if (hasAtomicNumbers) { if (atomicNumbers.get(i) != null) currentAtom.setAtomicNumber(Integer.parseInt(atomicNumbers.get(i))); } if (hasExactMasses) { if (exactMasses.get(i) != null) currentAtom.setExactMass(Double.parseDouble(exactMasses.get(i))); } if(atomCustomProperty.get(Integer.valueOf(i))!=null){ Iterator<String> it=atomCustomProperty.get(Integer.valueOf(i)).iterator(); while(it.hasNext()){ currentAtom.setProperty(it.next(),it.next()); } } // cdo.endObject("Atom"); currentMolecule.addAtom(currentAtom); } if (elid.size() > 0) { // assume this is the current working list bondElid = elid; } newAtomData(); } protected void storeBondData() { logger.debug( "Testing a1,a2,stereo,order = count: " + bondARef1.size(), "," + bondARef2.size(), "," + bondStereo.size(), "," + order.size(), "=" + bondCounter); if ((bondARef1.size() == bondCounter) && (bondARef2.size() == bondCounter)) { logger.debug("About to add bond info..."); Iterator<String> orders = order.iterator(); Iterator<String> ids = bondid.iterator(); Iterator<String> bar1s = bondARef1.iterator(); Iterator<String> bar2s = bondARef2.iterator(); Iterator<String> stereos = bondStereo.iterator(); Iterator<Boolean> aroms = bondAromaticity.iterator(); while (bar1s.hasNext()) { // cdo.startObject("Bond"); // if (ids.hasNext()) { // cdo.setObjectProperty("Bond", "id", (String)ids.next()); // } // cdo.setObjectProperty("Bond", "atom1", // Integer.valueOf(bondElid.indexOf( // (String)bar1s.next())).toString()); // cdo.setObjectProperty("Bond", "atom2", // Integer.valueOf(bondElid.indexOf( // (String)bar2s.next())).toString()); IAtom a1 = (IAtom)atomEnumeration.get((String)bar1s.next()); IAtom a2 = (IAtom)atomEnumeration.get((String)bar2s.next()); currentBond = currentChemFile.getBuilder().newBond(a1, a2); if (ids.hasNext()) { currentBond.setID((String)ids.next()); } if (orders.hasNext()) { String bondOrder = (String)orders.next(); if ("S".equals(bondOrder)) { // cdo.setObjectProperty("Bond", "order", "1"); currentBond.setOrder(CDKConstants.BONDORDER_SINGLE); } else if ("D".equals(bondOrder)) { // cdo.setObjectProperty("Bond", "order", "2"); currentBond.setOrder(CDKConstants.BONDORDER_DOUBLE); } else if ("T".equals(bondOrder)) { // cdo.setObjectProperty("Bond", "order", "3"); currentBond.setOrder(CDKConstants.BONDORDER_TRIPLE); } else if ("A".equals(bondOrder)) { // cdo.setObjectProperty("Bond", "order", "1.5"); currentBond.setOrder(CDKConstants.BONDORDER_SINGLE); currentBond.setFlag(CDKConstants.ISAROMATIC, true); } else { // cdo.setObjectProperty("Bond", "order", bondOrder); currentBond.setOrder( BondManipulator.createBondOrder(Double.parseDouble(bondOrder)) ); } } if (stereos.hasNext()) { // cdo.setObjectProperty("Bond", "stereo", // (String)stereos.next()); String nextStereo = (String)stereos.next(); if ("H".equals(nextStereo)) { currentBond.setStereo(IBond.Stereo.DOWN); } else if ("W".equals(nextStereo)) { currentBond.setStereo(IBond.Stereo.UP); } else if (nextStereo != null){ logger.warn("Cannot interpret stereo information: " + nextStereo); } } if (aroms.hasNext()) { Object nextArom = aroms.next(); if (nextArom != null && nextArom == Boolean.TRUE) { currentBond.setFlag(CDKConstants.ISAROMATIC, true); } } if (currentBond.getID() != null) { Map<String,String> currentBondProperties = bondCustomProperty.get(currentBond.getID()); if (currentBondProperties != null) { Iterator<String> keys = currentBondProperties.keySet().iterator(); while (keys.hasNext()) { String key = keys.next(); currentBond.setProperty(key,currentBondProperties.get(key)); } bondCustomProperty.remove(currentBond.getID()); } } // cdo.endObject("Bond"); currentMolecule.addBond(currentBond); } } newBondData(); } protected int addArrayElementsTo(List<String> toAddto, String array) { StringTokenizer tokenizer = new StringTokenizer(array); int i = 0; while (tokenizer.hasMoreElements()) { toAddto.add(tokenizer.nextToken()); i++; } return i; } }