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.transformation.helpers;
018:
019: import java.util.Map;
020: import java.util.StringTokenizer;
021:
022: import org.apache.avalon.framework.configuration.SAXConfigurationHandler;
023: import org.xml.sax.Attributes;
024: import org.xml.sax.SAXException;
025: import org.xml.sax.helpers.AttributesImpl;
026:
027: /**
028: * A SAX ContentHandler that builds Avalon <code>Configuration</code> objects,
029: * but also replaces variables of the form {var} with values from a map.
030: *
031: * @see VariableConfiguration
032: * @author <a href="jefft@apache.org">Jeff Turner</a>
033: * @version CVS $Id: InterpolatingConfigurationHandler.java 433543 2006-08-22 06:22:54Z crossley $
034: */
035: public class InterpolatingConfigurationHandler extends
036: SAXConfigurationHandler {
037: final private Map vars;
038: final private String location;
039:
040: /** Constructor.
041: * @param vars The mappings from variable name to value.
042: */
043: public InterpolatingConfigurationHandler(Map vars) {
044: this .vars = vars;
045: this .location = "Unknown";
046: }
047:
048: /** Constructor.
049: * @param vars The mappings from variable name to value.
050: * @param location The origin of this configuration info.
051: */
052: public InterpolatingConfigurationHandler(Map vars, String location) {
053: this .vars = vars;
054: this .location = location;
055: }
056:
057: /** Replace {vars} in attributes. */
058: public void startElement(String uri, String localName,
059: String qName, Attributes attr) throws SAXException {
060: AttributesImpl newAttr = new AttributesImpl(attr);
061: for (int i = 0; i < attr.getLength(); i++) {
062: newAttr.setValue(i, interp(attr.getValue(i)));
063: }
064: super .startElement(uri, localName, qName, newAttr);
065: }
066:
067: /** Replace {vars} in element bodies. */
068: public void characters(final char[] ch, int start, int len)
069: throws SAXException {
070: StringBuffer buf = new StringBuffer();
071: if (start != 0)
072: buf.append(ch, 0, start - 1);
073: String newVal = interp(new String(ch, start, len));
074: buf.append(newVal);
075: buf.append(ch, start + len, ch.length - (start + len));
076: super .characters(buf.toString().toCharArray(), start, newVal
077: .length());
078: }
079:
080: protected String getLocationString() {
081: return this .location;
082: }
083:
084: /**
085: * Interpolate variable values into a string.
086: *
087: * @param str String with {var} tokens
088: * @return <code>str</code>, with {variables} replaced by values. If an
089: * unknown variable token is encountered it is ignored.
090: */
091: private String interp(String str) {
092: StringBuffer buf = new StringBuffer(str.length() * 2);
093: StringTokenizer tok = new StringTokenizer(str, "{}", true);
094: int state = 0; // 0=outside, 1=inside
095: while (tok.hasMoreTokens()) {
096: String token = tok.nextToken();
097: if (state == 0 && "{".equals(token)) {
098: state = 1;
099: } else if (state == 1 && "}".equals(token)) {
100: state = 0;
101: } else if (state == 0) {
102: buf.append(token);
103: } else if (state == 1) {
104: //System.out.println("Replacing "+token+" with "+vars.get(token));
105: String val = (String) vars.get(token);
106: if (val == null) {
107: buf.append("{").append(token).append("}");
108: } else {
109: buf.append(val);
110: }
111: }
112: }
113: return buf.toString();
114: }
115:
116: }
|