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.components.xscript;
018:
019: import org.xml.sax.Attributes;
020: import org.xml.sax.SAXException;
021: import org.xml.sax.helpers.DefaultHandler;
022:
023: import java.util.Stack;
024:
025: /**
026: * A <code>ContentHandler</code> that accumulates the SAX stream into
027: * a <code>StringBuffer</code> object.
028: *
029: * @author <a href="mailto:ovidiu@cup.hp.com">Ovidiu Predescu</a>
030: * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
031: * @version CVS $Id: StringBufferContentHandler.java 433543 2006-08-22 06:22:54Z crossley $
032: * @since August 30, 2001
033: */
034: public class StringBufferContentHandler extends DefaultHandler {
035: private static Object marker = new Object();
036:
037: private Stack namespaces = new Stack();
038: private StringBuffer stringBuffer;
039:
040: public StringBufferContentHandler(StringBuffer stringBuffer) {
041: this .stringBuffer = stringBuffer;
042: }
043:
044: public void startPrefixMapping(String prefix, String uri)
045: throws SAXException {
046: namespaces.push(new NPU(prefix, uri));
047: }
048:
049: public void endPrefixMapping(String prefix) throws SAXException {
050: namespaces.pop();
051: }
052:
053: public void startElement(String uri, String loc, String qName,
054: Attributes a) throws SAXException {
055: int lastNamespaceIndex = 0;
056:
057: lastNamespaceIndex = namespaces.size() - 1;
058: while (lastNamespaceIndex >= 0
059: && namespaces.elementAt(lastNamespaceIndex) != marker) {
060: lastNamespaceIndex--;
061: }
062:
063: if (lastNamespaceIndex < 0) {
064: lastNamespaceIndex = 0;
065: } else if (namespaces.elementAt(lastNamespaceIndex) == marker) {
066: lastNamespaceIndex++;
067: }
068:
069: namespaces.push(marker);
070: stringBuffer.append("<").append(qName);
071:
072: for (int i = 0, len = a.getLength(); i < len; i++) {
073: // Check if the attribute is a namespace declaration. Some
074: // parsers (Xerces) sometimes pass the namespace declaration
075: // as an attribute. We need to catch this case so that we
076: // don't end up generating the namespace declaration twice.
077: String attrName = a.getQName(i);
078: if (attrName.startsWith("xmlns:")) {
079: // We have a namespace declaration
080: String name = a.getLocalName(i);
081:
082: // Check whether this namespace has been already declared
083: boolean found = false;
084: for (int j = namespaces.size() - 1; j >= lastNamespaceIndex; j--) {
085: Object obj = namespaces.elementAt(j);
086: if (obj == marker) {
087: continue;
088: }
089: NPU npu = (NPU) obj;
090:
091: if (name.equals(npu.prefix)) {
092: found = true;
093: break;
094: }
095: }
096:
097: if (!found) {
098: namespaces.push(new NPU(name, a.getValue(i)));
099: }
100: } else {
101: // Normal attribute
102: stringBuffer.append(" ").append(a.getQName(i)).append(
103: "=\"");
104: escape(stringBuffer, a.getValue(i));
105: stringBuffer.append("\"");
106: }
107: }
108:
109: if (namespaces.size() != 0) {
110: for (int i = namespaces.size() - 1; i >= lastNamespaceIndex; i--) {
111: Object obj = namespaces.elementAt(i);
112: if (obj == marker) {
113: continue;
114: }
115: NPU npu = (NPU) obj;
116: if ("".equals(npu.prefix)) {
117: // Default namespace
118: stringBuffer.append(" xmlns").append("=\"").append(
119: npu.uri).append("\"");
120: } else {
121: stringBuffer.append(" xmlns:").append(npu.prefix)
122: .append("=\"").append(npu.uri).append("\"");
123: }
124: }
125: }
126:
127: stringBuffer.append(">");
128: }
129:
130: public void endElement(String uri, String loc, String qName)
131: throws SAXException {
132: stringBuffer.append("</").append(qName).append(">");
133:
134: Object obj;
135: do {
136: obj = namespaces.pop();
137: } while (obj != marker);
138: }
139:
140: public void characters(char ch[], int start, int len)
141: throws SAXException {
142: escape(stringBuffer, ch, start, len);
143: }
144:
145: /**
146: * Copies string into buffer and
147: * escapes all '<', '&' and '>' chars in the string with
148: * corresponding entities.
149: */
150: private static void escape(StringBuffer buffer, String s) {
151: char[] ch = s.toCharArray();
152: escape(buffer, ch, 0, ch.length);
153: }
154:
155: /**
156: * Copies characters from the char array into buffer and
157: * escapes all '<', '&' and '>' chars with corresponding
158: * entities.
159: */
160: private static void escape(StringBuffer buffer, char ch[],
161: int start, int len) {
162: for (int i = start; i < start + len; i++) {
163: switch (ch[i]) {
164: case '<':
165: buffer.append("<");
166: break;
167: case '&':
168: buffer.append("&");
169: break;
170: case '>':
171: buffer.append(">");
172: break;
173: default:
174: buffer.append(ch[i]);
175: break;
176: }
177: }
178: }
179: }
180:
181: class NPU {
182: public String prefix;
183: public String uri;
184:
185: NPU(String prefix, String uri) {
186: this .prefix = prefix;
187: this .uri = uri;
188: }
189:
190: public String toString() {
191: return this .prefix + "=" + this.uri;
192: }
193: }
|