001/* A parser for PlotML (Plot Markup Language) supporting Histogram commands. 002 003 Copyright (c) 1998-2016 The Regents of the University of California. 004 All rights reserved. 005 Permission is hereby granted, without written agreement and without 006 license or royalty fees, to use, copy, modify, and distribute this 007 software and its documentation for any purpose, provided that the above 008 copyright notice and the following two paragraphs appear in all copies 009 of this software. 010 011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 015 SUCH DAMAGE. 016 017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 022 ENHANCEMENTS, OR MODIFICATIONS. 023 024 PT_COPYRIGHT_VERSION_2 025 COPYRIGHTENDKEY 026 027 */ 028package ptolemy.plot.plotml; 029 030import com.microstar.xml.XmlException; 031 032import ptolemy.plot.Histogram; 033 034/////////////////////////////////////////////////////////////////// 035//// HistogramMLParser 036 037/** 038 This class constructs a histogram from specifications 039 in PlotML (Plot Markup Language), which is an XML language. 040 This class supports extends the base class to 041 ensure that the associated plotter is an instance of Histogram. 042 It ignores unrecognized elements in the DTD. 043 The class contains an instance of the Microstar Ælfred XML 044 parser and implements callback methods to interpret the parsed XML. 045 The way to use this class is to construct it with a reference to 046 a Plot object and then call its parse() method. 047 048 @author Edward A. Lee 049 @version $Id$ 050 @since Ptolemy II 0.4 051 @Pt.ProposedRating Red (eal) 052 @Pt.AcceptedRating Red (cxh) 053 */ 054public class HistogramMLParser extends PlotMLParser { 055 /** Construct an parser to parse commands for the specified plot object. 056 * @param plot The plot object to which to apply the commands. 057 */ 058 public HistogramMLParser(Histogram plot) { 059 _plot = plot; 060 } 061 062 /////////////////////////////////////////////////////////////////// 063 //// public methods //// 064 065 /** End an element. Override the base class to ignore non-histogram 066 * operations. 067 * Ælfred will call this method at the end of each element 068 * (including EMPTY elements). 069 * @param elementName The element type name. 070 * @exception Exception If thrown by the base class. 071 */ 072 @Override 073 public void endElement(String elementName) throws Exception { 074 if (elementName.equals("bars") || elementName.equals("dataset")) { 075 // Ignore 076 } else { 077 super.endElement(elementName); 078 } 079 } 080 081 /** Start an element. 082 * This is called at the beginning of each XML 083 * element. By the time it is called, all of the attributes 084 * for the element will already have been reported using the 085 * attribute() method. Unrecognized elements are ignored. 086 * @param elementName The element type name. 087 * @exception XmlException If the element produces an error 088 * in constructing the model. 089 */ 090 @Override 091 public void startElement(String elementName) throws XmlException { 092 try { 093 if (elementName.equals("barGraph")) { 094 // Override the base class to ignore things irrelevant 095 // to histograms... 096 String widthSpec = (String) _attributes.get("width"); 097 String offsetSpec = (String) _attributes.get("offset"); 098 099 // NOTE: If only one of these is given, then the other 100 // is ignored. 101 if (widthSpec != null && offsetSpec != null) { 102 double width = Double.valueOf(widthSpec).doubleValue(); 103 double offset = Double.valueOf(offsetSpec).doubleValue(); 104 ((Histogram) _plot).setBars(width, offset); 105 } 106 } else if (elementName.equals("bin")) { 107 // Ignore if plot is not an instance of Histogram. 108 if (_plot instanceof Histogram) { 109 Histogram histogram = (Histogram) _plot; 110 String widthSpec = (String) _attributes.get("width"); 111 String offsetSpec = (String) _attributes.get("offset"); 112 113 // NOTE: If only one of these is given, then the other 114 // is ignored. 115 if (widthSpec != null && offsetSpec != null) { 116 double width = Double.valueOf(widthSpec).doubleValue(); 117 histogram.setBinWidth(width); 118 119 double offset = Double.valueOf(offsetSpec) 120 .doubleValue(); 121 histogram.setBinOffset(offset); 122 } 123 } 124 } else if (elementName.equals("dataset")) { 125 // Override the base class to ignore things irrelevant 126 // to histograms... 127 _currentDataset++; 128 _currentPointCount = 0.0; 129 130 String name = (String) _attributes.get("name"); 131 132 if (name != null) { 133 _plot.addLegend(_currentDataset, name); 134 } 135 } else if (elementName.equals("default")) { 136 // Override the base class to ignore things irrelevant 137 // to histograms... 138 } else { 139 super.startElement(elementName); 140 } 141 } catch (Exception ex) { 142 if (ex instanceof XmlException) { 143 throw (XmlException) ex; 144 } else { 145 String msg = "XML element \"" + elementName 146 + "\" triggers exception:\n " + ex.toString(); 147 throw new XmlException(msg, _currentExternalEntity(), 148 _parser.getLineNumber(), _parser.getColumnNumber()); 149 } 150 } 151 152 // NOTE: if super is called, this gets done three times... 153 // Any way to avoid it? 154 _attributes.clear(); 155 } 156 157 /////////////////////////////////////////////////////////////////// 158 //// protected methods //// 159 160 /** Add a point based on the current attributes. 161 * The second argument is the element name, used for error reporting. 162 * @param connected Ignored. 163 * @param element The name of the element. 164 * @exception Exception if thrown whil parsing the y attribute. 165 */ 166 @Override 167 protected void _addPoint(boolean connected, String element) 168 throws Exception { 169 String ySpec = (String) _attributes.get("y"); 170 _checkForNull(ySpec, "No y value for element \"" + element + "\""); 171 172 // NOTE: Do not use parseDouble() to maintain Java 1.1 compatibility. 173 double y = Double.valueOf(ySpec).doubleValue(); 174 ((Histogram) _plot).addPoint(_currentDataset, y); 175 } 176}