| /* |
| * 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.template.xml; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.apache.cocoon.xml.XMLConsumer; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.Locator; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| import org.xml.sax.helpers.AttributesImpl; |
| |
| /** |
| * @version $Id$ |
| */ |
| public class AttributeAwareXMLConsumerImpl implements AttributeAwareXMLConsumer { |
| |
| private StartElement currentElement; |
| private List saxbits; |
| private Locator locator; |
| |
| private XMLConsumer delegate; |
| |
| public AttributeAwareXMLConsumerImpl(XMLConsumer consumer) { |
| this.delegate = consumer; |
| this.saxbits = new ArrayList(); |
| } |
| |
| public void setDocumentLocator(Locator locator) { |
| this.locator = locator; |
| delegate.setDocumentLocator(locator); |
| } |
| |
| public void startDocument() throws SAXException { |
| delegate.startDocument(); |
| } |
| |
| public void endDocument() throws SAXException { |
| playCache(); |
| delegate.endDocument(); |
| } |
| |
| public void startPrefixMapping(String prefix, String uri) |
| throws SAXException { |
| playCache(); |
| delegate.startPrefixMapping(prefix, uri); |
| } |
| |
| public void endPrefixMapping(String prefix) throws SAXException { |
| playCache(); |
| delegate.endPrefixMapping(prefix); |
| } |
| |
| public void startElement(String namespaceURI, String localName, |
| String qName, Attributes attrs) throws SAXException { |
| playCache(); |
| this.currentElement = new StartElement(namespaceURI, localName, qName, |
| attrs); |
| } |
| |
| public void endElement(String namespaceURI, String localName, String qName) |
| throws SAXException { |
| playCache(); |
| delegate.endElement(namespaceURI, localName, qName); |
| } |
| |
| public void characters(char[] ch, int start, int length) |
| throws SAXException { |
| // TODO: should we allow to emit characters before adding an attribute? |
| if (this.currentElement != null) |
| this.saxbits.add(new Characters(ch, start, length)); |
| else |
| delegate.characters(ch, start, length); |
| |
| } |
| |
| public void ignorableWhitespace(char[] ch, int start, int length) |
| throws SAXException { |
| if (this.currentElement != null) |
| this.saxbits.add(new IgnorableWhitespace(ch, start, length)); |
| else |
| delegate.ignorableWhitespace(ch, start, length); |
| } |
| |
| public void processingInstruction(String target, String data) |
| throws SAXException { |
| playCache(); |
| delegate.processingInstruction(target, data); |
| } |
| |
| public void skippedEntity(String name) throws SAXException { |
| playCache(); |
| delegate.skippedEntity(name); |
| } |
| |
| public void startDTD(String name, String publicId, String systemId) |
| throws SAXException { |
| playCache(); |
| delegate.startDTD(name, publicId, systemId); |
| } |
| |
| public void endDTD() throws SAXException { |
| playCache(); |
| delegate.endDTD(); |
| } |
| |
| public void startEntity(String name) throws SAXException { |
| playCache(); |
| delegate.startEntity(name); |
| } |
| |
| public void endEntity(String name) throws SAXException { |
| playCache(); |
| delegate.endEntity(name); |
| } |
| |
| public void startCDATA() throws SAXException { |
| playCache(); |
| delegate.startCDATA(); |
| } |
| |
| public void endCDATA() throws SAXException { |
| playCache(); |
| delegate.endCDATA(); |
| } |
| |
| public void comment(char[] ch, int start, int length) throws SAXException { |
| playCache(); |
| delegate.comment(ch, start, length); |
| } |
| |
| public void attribute(String uri, String localName, String qName, |
| String type, String value) throws SAXException { |
| if (this.currentElement == null) |
| throw new SAXParseException("attribute event not allowed here", |
| this.locator); |
| else { |
| this.currentElement.attribute(uri, localName, qName, type, value); |
| // if between currentElement and jx:attribute only whitespace |
| // was recorded - skip it |
| boolean whitespaceOnly = true; |
| Iterator it = this.saxbits.iterator(); |
| while (it.hasNext()) { |
| SaxBit saxBit = (SaxBit) it.next(); |
| if (!(saxBit instanceof IgnorableWhitespace)) |
| whitespaceOnly = false; |
| } |
| if (whitespaceOnly) |
| this.saxbits.clear(); |
| } |
| } |
| |
| interface SaxBit { |
| public void send(ContentHandler contentHandler) throws SAXException; |
| } |
| |
| private class StartElement implements SaxBit { |
| private String namespaceURI; |
| private String localName; |
| private String qName; |
| private AttributesImpl attrs; |
| |
| public StartElement(String namespaceURI, String localName, |
| String qName, Attributes attrs) { |
| this.namespaceURI = namespaceURI; |
| this.localName = localName; |
| this.qName = qName; |
| this.attrs = new AttributesImpl(attrs); |
| } |
| |
| public void send(ContentHandler contentHandler) throws SAXException { |
| contentHandler.startElement(this.namespaceURI, this.localName, |
| this.qName, this.attrs); |
| } |
| |
| public void attribute(String uri, String localName, String qName, |
| String type, String value) { |
| this.attrs.addAttribute(uri, localName, qName, type, value); |
| } |
| } |
| |
| public final static class Characters implements SaxBit { |
| public final char[] ch; |
| |
| public Characters(char[] ch, int start, int length) { |
| this.ch = new char[length]; |
| System.arraycopy(ch, start, this.ch, 0, length); |
| } |
| |
| public void send(ContentHandler contentHandler) throws SAXException { |
| contentHandler.characters(ch, 0, ch.length); |
| } |
| } |
| |
| public final static class IgnorableWhitespace implements SaxBit { |
| public final char[] ch; |
| |
| public IgnorableWhitespace(char[] ch, int start, int length) { |
| this.ch = new char[length]; |
| System.arraycopy(ch, start, this.ch, 0, length); |
| } |
| |
| public void send(ContentHandler contentHandler) throws SAXException { |
| contentHandler.ignorableWhitespace(ch, 0, ch.length); |
| } |
| } |
| |
| public void playCache() throws SAXException { |
| if (this.currentElement != null) { |
| this.currentElement.send(delegate); |
| this.currentElement = null; |
| } |
| |
| Iterator it = this.saxbits.iterator(); |
| while (it.hasNext()) { |
| SaxBit saxBit = (SaxBit) it.next(); |
| saxBit.send(delegate); |
| } |
| this.saxbits.clear(); |
| } |
| } |