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 }