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.xml;
018:
019: import java.util.Iterator;
020: import java.util.Map;
021: import java.io.Writer;
022: import java.io.IOException;
023:
024: import org.xml.sax.ContentHandler;
025: import org.xml.sax.SAXException;
026: import org.xml.sax.Attributes;
027:
028: /**
029: * Modification of the SAX buffer with parameterization capabilities.
030: *
031: * Any <code>{name}</code> expression inside of the character events can be
032: * replaced by the content of another SaxBuffer if it is present in the map
033: * passed to the {@link #toSAX(ContentHandler, Map)} method.
034: *
035: * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
036: * @version CVS $Id: ParamSaxBuffer.java 531552 2007-04-23 18:21:01Z jjohnston $
037: */
038: public class ParamSaxBuffer extends SaxBuffer {
039:
040: /**
041: * If ch (in characters()) contains an unmatched '{' then
042: * we save the chars from '{' onward in previous_ch.
043: * Next call to characters() prepends the saved chars to ch before processing
044: * (and sets previous_ch to null).
045: */
046: private char[] previous_ch = null;
047:
048: /**
049: * Creates empty SaxBuffer
050: */
051: public ParamSaxBuffer() {
052: }
053:
054: /**
055: * Creates copy of another SaxBuffer
056: */
057: public ParamSaxBuffer(SaxBuffer saxBuffer) {
058: super (saxBuffer);
059: }
060:
061: /**
062: * Parses text and extracts <code>{name}</code> parameters for later
063: * substitution.
064: */
065: public void characters(char ch[], int start, int length)
066: throws SAXException {
067:
068: if (previous_ch != null) {
069: // prepend char's from previous_ch to ch
070: char[] buf = new char[length + previous_ch.length];
071: System
072: .arraycopy(previous_ch, 0, buf, 0,
073: previous_ch.length);
074: System
075: .arraycopy(ch, start, buf, previous_ch.length,
076: length);
077: ch = buf;
078: start = 0;
079: length += previous_ch.length;
080: previous_ch = null;
081: }
082:
083: final int end = start + length;
084: for (int i = start; i < end; i++) {
085: if (ch[i] == '{') {
086: // Send any collected characters so far
087: if (i > start) {
088: addBit(new Characters(ch, start, i - start));
089: }
090:
091: // Find closing brace, and construct parameter name
092: StringBuffer name = new StringBuffer();
093: int j = i + 1;
094: for (; j < end; j++) {
095: if (ch[j] == '}') {
096: break;
097: }
098: name.append(ch[j]);
099: }
100: if (j == end) {
101: // '{' without a closing '}'
102: // save char's from '{' in previous_ch in case the following call to characters()
103: // provides the '}'
104: previous_ch = new char[end - i];
105: System.arraycopy(ch, i, previous_ch, 0, end - i);
106: return;
107: }
108: addBit(new Parameter(name.toString()));
109:
110: // Continue processing
111: i = j;
112: start = j + 1;
113: continue;
114: }
115: }
116:
117: // Send any tailing characters
118: if (start < end) {
119: addBit(new Characters(ch, start, end - start));
120: }
121: }
122:
123: public void endElement(String namespaceURI, String localName,
124: String qName) throws SAXException {
125: flushChars();
126: super .endElement(namespaceURI, localName, qName);
127: }
128:
129: public void ignorableWhitespace(char ch[], int start, int length)
130: throws SAXException {
131: flushChars();
132: super .ignorableWhitespace(ch, start, length);
133: }
134:
135: public void processingInstruction(String target, String data)
136: throws SAXException {
137: flushChars();
138: super .processingInstruction(target, data);
139: }
140:
141: public void startDocument() throws SAXException {
142: flushChars();
143: super .startDocument();
144: }
145:
146: public void startElement(String namespaceURI, String localName,
147: String qName, Attributes atts) throws SAXException {
148: flushChars();
149: super .startElement(namespaceURI, localName, qName, atts);
150: }
151:
152: public void endDocument() throws SAXException {
153: flushChars();
154: super .endDocument();
155: }
156:
157: public void comment(char ch[], int start, int length)
158: throws SAXException {
159: flushChars();
160: super .comment(ch, start, length);
161: }
162:
163: public void endDTD() throws SAXException {
164: flushChars();
165: super .endDTD();
166: }
167:
168: public void startDTD(String name, String publicId, String systemId)
169: throws SAXException {
170: flushChars();
171: super .startDTD(name, publicId, systemId);
172: }
173:
174: private void flushChars() {
175: // Handle saved chars (in case we had a '{' with no matching '}').
176: if (previous_ch != null) {
177: addBit(new Characters(previous_ch, 0, previous_ch.length));
178: previous_ch = null;
179: }
180: }
181:
182: /**
183: * @param parameters map containing SaxBuffers
184: */
185: public void toSAX(ContentHandler contentHandler, Map parameters)
186: throws SAXException {
187: for (Iterator i = bits(); i.hasNext();) {
188: SaxBit saxbit = (SaxBit) i.next();
189: if (saxbit instanceof Parameter) {
190: ((Parameter) saxbit).send(contentHandler, parameters);
191: } else {
192: saxbit.send(contentHandler);
193: }
194: }
195: }
196:
197: /**
198: * @param parameters map containing SaxBuffers
199: */
200: public String toString(Map parameters) throws SAXException {
201: final StringBuffer buffer = new StringBuffer();
202: for (Iterator i = bits(); i.hasNext();) {
203: SaxBit saxbit = (SaxBit) i.next();
204: if (saxbit instanceof Parameter) {
205: ((Parameter) saxbit).toString(buffer, parameters);
206: } else if (saxbit instanceof Characters) {
207: ((Characters) saxbit).toString(buffer);
208: }
209: }
210: return buffer.toString();
211: }
212:
213: final static class Parameter implements SaxBit {
214: private final String name;
215:
216: public Parameter(String name) {
217: this .name = name;
218: }
219:
220: public void send(ContentHandler contentHandler) {
221: }
222:
223: public void send(ContentHandler contentHandler, Map parameters)
224: throws SAXException {
225: SaxBuffer value = (SaxBuffer) parameters.get(name);
226: if (value != null) {
227: value.toSAX(contentHandler);
228: }
229: }
230:
231: public void toString(StringBuffer result, Map parameters)
232: throws SAXException {
233: String value = (String) parameters.get(name);
234: if (value != null) {
235: result.append(value);
236: }
237: }
238:
239: public void dump(Writer writer) throws IOException {
240: writer.write("[Parameter] name=" + name);
241: }
242: }
243: }
|