1 /* Copyright (C) 2003-2007 Egon Willighagen <egonw@users.sf.net> 2 * 3 * Contact: cdk-devel@lists.sf.net 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 package org.openscience.cdk.config.isotopes; 20 21 import java.util.ArrayList; 22 import java.util.List; 23 24 import org.openscience.cdk.interfaces.IIsotope; 25 import org.openscience.cdk.interfaces.IChemObjectBuilder; 26 import org.openscience.cdk.tools.ILoggingTool; 27 import org.openscience.cdk.tools.LoggingToolFactory; 28 import org.xml.sax.Attributes; 29 import org.xml.sax.helpers.DefaultHandler; 30 31 /** 32 * Reads an isotope list in CML2 format. An example definition is: 33 * <pre>{@code 34 * <isotopeList id="H"> 35 * <isotope id="H1" isotopeNumber="1" elementTyp="H"> 36 * <abundance dictRef="cdk:relativeAbundance">100.0</abundance> 37 * <scalar dictRef="cdk:exactMass">1.00782504</scalar> 38 * <scalar dictRef="cdk:atomicNumber">1</scalar> 39 * </isotope> 40 * <isotope id="H2" isotopeNumber="2" elementTyp="H"> 41 * <abundance dictRef="cdk:relativeAbundance">0.015</abundance> 42 * <scalar dictRef="cdk:exactMass">2.01410179</scalar> 43 * <scalar dictRef="cdk:atomicNumber">1</scalar> 44 * </isotope> 45 * </isotopeList> 46 * }</pre> 47 * 48 * @cdk.module extra 49 * @cdk.githash 50 */ 51 public class IsotopeHandler extends DefaultHandler { 52 53 private static ILoggingTool logger = LoggingToolFactory.createLoggingTool(IsotopeHandler.class); 54 private String currentChars; 55 private List<IIsotope> isotopes; 56 57 private IIsotope workingIsotope; 58 private String currentElement; 59 private String dictRef; 60 61 private IChemObjectBuilder builder; 62 63 /** 64 * Constructs an IsotopeHandler used by the IsotopeReader. 65 * 66 * @param builder The IChemObjectBuilder used to create new IIsotope's. 67 */ IsotopeHandler(IChemObjectBuilder builder)68 public IsotopeHandler(IChemObjectBuilder builder) { 69 this.builder = builder; 70 } 71 72 /** 73 * Returns the isotopes read from the XML file. 74 * 75 * @return A List object with all isotopes 76 */ getIsotopes()77 public List<IIsotope> getIsotopes() { 78 return isotopes; 79 } 80 81 // SAX Parser methods 82 83 /** {@inheritDoc} */ 84 @Override startDocument()85 public void startDocument() { 86 isotopes = new ArrayList<IIsotope>(); 87 } 88 89 /** {@inheritDoc} */ 90 @Override endElement(String uri, String local, String raw)91 public void endElement(String uri, String local, String raw) { 92 logger.debug("end element: ", raw); 93 if ("isotope".equals(local)) { 94 if (workingIsotope != null) isotopes.add(workingIsotope); 95 workingIsotope = null; 96 } else if ("isotopeList".equals(local)) { 97 currentElement = null; 98 } else if ("scalar".equals(local)) { 99 try { 100 if ("bo:exactMass".equals(dictRef)) { 101 workingIsotope.setExactMass(Double.parseDouble(currentChars)); 102 } else if ("bo:atomicNumber".equals(dictRef)) { 103 workingIsotope.setAtomicNumber(Integer.parseInt(currentChars)); 104 } else if ("bo:relativeAbundance".equals(dictRef)) { 105 workingIsotope.setNaturalAbundance(Double.parseDouble(currentChars)); 106 } 107 } catch (NumberFormatException exception) { 108 logger.error("The ", dictRef, " value is incorrect: ", currentChars); 109 logger.debug(exception); 110 } 111 } 112 } 113 114 /** {@inheritDoc} */ 115 @Override startElement(String uri, String local, String raw, Attributes atts)116 public void startElement(String uri, String local, String raw, Attributes atts) { 117 currentChars = ""; 118 dictRef = ""; 119 logger.debug("startElement: ", raw); 120 logger.debug("uri: ", uri); 121 logger.debug("local: ", local); 122 logger.debug("raw: ", raw); 123 if ("isotope".equals(local)) { 124 workingIsotope = createIsotopeOfElement(currentElement, atts); 125 } else if ("isotopeList".equals(local)) { 126 currentElement = getElementSymbol(atts); 127 } else if ("scalar".equals(local)) { 128 for (int i = 0; i < atts.getLength(); i++) { 129 if ("dictRef".equals(atts.getQName(i))) { 130 dictRef = atts.getValue(i); 131 } 132 } 133 } 134 } 135 136 /** {@inheritDoc} */ 137 @Override characters(char chars[], int start, int length)138 public void characters(char chars[], int start, int length) { 139 currentChars += new String(chars, start, length); 140 } 141 createIsotopeOfElement(String currentElement, Attributes atts)142 private IIsotope createIsotopeOfElement(String currentElement, Attributes atts) { 143 IIsotope isotope = builder.newInstance(IIsotope.class, currentElement); 144 145 for (int i = 0; i < atts.getLength(); i++) { 146 try { 147 if ("id".equals(atts.getQName(i))) { 148 isotope.setID(atts.getValue(i)); 149 } else if ("number".equals(atts.getQName(i))) { 150 isotope.setMassNumber(Integer.parseInt(atts.getValue(i))); 151 } else if ("elementType".equals(atts.getQName(i))) { 152 isotope.setSymbol(atts.getValue(i)); 153 } 154 } catch (NumberFormatException exception) { 155 logger.error("Value of isotope@", atts.getQName(i), " is not as expected."); 156 logger.debug(exception); 157 } 158 } 159 160 // we set the natural abundance to 0, since the default is -1, but 161 // some isotope entries have no entry for this field, so the values 162 // stays at -1 163 isotope.setNaturalAbundance(0.0); 164 165 return isotope; 166 } 167 getElementSymbol(Attributes atts)168 private String getElementSymbol(Attributes atts) { 169 for (int i = 0; i < atts.getLength(); i++) { 170 if ("id".equals(atts.getQName(i))) { 171 return atts.getValue(i); 172 } 173 } 174 return ""; 175 } 176 177 } 178