001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.template.script;
018:
019: import java.util.Stack;
020:
021: import org.apache.cocoon.template.JXTemplateGenerator;
022: import org.apache.cocoon.template.environment.ParsingContext;
023: import org.apache.cocoon.template.instruction.Instruction;
024: import org.apache.cocoon.template.script.event.*;
025: import org.apache.commons.lang.StringUtils;
026: import org.xml.sax.Attributes;
027: import org.xml.sax.ContentHandler;
028: import org.xml.sax.Locator;
029: import org.xml.sax.SAXException;
030: import org.xml.sax.ext.LexicalHandler;
031: import org.xml.sax.helpers.AttributesImpl;
032: import org.xml.sax.helpers.LocatorImpl;
033:
034: /**
035: * @version $Id: Parser.java 449189 2006-09-23 06:52:29Z crossley $
036: */
037: public class Parser implements ContentHandler, LexicalHandler {
038: StartDocument startEvent;
039: Event lastEvent;
040: Stack stack = new Stack();
041: Locator locator;
042: Locator charLocation;
043: StringBuffer charBuf;
044:
045: public static final Locator NULL_LOCATOR = new LocatorImpl();
046: protected ParsingContext parsingContext;
047:
048: public Parser() {
049: }
050:
051: public Parser(ParsingContext parsingContext) {
052: this .parsingContext = parsingContext;
053: }
054:
055: public void setParsingContext(ParsingContext parsingContext) {
056: this .parsingContext = parsingContext;
057: }
058:
059: public StartDocument getStartEvent() {
060: return this .startEvent;
061: }
062:
063: protected void recycle() {
064: startEvent = null;
065: lastEvent = null;
066: stack.clear();
067: locator = null;
068: charLocation = null;
069: charBuf = null;
070: }
071:
072: private void addEvent(Event ev) throws SAXException {
073: if (ev != null) {
074: if (lastEvent == null) {
075: lastEvent = startEvent = new StartDocument(locator);
076: } else {
077: flushChars();
078: }
079: lastEvent.setNext(ev);
080: lastEvent = ev;
081: } else {
082: throw new NullPointerException("null event");
083: }
084: }
085:
086: void flushChars() throws SAXException {
087: if (charBuf != null) {
088: char[] chars = new char[charBuf.length()];
089: charBuf.getChars(0, charBuf.length(), chars, 0);
090: Characters ev = new Characters(this .parsingContext,
091: charLocation, chars, 0, chars.length);
092: lastEvent.setNext(ev);
093: lastEvent = ev;
094: charLocation = null;
095: charBuf = null;
096: }
097: }
098:
099: public void characters(char[] ch, int start, int length)
100: throws SAXException {
101: if (charBuf == null) {
102: charBuf = new StringBuffer(length);
103: charLocation = locator != null ? new LocatorImpl(locator)
104: : NULL_LOCATOR;
105: }
106: charBuf.append(ch, start, length);
107: }
108:
109: public void endDocument() throws SAXException {
110: StartDocument startDoc = (StartDocument) stack.pop();
111: EndDocument endDoc = new EndDocument(locator);
112: startDoc.setEndDocument(endDoc);
113: addEvent(endDoc);
114: }
115:
116: public void endElement(String namespaceURI, String localName,
117: String raw) throws SAXException {
118: Event start = (Event) stack.pop();
119: Event newEvent = null;
120: if (start instanceof Instruction) {
121: Instruction startInstruction = (Instruction) start;
122: EndInstruction endInstruction = new EndInstruction(locator,
123: startInstruction);
124: newEvent = endInstruction;
125: addEvent(newEvent);
126: startInstruction.endNotify();
127: } else {
128: StartElement startElement = (StartElement) start;
129: newEvent = new EndElement(locator, startElement);
130: startElement.setEndElement((EndElement) newEvent);
131: addEvent(newEvent);
132: }
133: }
134:
135: public void endPrefixMapping(String prefix) throws SAXException {
136: EndPrefixMapping endPrefixMapping = new EndPrefixMapping(
137: locator, prefix);
138: addEvent(endPrefixMapping);
139: }
140:
141: public void ignorableWhitespace(char[] ch, int start, int length)
142: throws SAXException {
143: Event ev = new IgnorableWhitespace(this .parsingContext,
144: locator, ch, start, length);
145: addEvent(ev);
146: }
147:
148: public void processingInstruction(String target, String data)
149: throws SAXException {
150: Event pi = new ProcessingInstruction(locator, target, data);
151: addEvent(pi);
152: }
153:
154: public void setDocumentLocator(Locator locator) {
155: this .locator = locator;
156: }
157:
158: public void skippedEntity(String name) throws SAXException {
159: addEvent(new SkippedEntity(locator, name));
160: }
161:
162: public void startDocument() {
163: startEvent = new StartDocument(locator);
164: lastEvent = startEvent;
165: stack.push(lastEvent);
166: }
167:
168: public void startElement(String namespaceURI, String localName,
169: String qname, Attributes attrs) throws SAXException {
170: Event newEvent = null;
171: AttributesImpl elementAttributes = new AttributesImpl(attrs);
172: int attributeCount = elementAttributes.getLength();
173: for (int i = 0; i < attributeCount; i++) {
174: String attributeURI = elementAttributes.getURI(i);
175: if (StringUtils
176: .equals(attributeURI, JXTemplateGenerator.NS)) {
177: // TODO: template properties should be allowed only on template
178: // root
179: getStartEvent().getTemplateProperties().put(
180: elementAttributes.getLocalName(i),
181: this .parsingContext.getStringTemplateParser()
182: .compileExpr(
183: elementAttributes.getValue(i),
184: null, locator));
185: elementAttributes.removeAttribute(i--);
186: }
187: }
188: StartElement startElement = new StartElement(
189: this .parsingContext, locator, namespaceURI, localName,
190: qname, elementAttributes);
191: InstructionFactory instructionFactory = this .parsingContext
192: .getInstructionFactory();
193: if (instructionFactory.isInstruction(startElement))
194: newEvent = instructionFactory.createInstruction(
195: this .parsingContext, startElement, attrs, stack);
196: else
197: newEvent = startElement;
198: stack.push(newEvent);
199: addEvent(newEvent);
200: }
201:
202: public void startPrefixMapping(String prefix, String uri)
203: throws SAXException {
204: addEvent(new StartPrefixMapping(locator, prefix, uri));
205: }
206:
207: public void comment(char ch[], int start, int length)
208: throws SAXException {
209: // DO NOTHING
210: }
211:
212: public void endCDATA() throws SAXException {
213: addEvent(new EndCDATA(locator));
214: }
215:
216: public void endDTD() throws SAXException {
217: addEvent(new EndDTD(locator));
218: }
219:
220: public void endEntity(String name) throws SAXException {
221: addEvent(new EndEntity(locator, name));
222: }
223:
224: public void startCDATA() throws SAXException {
225: addEvent(new StartCDATA(locator));
226: }
227:
228: public void startDTD(String name, String publicId, String systemId)
229: throws SAXException {
230: addEvent(new StartDTD(locator, name, publicId, systemId));
231: }
232:
233: public void startEntity(String name) throws SAXException {
234: addEvent(new StartEntity(locator, name));
235: }
236: }
|