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