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.woody.transformation;
018:
019: import java.util.LinkedList;
020:
021: import org.apache.cocoon.woody.Constants;
022: import org.apache.cocoon.xml.AbstractXMLPipe;
023: import org.apache.cocoon.xml.SaxBuffer;
024: import org.apache.cocoon.xml.XMLConsumer;
025: import org.xml.sax.Attributes;
026: import org.xml.sax.ContentHandler;
027: import org.xml.sax.Locator;
028: import org.xml.sax.SAXException;
029: import org.xml.sax.ext.LexicalHandler;
030: import org.xml.sax.helpers.AttributesImpl;
031:
032: // TODO: Reduce the Element creation and deletion churn by providing startElement
033: // and endElement methods which do not create or use Elements on the stack.
034: /*
035: * Base class for XMLPipe's. Allows the structure of the source code of
036: * the XMLPipe to match the structure of the data being transformed.
037: *
038: * @author Timothy Larson
039: * @version $Id: EffectPipe.java 433543 2006-08-22 06:22:54Z crossley $
040: */
041: public class EffectPipe extends AbstractXMLPipe {
042:
043: protected static final int EVENT_SET_DOCUMENT_LOCATOR = 0;
044: protected static final int EVENT_START_DOCUMENT = 1;
045: protected static final int EVENT_END_DOCUMENT = 2;
046: protected static final int EVENT_START_PREFIX_MAPPING = 3;
047: protected static final int EVENT_END_PREFIX_MAPPING = 4;
048: protected static final int EVENT_START_ELEMENT = 5;
049: protected static final int EVENT_END_ELEMENT = 6;
050: protected static final int EVENT_ELEMENT = 7;
051: protected static final int EVENT_CHARACTERS = 8;
052: protected static final int EVENT_IGNORABLE_WHITESPACE = 9;
053: protected static final int EVENT_PROCESSING_INSTRUCTION = 10;
054: protected static final int EVENT_SKIPPED_ENTITY = 11;
055: protected static final int EVENT_START_DTD = 12;
056: protected static final int EVENT_END_DTD = 13;
057: protected static final int EVENT_START_ENTITY = 14;
058: protected static final int EVENT_END_ENTITY = 15;
059: protected static final int EVENT_START_CDATA = 16;
060: protected static final int EVENT_END_CDATA = 17;
061: protected static final int EVENT_COMMENT = 18;
062:
063: protected class Element {
064: public String prefix;
065: public String uri;
066: public String loc;
067: public String raw;
068: public Attributes attrs;
069: public boolean mine;
070:
071: public Element() {
072: prefix = null;
073: uri = null;
074: loc = null;
075: raw = null;
076: attrs = Constants.EMPTY_ATTRS;
077: mine = true;
078: }
079:
080: public Element(String prefix, String uri) {
081: this .prefix = prefix;
082: this .uri = uri;
083: }
084:
085: public Element(String uri, String loc, String raw,
086: Attributes attrs) {
087: this .uri = uri;
088: this .loc = loc;
089: this .raw = raw;
090: this .attrs = Constants.EMPTY_ATTRS;
091: if (attrs == null) {
092: this .attrs = Constants.EMPTY_ATTRS;
093: mine = true;
094: } else {
095: this .attrs = attrs;
096: mine = false;
097: }
098: }
099:
100: public void addAttributes(Attributes attrs) {
101: if (attrs != null) {
102: if (mine == true) {
103: if (this .attrs == Constants.EMPTY_ATTRS) {
104: this .attrs = attrs;
105: mine = false;
106: } else {
107: ((AttributesImpl) this .attrs)
108: .setAttributes(attrs);
109: }
110: } else {
111: this .attrs = new AttributesImpl(this .attrs);
112: ((AttributesImpl) this .attrs).setAttributes(attrs);
113: mine = true;
114: }
115: }
116: }
117:
118: public void addAttribute(String uri, String loc, String raw,
119: String type, String value) {
120: if (!mine || attrs == Constants.EMPTY_ATTRS) {
121: attrs = new AttributesImpl(attrs);
122: mine = true;
123: }
124: ((AttributesImpl) attrs).addAttribute(uri, loc, raw, type,
125: value);
126: }
127:
128: public void addAttribute(String prefix, String uri, String loc,
129: String value) {
130: if (!mine || attrs == Constants.EMPTY_ATTRS) {
131: attrs = new AttributesImpl(attrs);
132: mine = true;
133: }
134: ((AttributesImpl) attrs).addAttribute(uri, loc, prefix
135: + ":" + loc, "CDATA", value);
136: }
137:
138: public void addAttribute(String loc, String value) {
139: if (!mine || attrs == Constants.EMPTY_ATTRS) {
140: attrs = new AttributesImpl(attrs);
141: mine = true;
142: }
143: ((AttributesImpl) attrs).addAttribute("", loc, loc,
144: "CDATA", value);
145: }
146:
147: public void claimAttributes() {
148: if (!mine) {
149: attrs = new AttributesImpl(attrs);
150: mine = true;
151: }
152: }
153: }
154:
155: protected abstract class Handler {
156: public abstract Handler process() throws SAXException;
157: }
158:
159: protected class NullHandler extends Handler {
160: public Handler process() throws SAXException {
161: return this ;
162: }
163: }
164:
165: protected class BufferHandler extends Handler {
166: public Handler process() throws SAXException {
167: switch (event) {
168: case EVENT_ELEMENT:
169: return this ;
170: default:
171: out.buffer();
172: return this ;
173: }
174: }
175: }
176:
177: protected class Output extends AbstractXMLPipe {
178: private LinkedList buffers = null;
179: private SaxBuffer saxBuffer = null;
180: private LinkedList elements = null;
181: protected Element element = null;
182:
183: public Output() {
184: elements = new LinkedList();
185: }
186:
187: public void startPrefixMapping() throws SAXException {
188: super .startPrefixMapping(input.prefix, input.uri);
189: }
190:
191: public void endPrefixMapping() throws SAXException {
192: super .endPrefixMapping(input.prefix);
193: }
194:
195: public void element(String prefix, String uri, String loc,
196: Attributes attrs) throws SAXException {
197: element = new Element(uri, loc, prefix + ":" + loc, attrs);
198: }
199:
200: public void element(String prefix, String uri, String loc)
201: throws SAXException {
202: element(prefix, uri, loc, null);
203: }
204:
205: public void element(String loc, Attributes attrs)
206: throws SAXException {
207: element = new Element("", loc, loc, attrs);
208: }
209:
210: public void element(String loc) throws SAXException {
211: element(loc, null);
212: }
213:
214: public void element() throws SAXException {
215: element = new Element(input.uri, input.loc, input.raw,
216: input.attrs);
217: }
218:
219: public void attribute(String prefix, String uri, String name,
220: String value) throws SAXException {
221: element.addAttribute(prefix, uri, name, value);
222: }
223:
224: public void attribute(String name, String value)
225: throws SAXException {
226: element.addAttribute(name, value);
227: }
228:
229: public void copyAttribute(String prefix, String uri, String name)
230: throws SAXException {
231: String value = null;
232: if (input.attrs != null
233: && (value = input.attrs.getValue(uri, name)) != null) {
234: attribute(prefix, uri, name, value);
235: } else {
236: throw new SAXException(
237: "Attribute \""
238: + name
239: + "\" cannot be copied because it does not exist.");
240: }
241: }
242:
243: public void attributes(Attributes attrs) throws SAXException {
244: element.addAttributes(attrs);
245: }
246:
247: public void attributes() throws SAXException {
248: attributes(input.attrs);
249: }
250:
251: public void startElement() throws SAXException {
252: if (element.attrs == null) {
253: element.attrs = Constants.EMPTY_ATTRS;
254: }
255: super .startElement(element.uri, element.loc, element.raw,
256: element.attrs);
257: elements.addFirst(element);
258: element = null;
259: }
260:
261: public void endElement() throws SAXException {
262: element = (Element) elements.removeFirst();
263: super .endElement(element.uri, element.loc, element.raw);
264: element = null;
265: }
266:
267: public void startElement(String uri, String loc, String raw,
268: Attributes attrs) throws SAXException {
269: super .startElement(uri, loc, raw, attrs);
270: }
271:
272: public void endElement(String uri, String loc, String raw)
273: throws SAXException {
274: super .endElement(uri, loc, raw);
275: }
276:
277: public void copy() throws SAXException {
278: switch (event) {
279: case EVENT_SET_DOCUMENT_LOCATOR:
280: this .setDocumentLocator(locator);
281: break;
282: case EVENT_START_DOCUMENT:
283: this .startDocument();
284: break;
285: case EVENT_END_DOCUMENT:
286: this .endDocument();
287: break;
288: case EVENT_START_PREFIX_MAPPING:
289: this .startPrefixMapping();
290: break;
291: case EVENT_END_PREFIX_MAPPING:
292: this .endPrefixMapping();
293: break;
294: case EVENT_START_ELEMENT:
295: this .element();
296: attributes();
297: startElement();
298: break;
299: case EVENT_END_ELEMENT:
300: this .endElement();
301: break;
302: case EVENT_CHARACTERS:
303: this .characters(c, start, len);
304: break;
305: case EVENT_IGNORABLE_WHITESPACE:
306: this .ignorableWhitespace(c, start, len);
307: break;
308: case EVENT_PROCESSING_INSTRUCTION:
309: this .processingInstruction(target, data);
310: break;
311: case EVENT_SKIPPED_ENTITY:
312: this .skippedEntity(name);
313: break;
314: case EVENT_START_DTD:
315: this .startDTD(name, publicId, systemId);
316: break;
317: case EVENT_END_DTD:
318: this .endDTD();
319: break;
320: case EVENT_START_ENTITY:
321: this .startEntity(name);
322: break;
323: case EVENT_END_ENTITY:
324: this .endEntity(name);
325: break;
326: case EVENT_START_CDATA:
327: this .startCDATA();
328: break;
329: case EVENT_END_CDATA:
330: this .endCDATA();
331: break;
332: case EVENT_COMMENT:
333: this .comment(c, start, len);
334: break;
335: }
336: }
337:
338: protected void bufferInit() {
339: if (saxBuffer != null) {
340: if (buffers == null) {
341: buffers = new LinkedList();
342: }
343: buffers.addFirst(saxBuffer);
344: }
345: saxBuffer = new SaxBuffer();
346: }
347:
348: protected void bufferFini() {
349: if (buffers != null && buffers.size() > 0) {
350: saxBuffer = (SaxBuffer) buffers.removeFirst();
351: } else {
352: saxBuffer = null;
353: }
354: }
355:
356: protected SaxBuffer getBuffer() {
357: return saxBuffer;
358: }
359:
360: public void buffer() throws SAXException {
361: switch (event) {
362: case EVENT_SET_DOCUMENT_LOCATOR:
363: saxBuffer.setDocumentLocator(locator);
364: break;
365: case EVENT_START_DOCUMENT:
366: saxBuffer.startDocument();
367: break;
368: case EVENT_END_DOCUMENT:
369: saxBuffer.endDocument();
370: break;
371: case EVENT_START_PREFIX_MAPPING:
372: saxBuffer.startPrefixMapping(prefix, uri);
373: break;
374: case EVENT_END_PREFIX_MAPPING:
375: saxBuffer.endPrefixMapping(prefix);
376: break;
377: case EVENT_START_ELEMENT:
378: saxBuffer.startElement(input.uri, input.loc, input.raw,
379: input.attrs);
380: break;
381: case EVENT_END_ELEMENT:
382: saxBuffer.endElement(input.uri, input.loc, input.raw);
383: break;
384: case EVENT_CHARACTERS:
385: saxBuffer.characters(c, start, len);
386: break;
387: case EVENT_IGNORABLE_WHITESPACE:
388: saxBuffer.ignorableWhitespace(c, start, len);
389: break;
390: case EVENT_PROCESSING_INSTRUCTION:
391: saxBuffer.processingInstruction(target, data);
392: break;
393: case EVENT_SKIPPED_ENTITY:
394: saxBuffer.skippedEntity(name);
395: break;
396: case EVENT_START_DTD:
397: saxBuffer.startDTD(name, publicId, systemId);
398: break;
399: case EVENT_END_DTD:
400: saxBuffer.endDTD();
401: break;
402: case EVENT_START_ENTITY:
403: saxBuffer.startEntity(name);
404: break;
405: case EVENT_END_ENTITY:
406: saxBuffer.endEntity(name);
407: break;
408: case EVENT_START_CDATA:
409: saxBuffer.startCDATA();
410: break;
411: case EVENT_END_CDATA:
412: saxBuffer.endCDATA();
413: break;
414: case EVENT_COMMENT:
415: saxBuffer.comment(c, start, len);
416: break;
417: }
418: }
419: }
420:
421: protected int event = 0;
422:
423: protected Handler nullHandler = new NullHandler();
424: protected Handler bufferHandler = new BufferHandler();
425:
426: protected LinkedList handlers = null;
427: protected Handler handler = null;
428:
429: protected LinkedList elements = null;
430: protected Element input = null;
431:
432: protected Locator locator = null;
433: protected String name = null;
434: protected String publicId = null;
435: protected String systemId = null;
436: protected String target = null;
437: protected String data = null;
438: protected String prefix = null;
439: protected String uri = null;
440: protected char c[] = null;
441: protected int start = 0;
442: protected int len = 0;
443:
444: public Output out = null;
445:
446: public void init() {
447: handlers = new LinkedList();
448: elements = new LinkedList();
449: out = new Output();
450: }
451:
452: //====================================
453: // Methods overriding AbstractXMLPipe
454: //====================================
455:
456: public void setConsumer(XMLConsumer consumer) {
457: super .setConsumer(consumer);
458: out.setConsumer(consumer);
459: }
460:
461: public void setContentHandler(ContentHandler handler) {
462: super .setContentHandler(handler);
463: out.setContentHandler(handler);
464: }
465:
466: public void setLexicalHandler(LexicalHandler handler) {
467: super .setLexicalHandler(handler);
468: out.setLexicalHandler(handler);
469: }
470:
471: public void recycle() {
472: super .recycle();
473: handlers = null;
474: elements = null;
475: out = null;
476: }
477:
478: public void setDocumentLocator(Locator locator) {
479: this .locator = locator;
480: try {
481: event = EVENT_SET_DOCUMENT_LOCATOR;
482: handler = handler.process();
483: } catch (Exception e) {
484: throw new RuntimeException(e.getMessage());
485: }
486: }
487:
488: public void startDocument() throws SAXException {
489: event = EVENT_START_DOCUMENT;
490: handler = handler.process();
491: }
492:
493: public void endDocument() throws SAXException {
494: event = EVENT_END_DOCUMENT;
495: handler = handler.process();
496: }
497:
498: public void startPrefixMapping(String prefix, String uri)
499: throws SAXException {
500: input = new Element(prefix, uri);
501: elements.addFirst(input);
502: //this.prefix = prefix; this.uri = uri;
503: event = EVENT_START_PREFIX_MAPPING;
504: handler = handler.process();
505: }
506:
507: public void endPrefixMapping(String prefix) throws SAXException {
508: input = (Element) elements.removeFirst();
509: //this.prefix = prefix;
510: event = EVENT_END_PREFIX_MAPPING;
511: handler = handler.process();
512: input = null;
513: }
514:
515: public void startElement(String uri, String loc, String raw,
516: Attributes attrs) throws SAXException {
517: input = new Element(uri, loc, raw, attrs);
518: elements.addFirst(input);
519: handlers.addFirst(handler);
520: event = EVENT_ELEMENT;
521: handler = handler.process();
522: event = EVENT_START_ELEMENT;
523: handler = handler.process();
524: }
525:
526: public void endElement(String uri, String loc, String raw)
527: throws SAXException {
528: input = (Element) elements.removeFirst();
529: event = EVENT_END_ELEMENT;
530: handler.process();
531: handler = (Handler) handlers.removeFirst();
532: input = null;
533: }
534:
535: public void characters(char c[], int start, int len)
536: throws SAXException {
537: this .c = c;
538: this .start = start;
539: this .len = len;
540: event = EVENT_CHARACTERS;
541: handler = handler.process();
542: }
543:
544: public void ignorableWhitespace(char c[], int start, int len)
545: throws SAXException {
546: this .c = c;
547: this .start = start;
548: this .len = len;
549: event = EVENT_IGNORABLE_WHITESPACE;
550: handler = handler.process();
551: }
552:
553: public void processingInstruction(String target, String data)
554: throws SAXException {
555: this .target = target;
556: this .data = data;
557: event = EVENT_PROCESSING_INSTRUCTION;
558: handler = handler.process();
559: }
560:
561: public void skippedEntity(String name) throws SAXException {
562: this .name = name;
563: event = EVENT_SKIPPED_ENTITY;
564: handler = handler.process();
565: }
566:
567: public void startDTD(String name, String publicId, String systemId)
568: throws SAXException {
569: this .name = name;
570: this .publicId = publicId;
571: this .systemId = systemId;
572: event = EVENT_START_DTD;
573: handler = handler.process();
574: }
575:
576: public void endDTD() throws SAXException {
577: event = EVENT_END_DTD;
578: handler = handler.process();
579: }
580:
581: public void startEntity(String name) throws SAXException {
582: this .name = name;
583: event = EVENT_START_ENTITY;
584: handler = handler.process();
585: }
586:
587: public void endEntity(String name) throws SAXException {
588: this .name = name;
589: event = EVENT_END_ENTITY;
590: handler = handler.process();
591: }
592:
593: public void startCDATA() throws SAXException {
594: event = EVENT_START_CDATA;
595: handler = handler.process();
596: }
597:
598: public void endCDATA() throws SAXException {
599: event = EVENT_END_CDATA;
600: handler = handler.process();
601: }
602:
603: public void comment(char c[], int start, int len)
604: throws SAXException {
605: this.c = c;
606: this.start = start;
607: this.len = len;
608: event = EVENT_COMMENT;
609: handler = handler.process();
610: }
611: }
|