001    /*
002     * Copyright 2002 - 2007 JEuclid, http://jeuclid.sf.net
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    /* $Id: SAXBuilder.java 422 2007-08-16 09:36:52Z maxberger $ */
018    
019    package net.sourceforge.jeuclid;
020    
021    import java.util.Stack;
022    
023    import net.sourceforge.jeuclid.elements.AbstractJEuclidElement;
024    import net.sourceforge.jeuclid.elements.JEuclidElementFactory;
025    import net.sourceforge.jeuclid.elements.generic.DocumentElement;
026    import net.sourceforge.jeuclid.elements.support.attributes.AttributeMap;
027    import net.sourceforge.jeuclid.elements.support.attributes.SAXAttributeMap;
028    
029    import org.w3c.dom.Node;
030    import org.w3c.dom.mathml.MathMLElement;
031    import org.xml.sax.Attributes;
032    import org.xml.sax.ContentHandler;
033    import org.xml.sax.Locator;
034    
035    /**
036     * Generator for creating a MathElement tree from SAX events.
037     * 
038     * @author <a href="mailto:stephan@vern.chem.tu-berlin.de">Stephan Michels</a>
039     * @author Max Berger
040     * @version $Revision: 422 $
041     */
042    public class SAXBuilder implements ContentHandler {
043        private DocumentElement rootElement;
044    
045        private final Stack<Node> stack = new Stack<Node>();;
046    
047        private final MathBase mbase;
048    
049        /**
050         * Logger for this class.
051         */
052        // unused
053        // private static final Log LOGGER =
054        // LogFactory.getLog(SAXMathBuilder.class);
055        /**
056         * default constructor.
057         */
058        public SAXBuilder() {
059            this.mbase = new MathBase(MathBase.getDefaultParameters());
060        }
061    
062        /**
063         * Returns the created math root element.
064         * 
065         * @return Math root element
066         */
067        public DocumentElement getMathRootElement() {
068            return this.rootElement;
069        }
070    
071        /**
072         * Receive notification of character data.
073         * 
074         * @param ch
075         *            The characters from the XML document.
076         * @param start
077         *            The start position in the array.
078         * @param length
079         *            The number of characters to read from the array.
080         */
081        public void characters(final char[] ch, final int start, final int length) {
082            if (!this.stack.empty()) {
083                ((AbstractJEuclidElement) this.stack.peek()).addText(new String(
084                        ch, start, length));
085            }
086        }
087    
088        /**
089         * Receive notification of the end of a document.
090         */
091        public void endDocument() {
092            this.rootElement.fireChangeForSubTree();
093        }
094    
095        /**
096         * Receive notification of the end of an element.
097         * 
098         * @param namespaceURI
099         *            The Namespace URI, or the empty string if the element has no
100         *            Namespace URI or if Namespace processing is not being
101         *            performed.
102         * @param localName
103         *            The local name (without prefix), or the empty string if
104         *            Namespace processing is not being performed.
105         * @param qName
106         *            The qualified XML 1.0 name (with prefix), or the empty
107         *            string if qualified names are not available.
108         */
109        public void endElement(final String namespaceURI, final String localName,
110                final String qName) {
111            if (!this.stack.empty()) {
112                this.stack.pop();
113    
114            }
115        }
116    
117        /**
118         * Receive notification of the beginning of a document.
119         */
120        public void startDocument() {
121            this.rootElement = null;
122            this.stack.clear();
123            this.rootElement = new DocumentElement(this.mbase);
124            this.mbase.setRootElement(this.rootElement);
125            this.stack.push(this.rootElement);
126        }
127    
128        /**
129         * Receive notification of the beginning of an element.
130         * 
131         * @param namespaceURI
132         *            The Namespace URI, or the empty string if the element has no
133         *            Namespace URI or if Namespace processing is not being
134         *            performed.
135         * @param localName
136         *            The local name (without prefix), or the empty string if
137         *            Namespace processing is not being performed.
138         * @param qName
139         *            The qualified name (with prefix), or the empty string if
140         *            qualified names are not available.
141         * @param attributes
142         *            The attributes attached to the element. If there are no
143         *            attributes, it shall be an empty Attributes object.
144         */
145        public void startElement(final String namespaceURI,
146                final String localName, final String qName,
147                final Attributes attributes) {
148            if (this.stack.empty()) {
149                return;
150            }
151    
152            final AttributeMap aMap = new SAXAttributeMap(attributes);
153            final MathMLElement element = JEuclidElementFactory.elementFromName(
154                    localName, aMap, this.mbase);
155    
156            if (!this.stack.empty()) {
157                this.stack.peek().appendChild(element);
158            }
159    
160            this.stack.push(element);
161        }
162    
163        /**
164         * End the scope of a prefix-URI mapping.
165         * 
166         * @param prefix
167         *            Prefix
168         */
169        public void endPrefixMapping(final String prefix) {
170        }
171    
172        /**
173         * Receive notification of ignorable whitespace in element content.
174         * 
175         * @param ch
176         *            Space char
177         * @param start
178         *            Start position
179         * @param length
180         *            Length
181         */
182        public void ignorableWhitespace(final char[] ch, final int start,
183                final int length) {
184        }
185    
186        /**
187         * Receive notification of a processing instruction.
188         * 
189         * @param target
190         *            Target
191         * @param data
192         *            Data
193         */
194        public void processingInstruction(final String target, final String data) {
195        }
196    
197        /**
198         * Receive an object for locating the origin of SAX document events.
199         * 
200         * @param locator
201         *            Locator
202         */
203        public void setDocumentLocator(final Locator locator) {
204        }
205    
206        /**
207         * Receive notification of a skipped entity.
208         * 
209         * @param name
210         *            Entity name
211         */
212        public void skippedEntity(final String name) {
213        }
214    
215        /**
216         * Begin the scope of a prefix-URI Namespace mapping.
217         * 
218         * @param prefix
219         *            Prefix
220         * @param uri
221         *            Uri
222         */
223        public void startPrefixMapping(final String prefix, final String uri) {
224        }
225    
226    }