/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.xml; import java.util.Iterator; import java.util.Map; import java.io.Writer; import java.io.IOException; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.Attributes; /** * Modification of the SAX buffer with parameterization capabilities. * * Any <code>{name}</code> expression inside of the character events can be * replaced by the content of another SaxBuffer if it is present in the map * passed to the {@link #toSAX(ContentHandler, Map)} method. * * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a> * @version CVS $Id$ */ public class ParamSaxBuffer extends SaxBuffer { /** * If ch (in characters()) contains an unmatched '{' then * we save the chars from '{' onward in previous_ch. * Next call to characters() prepends the saved chars to ch before processing * (and sets previous_ch to null). */ private char[] previous_ch = null; /** * Creates empty SaxBuffer */ public ParamSaxBuffer() { } /** * Creates copy of another SaxBuffer */ public ParamSaxBuffer(SaxBuffer saxBuffer) { super(saxBuffer); } /** * Parses text and extracts <code>{name}</code> parameters for later * substitution. * '{' is escaped with a preceding '\'. */ public void characters(char ch[], int start, int length) throws SAXException { if (previous_ch != null) { // prepend char's from previous_ch to ch char[] buf = new char[length + previous_ch.length]; System.arraycopy(previous_ch, 0, buf, 0, previous_ch.length); System.arraycopy(ch, start, buf, previous_ch.length, length); ch = buf; start = 0; length += previous_ch.length; previous_ch = null; } final int end = start + length; for (int i = start; i < end; i++) { if (ch[i] == '\\') { if (i + 1 == end) { // if '\' is the last char, flush chars and let's wait to see if a '{' or '\' will come next addBit(new Characters(ch, start, i - start)); previous_ch = new char[]{ch[i]}; return; } if (ch[i + 1] == '{' || ch[i + 1] == '\\') { // Encountered "\{" or "\\", meaning that the next char should be escaped addBit(new Characters(ch, start, i - start)); addBit(new Characters(new char[]{ch[i + 1]}, 0, 1)); i++; start = i + 1; continue; } } else if (ch[i] == '{') { // Send any collected characters so far if (i > start) { addBit(new Characters(ch, start, i - start)); } // Find closing brace, and construct parameter name StringBuffer name = new StringBuffer(); int j = i + 1; for (; j < end; j++) { if (ch[j] == '}') { break; } name.append(ch[j]); } if (j == end) { // '{' without a closing '}' // save char's from '{' in previous_ch in case the following call to characters() // provides the '}' previous_ch = new char[end - i]; System.arraycopy(ch, i, previous_ch, 0, end - i); return; } addBit(new Parameter(name.toString())); // Continue processing i = j; start = j + 1; continue; } } // Send any tailing characters if (start < end) { addBit(new Characters(ch, start, end - start)); } } public void endElement(String namespaceURI, String localName, String qName) throws SAXException { flushChars(); super.endElement(namespaceURI, localName, qName); } public void ignorableWhitespace(char ch[], int start, int length) throws SAXException { flushChars(); super.ignorableWhitespace(ch, start, length); } public void processingInstruction(String target, String data) throws SAXException { flushChars(); super.processingInstruction(target, data); } public void startDocument() throws SAXException { flushChars(); super.startDocument(); } public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { flushChars(); super.startElement(namespaceURI, localName, qName, atts); } public void endDocument() throws SAXException { flushChars(); super.endDocument(); } public void comment(char ch[], int start, int length) throws SAXException { flushChars(); super.comment(ch, start, length); } public void endDTD() throws SAXException { flushChars(); super.endDTD(); } public void startDTD(String name, String publicId, String systemId) throws SAXException { flushChars(); super.startDTD(name, publicId, systemId); } private void flushChars() { // Handle saved chars (in case we had a '{' with no matching '}'). if (previous_ch != null) { addBit(new Characters(previous_ch, 0, previous_ch.length)); previous_ch = null; } } /** * @param parameters map containing SaxBuffers */ public void toSAX(ContentHandler contentHandler, Map parameters) throws SAXException { for (Iterator i = bits(); i.hasNext();) { SaxBit saxbit = (SaxBit)i.next(); if (saxbit instanceof Parameter) { ((Parameter)saxbit).send(contentHandler, parameters); } else { saxbit.send(contentHandler); } } } /** * @param parameters map containing SaxBuffers */ public String toString(Map parameters) throws SAXException { final StringBuffer buffer = new StringBuffer(); for (Iterator i = bits(); i.hasNext();) { SaxBit saxbit = (SaxBit)i.next(); if (saxbit instanceof Parameter) { ((Parameter)saxbit).toString(buffer, parameters); } else if (saxbit instanceof Characters) { ((Characters) saxbit).toString(buffer); } } return buffer.toString(); } final static class Parameter implements SaxBit { private final String name; public Parameter(String name) { this.name = name; } public void send(ContentHandler contentHandler) { } public void send(ContentHandler contentHandler, Map parameters) throws SAXException { SaxBuffer value = (SaxBuffer)parameters.get(name); if (value != null) { value.toSAX(contentHandler); } } public void toString(StringBuffer result, Map parameters) throws SAXException { String value = (String)parameters.get(name); if (value != null) { result.append(value); } } public void dump(Writer writer) throws IOException { writer.write("[Parameter] name=" + name); } } }