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 }