Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/LoggingEntityResolver.java URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/LoggingEntityResolver.java?rev=330548&view=auto ============================================================================== --- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/LoggingEntityResolver.java (added) +++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/LoggingEntityResolver.java Thu Nov 3 05:41:06 2005 @@ -0,0 +1,55 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed 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 org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * Logging entity resolver to assist in caching. + * + * @author Donald Ball + * @version CVS $Id: LoggingEntityResolver.java 30941 2004-07-29 19:56:58Z vgritsenko $ + */ +public class LoggingEntityResolver extends AbstractLogEnabled implements EntityResolver { + + protected EntityResolver resolver; + protected Set dependencies; + + public LoggingEntityResolver(EntityResolver resolver) { + this.resolver = resolver; + dependencies = new HashSet(); + } + + public InputSource resolveEntity(String public_id, String system_id) throws SAXException,IOException { + InputSource input_source = resolver.resolveEntity(public_id,system_id); + dependencies.add(input_source); + getLogger().debug("Dependency: "+input_source.getSystemId()); + return input_source; + } + + public Set getDependencies() { + return Collections.unmodifiableSet(dependencies); + } + +} Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/LoggingEntityResolver.java ------------------------------------------------------------------------------ svn:eol-style = native Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/NamespacesTable.java URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/NamespacesTable.java?rev=330548&view=auto ============================================================================== --- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/NamespacesTable.java (added) +++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/NamespacesTable.java Thu Nov 3 05:41:06 2005 @@ -0,0 +1,534 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed 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 org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +/** + * Keeps track of namespaces declarations and resolve namespaces names. + *
+ * This class also provides a very convenient and safe way of handling + * namespace declarations in SAX pipes. It also allows to filter duplicate namespace + * declarations that too often clutter up XML documents that went through + * several transformations, and avoid useless namespace declarations that aren't followed + * by element events. + *
+ * Usage example in a SAX pipe: + *
+ * NamespacesTable namespaces = new NamespacesTable(); + * ContentHandler nextHandler; + * + * public void startPrefixMapping(String prefix, String uri) throws SAXException { + * namespaces.addDeclaration(prefix, uri); + * } + * + * public void startElement(...) throws SAXException { + * // automatically start mappings for this scope + * namespaces.enterScope(nextHandler); + * nextHandler.startElement(...); + * } + * + * public void endElement(...) throws SAXException { + * nextHandler.endElement(...); + * // automatically end mappings for this scope + * namespaces.leaveScope(nextHandler); + * } + * + * public void endPrefixMapping(String prefix) throws SAXException { + * // Ignore, it is handled by leaveScope() + * } + *+ * + * @version $Id: NamespacesTable.java 233343 2005-08-18 18:06:44Z sylvain $ + */ +public class NamespacesTable { + /** The last namespace declaration. */ + private Entry lastEntry; + + /** The entry that start the prefix mappings for the scope that's about to be entered + * or was just left. + */ + private Entry lastDeclaredEntry; + + private boolean usesScopes = false; + + /** + * Construct a new
NamespacesTable
instance.
+ */
+ public NamespacesTable() {
+ clear();
+ }
+
+ /**
+ * Clear and reinitialize this namespace table before reuse.
+ *
+ * @since 2.1.8
+ */
+ public void clear() {
+ this.lastEntry = Entry.create("","");
+ this.addDeclaration("xml", "http://www.w3.org/XML/1998/namespace");
+ // Lock this scope
+ this.lastEntry.closedScopes = 1;
+ }
+
+ /**
+ * Declare a new namespace prefix-uri mapping.
+ *
+ * @return The newly added Declaration
.
+ */
+ public Declaration addDeclaration(String prefix, String uri) {
+ // Find a previous declaration of the same prefix
+ Entry dup = this.lastEntry;
+ while (dup != null && !dup.prefix.equals(prefix)) {
+ dup = dup.previous;
+ }
+
+ if (dup != null) {
+ if (usesScopes && dup.uri.equals(uri)) {
+ return dup;
+ }
+ dup.overriden = true;
+ }
+
+ Entry e = Entry.create(prefix, uri);
+ e.previous = this.lastEntry;
+ e.overrides = dup;
+ this.lastEntry = e;
+ // this always starts the declared prefix chain
+ this.lastDeclaredEntry = e;
+ return e;
+ }
+
+ /**
+ * Undeclare a namespace prefix-uri mapping. If the prefix was previously declared
+ * mapping another URI, its value is restored.
+ *
+ * When using {@link #enterScope()}/{@link #leaveScope()}, this method does nothing and always
+ * returns null
, as declaration removal is handled in {@link #leaveScope()}.
+ *
+ * @return the removed Declaration
or null.
+ */
+ public Declaration removeDeclaration(String prefix) {
+ if (usesScopes) {
+ // Automatically handled in leaveScope
+ return null; // or throw and IllegalStateException if enterScope(handler) was used?
+ }
+
+ Entry current = this.lastEntry;
+ Entry afterCurrent = null;
+ while(current != null) {
+ if (current.closedScopes > 0) {
+ // Don't undeclare mappings not declared in this scope
+ return null;
+ }
+
+ if (current.prefix.equals(prefix)) {
+ // Got it
+ // Remove it from the chain
+ if (afterCurrent != null) {
+ afterCurrent.previous = current.previous;
+ }
+ // And report closed scopes on the previous entry
+ current.previous.closedScopes += current.closedScopes;
+ Entry overrides = current.overrides;
+ if (overrides != null) {
+ // No more overriden
+ overrides.overriden = false;
+ }
+
+ if (this.lastDeclaredEntry == current) {
+ if (current.previous.closedScopes == 0) {
+ this.lastDeclaredEntry = current.previous;
+ } else {
+ this.lastDeclaredEntry = null;
+ }
+ }
+
+ if (this.lastEntry == current) {
+ this.lastEntry = current.previous;
+ }
+
+ return current;
+ }
+
+ afterCurrent = current;
+ current = current.previous;
+ }
+
+ // Not found
+ return null;
+ }
+
+ /**
+ * Enter a new scope. This starts a new, empty list of declarations for the new scope.
+ *
+ * Typically called in a SAX handler before sending a startElement()
+ * event.
+ *
+ * @since 2.1.8
+ */
+ public void enterScope() {
+ this.usesScopes = true;
+ this.lastEntry.closedScopes++;
+ this.lastDeclaredEntry = null;
+ }
+
+ /**
+ * Start all declared mappings of the current scope and enter a new scope. This starts a new,
+ * empty list of declarations for the new scope.
+ *
+ * Typically called in a SAX handler before sending a startElement()
+ * event.
+ *
+ * @param handler the handler that will receive startPrefixMapping events.
+ * @throws SAXException
+ * @since 2.1.8
+ */
+ public void enterScope(ContentHandler handler) throws SAXException {
+ this.usesScopes = true;
+ Entry current = this.lastEntry;
+ while (current != null && current.closedScopes == 0) {
+ handler.startPrefixMapping(current.prefix, current.uri);
+ current = current.previous;
+ }
+ this.lastEntry.closedScopes++;
+ this.lastDeclaredEntry = null;
+ }
+
+ /**
+ * Leave a scope. The namespace declarations that occured before the corresponding
+ * enterScope()
are no more visible using the resolution methods, but
+ * still available using {@link #getCurrentScopeDeclarations()} until the next call
+ * to {@link #addDeclaration(String, String)} or {@link #enterScope()}.
+ *
+ * Typically called in a SAX handler after sending a endElement()
+ * event.
+ *
+ * @since 2.1.8
+ */
+ public void leaveScope() {
+ Entry current = this.lastEntry;
+
+ // Purge declarations that were added but not included in a scope
+ while (current.closedScopes == 0) {
+ current = current.previous;
+ }
+
+ current.closedScopes--;
+
+ if (current.closedScopes == 0) {
+ this.lastDeclaredEntry = current;
+ } else {
+ // More than one scope closed here: no local declarations
+ this.lastDeclaredEntry = null;
+ }
+
+ while (current != null && current.closedScopes == 0) {
+ Entry overrides = current.overrides;
+ if (overrides != null) {
+ // No more overriden
+ overrides.overriden = false;
+ }
+ current = current.previous;
+ }
+ this.lastEntry = current;
+ }
+
+ /**
+ * Leave a scope. The namespace declarations that occured before the corresponding
+ * enterScope()
are no more visible using the resolution methods, but
+ * still available using {@link #getCurrentScopeDeclarations()} until the next call
+ * to {@link #addDeclaration(String, String)} or {@link #enterScope()}.
+ *
+ * Typically called in a SAX handler after sending a endElement()
+ * event.
+ *
+ * @param handler the handler that will receive endPrefixMapping events.
+ * @throws SAXException
+ * @since 2.1.8
+ */
+ public void leaveScope(ContentHandler handler) throws SAXException {
+ Entry current = this.lastEntry;
+
+ // Purge declarations that were added but not included in a scope
+ while (current.closedScopes == 0) {
+ current = current.previous;
+ }
+
+ current.closedScopes--;
+
+ if (current.closedScopes == 0) {
+ this.lastDeclaredEntry = current;
+ } else {
+ // More than one scope closed here: no local declarations
+ this.lastDeclaredEntry = null;
+ }
+
+ while (current != null && current.closedScopes == 0) {
+ handler.endPrefixMapping(current.prefix);
+ Entry overrides = current.overrides;
+ if (overrides != null) {
+ // No more overriden
+ overrides.overriden = false;
+ }
+ current = current.previous;
+ }
+
+ this.lastEntry = current;
+ }
+
+ private static final Declaration[] NO_DECLS = new Declaration[0];
+
+ /**
+ * Get the declarations that were declared within the current scope.
+ *
+ * @return the declarations (possibly empty, but never null)
+ * @since 2.1.8
+ */
+ public Declaration[] getCurrentScopeDeclarations() {
+ int count = 0;
+ Entry current = this.lastDeclaredEntry;
+ while (current != null && current.closedScopes == 0) {
+ count++;
+ current = current.previous;
+ }
+
+ if (count == 0) return NO_DECLS;
+
+ Declaration[] decls = new Declaration[count];
+ count = 0;
+ current = this.lastDeclaredEntry;
+ while (current != null && current.closedScopes == 0) {
+ decls[count++] = current;
+ current = current.previous;
+ }
+ return decls;
+ }
+
+ /**
+ * Return the URI associated with the given prefix or null if the
+ * prefix was not mapped.
+ */
+ public String getUri(String prefix) {
+ Entry current = this.lastEntry;
+ while (current != null) {
+ if (current.prefix.equals(prefix)) {
+ return current.uri;
+ }
+ current = current.previous;
+ }
+
+ // Not found
+ return null;
+ }
+
+ /**
+ * Return an array with all prefixes currently mapped to the specified URI.
+ *
+ * The array length might be zero if no prefixes are associated with
+ * the specified uri.
+ *
+ * @return A non-null String
array.
+ */
+ public String[] getPrefixes(String uri) {
+
+ Entry current=this.lastEntry;
+ int count=0;
+ while (current!=null) {
+ if(!current.overriden && current.uri.equals(uri))
+ count++;
+ current=current.previous;
+ }
+ if (count==0) return(new String[0]);
+
+ String prefixes[]=new String[count];
+ count=0;
+ current = this.lastEntry;
+ while (current!=null) {
+ if(!current.overriden && current.uri.equals(uri))
+ prefixes[count++] = current.prefix;
+ current = current.previous;
+ }
+ return prefixes;
+ }
+
+
+ /**
+ * Return one of the prefixes currently mapped to the specified URI or
+ * null.
+ */
+ public String getPrefix(String uri) {
+ Entry current = this.lastEntry;
+ while (current != null) {
+ if(!current.overriden && current.uri.equals(uri))
+ return current.prefix;
+ current = current.previous;
+ }
+ return null;
+ }
+
+ /**
+ * Resolve a namespace-aware name against the current namespaces
+ * declarations.
+ *
+ * @param uri The namespace URI or null if not known.
+ * @param raw The raw (complete) name or null if not known.
+ * @param prefix The namespace prefix or null if not known.
+ * @param local The local name or null if not known.
+ * @return A non-null Name
.
+ * @exception SAXException If the name cannot be resolved.
+ */
+ public Name resolve(String uri, String raw, String prefix, String local)
+ throws SAXException {
+ if (uri==null) uri="";
+ if (raw==null) raw="";
+ if (prefix==null) prefix="";
+ if (local==null) local="";
+ // Start examining the URI
+ if (raw.length()>0) {
+ // The raw name was specified
+ int pos=raw.indexOf(':');
+ if (pos>0) {
+ // We have a namespace prefix:local separator
+ String pre=raw.substring(0,pos);
+ String loc=raw.substring(pos+1);
+ if (prefix.length()==0) prefix=pre;
+ else if (!prefix.equals(pre))
+ throw new SAXException("Raw/Prefix mismatch");
+ if (local.length()==0) local=loc;
+ else if (!local.equals(loc))
+ throw new SAXException("Raw/Local Name mismatch");
+ } else {
+ // We don't have a prefix:local separator
+ if (prefix.length()>0)
+ throw new SAXException("Raw Name/Prefix mismatch");
+ if (local.length()==0) local=raw;
+ else if (!local.equals(raw))
+ throw new SAXException("Raw Name/Local Name mismatch");
+ }
+ } else {
+ // The raw name was not specified
+ if (local.length()==0) throw new SAXException("No Raw/Local Name");
+ if (prefix.length()==0) raw=local;
+ else raw=prefix+':'+local;
+ }
+ // We have resolved and checked data between the raw, local, and
+ // prefix... We have to doublecheck the namespaces.
+ if (uri.length()>0) {
+ // We have a URI and a prefix, check them
+ if ((prefix.length()>0) && (!uri.equals(this.getUri(prefix)))) {
+ throw new SAXException("URI/Prefix mismatch [" + prefix + "," + uri + "]");
+ } else {
+ String temp=this.getPrefix(uri);
+ if (temp==null) throw new SAXException("URI not declared");
+ else if (temp.length()>0) {
+ prefix=temp;
+ raw=prefix+':'+local;
+ }
+ }
+ } else {
+ // We don't have a URI, check if we can find one from the prefix.
+ String temp=this.getUri(prefix);
+ if (temp==null) throw new SAXException("Prefix not declared");
+ else uri=temp;
+ }
+ NameImpl name=new NameImpl();
+ if (uri.length() > 0) name.uri=uri;
+ else name.uri=null;
+ name.raw=raw;
+ name.prefix=prefix;
+ name.local=local;
+ return(name);
+ }
+
+ /** The internal entry structure for this table. */
+ private static class Entry implements Declaration {
+ /** The URI string. */
+ protected String uri="";
+ /** The prefix string. */
+ protected String prefix="";
+ /** The previous declaration. */
+ protected Entry previous;
+ protected Entry overrides;
+ protected int closedScopes = 0;
+ protected boolean overriden = false;
+
+ /** Create a new namespace declaration. */
+ protected static Entry create(String prefix, String uri) {
+ // Create a new entry
+ Entry e = new Entry();
+ // Set the prefix string.
+ if (prefix != null) e.prefix=prefix;
+ // Set the uri string.
+ if (uri != null) e.uri=uri;
+ // Return the entry
+ return e;
+ }
+
+ /** Return the namespace URI. */
+ public String getUri() { return this.uri; }
+ /** Return the namespace prefix. */
+ public String getPrefix() { return this.prefix; }
+ }
+
+ /** The default namespace-aware name declaration implementation */
+ private static class NameImpl implements Name {
+ /** The namespace URI. */
+ protected String uri;
+ /** The namespace prefix. */
+ protected String prefix;
+ /** The namespace local name. */
+ protected String local;
+ /** The namespace raw name. */
+ protected String raw;
+
+ /** Return the namespace URI. */
+ public String getUri() { return this.uri; }
+ /** Return the namespace prefix. */
+ public String getPrefix() { return this.prefix; }
+ /** Return the namespace local name. */
+ public String getLocalName() { return this.local; }
+ /** Return the namespace raw name. */
+ public String getQName() { return this.raw; }
+ }
+
+ /**
+ * A namespace-aware name. (This interface is used in conjunction
+ * with NamespacesTable
).
+ */
+ public interface Name {
+ /** Return the namespace URI. */
+ String getUri();
+ /** Return the namespace prefix. */
+ String getPrefix();
+ /** Return the namespace local name. */
+ String getLocalName();
+ /** Return the namespace raw name. */
+ String getQName();
+ }
+
+ /**
+ * A namespace declaration. (This interface is used in conjunction
+ * with NamespacesTable
).
+ */
+ public interface Declaration {
+ /** Return the namespace URI. */
+ String getUri();
+ /** Return the namespace prefix. */
+ String getPrefix();
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/NamespacesTable.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/ParamSaxBuffer.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/ParamSaxBuffer.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/ParamSaxBuffer.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/ParamSaxBuffer.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,206 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * Licensed 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 {name}
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 Vadim Gritsenko
+ * @version CVS $Id: ParamSaxBuffer.java 106182 2004-11-22 14:16:31Z bruno $
+ */
+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 {name}
parameters for later
+ * substitution.
+ */
+ 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] == '{') {
+ // 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);
+ break;
+ }
+ 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);
+ }
+ }
+ }
+
+
+ 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 dump(Writer writer) throws IOException {
+ writer.write("[Parameter] name=" + name);
+ }
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/ParamSaxBuffer.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/RedundantNamespacesFilter.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/RedundantNamespacesFilter.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/RedundantNamespacesFilter.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/RedundantNamespacesFilter.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,78 @@
+/*
+ * Copyright 1999-2005 The Apache Software Foundation.
+ *
+ * Licensed 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 org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+/**
+ * A SAX filter that strips out redundant namespace declarations.
+ *
+ *
+ * It handles both duplicate declarations (i.e. a namespace already declared by a
+ * parent element) and empty namespaces scopes (i.e. start/stopPrefixMapping with
+ * no element inbetween) that can be produced by some components (e.g. JXTG or
+ * BrowserUpdateTransformer). Such empty scopes confuse the Xalan serializer which
+ * then produces weird namespace declarations (xmlns:%@$#^@#="%@$#^@#"
).
+ *
+ *
+ * This is a the most simple use of {@link NamespacesTable}.
+ *
+ * @version CVS $Id: RedundantNamespacesFilter.java 231484 2005-08-11 17:18:02Z sylvain $
+ */
+public class RedundantNamespacesFilter extends AbstractXMLPipe {
+
+ /** Layered storage for all namespace declarations */
+ private NamespacesTable ns = new NamespacesTable();
+
+ /**
+ * No-arg constructor. Requires an explicit call to
+ * setConsumer()
.
+ */
+ public RedundantNamespacesFilter() {
+ // Nothing
+ }
+
+ /**
+ * Creates a filter directly linked to its consumer
+ *
+ * @param consumer
+ * the SAX stream consumer
+ */
+ public RedundantNamespacesFilter(XMLConsumer consumer) {
+ setConsumer(consumer);
+ }
+
+ public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ // Just declare it: duplicate declarations are ignorede by NamespacesTable
+ ns.addDeclaration(prefix, uri);
+ }
+
+ public void startElement(String uri, String loc, String raw, Attributes a) throws SAXException {
+ // Declare namespaces for this scope, if any
+ ns.enterScope(this.contentHandler);
+ super.startElement(uri, loc, raw, a);
+ }
+
+ public void endElement(String uri, String loc, String raw) throws SAXException {
+ super.endElement(uri, loc, raw);
+ ns.leaveScope(this.contentHandler);
+ }
+
+ public void endPrefixMapping(String prefix) throws SAXException {
+ ns.removeDeclaration(prefix);
+ }
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/RedundantNamespacesFilter.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/SaxBuffer.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/SaxBuffer.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/SaxBuffer.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/SaxBuffer.java Thu Nov 3 05:41:06 2005
@@ -0,0 +1,569 @@
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * Licensed 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 org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.Locator;
+import org.xml.sax.Attributes;
+import org.xml.sax.ext.LexicalHandler;
+import org.apache.excalibur.xml.sax.XMLizable;
+import org.apache.avalon.excalibur.pool.Recyclable;
+
+import java.io.Serializable;
+import java.io.Writer;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Collections;
+
+/**
+ * A class that can record SAX events and replay them later.
+ *
+ *
Compared to {@link org.apache.cocoon.components.sax.XMLByteStreamCompiler}, + * this class is many times faster at sending out the recorded SAX events since + * it doesn't need to convert between byte and char representations etc. + * On the other hand, its data structure is more complex then a simple byte array, + * making XMLByteStreamCompiler better in case the recorded SAX should be stored long-term. + * + *
Use this class if you need to frequently generate smaller amounts of SAX events, + * or replay a set of recorded start events immediately.
+ * + *Both {@link ContentHandler} and {@link LexicalHandler} are supported, the only + * exception is that the setDocumentLocator event is not recorded.
+ * + * @version CVS $Id: SaxBuffer.java 54075 2004-10-08 13:02:12Z vgritsenko $ + */ +public class SaxBuffer extends AbstractSAXFragment + implements XMLConsumer, Recyclable, Serializable { + + /** + * Stores list of {@link SaxBit} objects. + */ + protected List saxbits; + + /** + * Creates empty SaxBuffer + */ + public SaxBuffer() { + this.saxbits = new ArrayList(); + } + + /** + * Creates SaxBuffer based on the provided bits list. + */ + public SaxBuffer(List bits) { + this.saxbits = bits; + } + + /** + * Creates copy of another SaxBuffer + */ + public SaxBuffer(SaxBuffer saxBuffer) { + this.saxbits = new ArrayList(saxBuffer.saxbits); + } + + // + // ContentHandler Interface + // + + public void skippedEntity(String name) throws SAXException { + saxbits.add(new SkippedEntity(name)); + } + + public void setDocumentLocator(Locator locator) { + // Don't record this event + } + + public void ignorableWhitespace(char ch[], int start, int length) throws SAXException { + saxbits.add(new IgnorableWhitespace(ch, start, length)); + } + + public void processingInstruction(String target, String data) throws SAXException { + saxbits.add(new PI(target, data)); + } + + public void startDocument() throws SAXException { + saxbits.add(StartDocument.SINGLETON); + } + + public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { + saxbits.add(new StartElement(namespaceURI, localName, qName, atts)); + } + + public void endPrefixMapping(String prefix) throws SAXException { + saxbits.add(new EndPrefixMapping(prefix)); + } + + public void characters(char ch[], int start, int length) throws SAXException { + saxbits.add(new Characters(ch, start, length)); + } + + public void endElement(String namespaceURI, String localName, String qName) throws SAXException { + saxbits.add(new EndElement(namespaceURI, localName, qName)); + } + + public void endDocument() throws SAXException { + saxbits.add(EndDocument.SINGLETON); + } + + public void startPrefixMapping(String prefix, String uri) throws SAXException { + saxbits.add(new StartPrefixMapping(prefix, uri)); + } + + // + // LexicalHandler Interface + // + + public void endCDATA() throws SAXException { + saxbits.add(EndCDATA.SINGLETON); + } + + public void comment(char ch[], int start, int length) throws SAXException { + saxbits.add(new Comment(ch, start, length)); + } + + public void startEntity(String name) throws SAXException { + saxbits.add(new StartEntity(name)); + } + + public void endDTD() throws SAXException { + saxbits.add(EndDTD.SINGLETON); + } + + public void startDTD(String name, String publicId, String systemId) throws SAXException { + saxbits.add(new StartDTD(name, publicId, systemId)); + } + + public void startCDATA() throws SAXException { + saxbits.add(StartCDATA.SINGLETON); + } + + public void endEntity(String name) throws SAXException { + saxbits.add(new EndEntity(name)); + } + + // + // Public Methods + // + + /** + * Add a bit containing XMLizable object + */ + public void xmlizable(XMLizable xml) { + saxbits.add(new XMLizableBit(xml)); + } + + /** + * @return true if buffer is empty + */ + public boolean isEmpty() { + return saxbits.isEmpty(); + } + + /** + * @return unmodifiable list of SAX bits + */ + public List getBits() { + return Collections.unmodifiableList(saxbits); + } + + /** + * Stream this buffer into the provided content handler. + * If contentHandler object implements LexicalHandler, it will get lexical + * events as well. + */ + public void toSAX(ContentHandler contentHandler) throws SAXException { + for (Iterator i = saxbits.iterator(); i.hasNext();) { + SaxBit saxbit = (SaxBit)i.next(); + saxbit.send(contentHandler); + } + } + + /** + * @return String value of the buffer + */ + public String toString() { + // NOTE: This method is used in i18n XML bundle implementation + final StringBuffer value = new StringBuffer(); + for (Iterator i = saxbits.iterator(); i.hasNext();) { + final SaxBit saxbit = (SaxBit) i.next(); + if (saxbit instanceof Characters) { + ((Characters) saxbit).toString(value); + } + } + + return value.toString(); + } + + /** + * Clear this buffer + */ + public void recycle() { + saxbits.clear(); + } + + /** + * Dump buffer contents into the provided writer. + */ + public void dump(Writer writer) throws IOException { + Iterator i = saxbits.iterator(); + while (i.hasNext()) { + final SaxBit saxbit = (SaxBit) i.next(); + saxbit.dump(writer); + } + writer.flush(); + } + + // + // Implementation Methods + // + + /** + * Adds a SaxBit to the bits list + */ + protected final void addBit(SaxBit bit) { + saxbits.add(bit); + } + + /** + * Iterates through the bits list + */ + protected final Iterator bits() { + return saxbits.iterator(); + } + + /** + * SaxBit is a representation of the SAX event. Every SaxBit is immutable object. + */ + interface SaxBit { + public void send(ContentHandler contentHandler) throws SAXException; + public void dump(Writer writer) throws IOException; + } + + public final static class StartDocument implements SaxBit, Serializable { + public static final StartDocument SINGLETON = new StartDocument(); + + public void send(ContentHandler contentHandler) throws SAXException { + contentHandler.startDocument(); + } + + public void dump(Writer writer) throws IOException { + writer.write("[StartDocument]\n"); + } + } + + public final static class EndDocument implements SaxBit, Serializable { + public static final EndDocument SINGLETON = new EndDocument(); + + public void send(ContentHandler contentHandler) throws SAXException { + contentHandler.endDocument(); + } + + public void dump(Writer writer) throws IOException { + writer.write("[EndDocument]\n"); + } + } + + public final static class PI implements SaxBit, Serializable { + public final String target; + public final String data; + + public PI(String target, String data) { + this.target = target; + this.data = data; + } + + public void send(ContentHandler contentHandler) throws SAXException { + contentHandler.processingInstruction(target, data); + } + + public void dump(Writer writer) throws IOException { + writer.write("[ProcessingInstruction] target=" + target + ",data=" + data + "\n"); + } + } + + public final static class StartDTD implements SaxBit, Serializable { + public final String name; + public final String publicId; + public final String systemId; + + public StartDTD(String name, String publicId, String systemId) { + this.name = name; + this.publicId = publicId; + this.systemId = systemId; + } + + public void send(ContentHandler contentHandler) throws SAXException { + if (contentHandler instanceof LexicalHandler) + ((LexicalHandler)contentHandler).startDTD(name, publicId, systemId); + } + + public void dump(Writer writer) throws IOException { + writer.write("[StartDTD] name=" + name + ",publicId=" + publicId + ",systemId=" + systemId + "\n"); + } + } + + public final static class EndDTD implements SaxBit, Serializable { + public static final EndDTD SINGLETON = new EndDTD(); + + public void send(ContentHandler contentHandler) throws SAXException { + if (contentHandler instanceof LexicalHandler) + ((LexicalHandler)contentHandler).endDTD(); + } + + public void dump(Writer writer) throws IOException { + writer.write("[EndDTD]\n"); + } + } + + public final static class StartEntity implements SaxBit, Serializable { + public final String name; + + public StartEntity(String name) { + this.name = name; + } + + public void send(ContentHandler contentHandler) throws SAXException { + if (contentHandler instanceof LexicalHandler) + ((LexicalHandler)contentHandler).startEntity(name); + } + + public void dump(Writer writer) throws IOException { + writer.write("[StartEntity] name=" + name + "\n"); + } + } + + public final static class EndEntity implements SaxBit, Serializable { + public final String name; + + public EndEntity(String name) { + this.name = name; + } + + public void send(ContentHandler contentHandler) throws SAXException { + if (contentHandler instanceof LexicalHandler) + ((LexicalHandler)contentHandler).endEntity(name); + } + + public void dump(Writer writer) throws IOException { + writer.write("[EndEntity] name=" + name + "\n"); + } + } + + public final static class SkippedEntity implements SaxBit, Serializable { + public final String name; + + public SkippedEntity(String name) { + this.name = name; + } + + public void send(ContentHandler contentHandler) throws SAXException { + contentHandler.skippedEntity(name); + } + + public void dump(Writer writer) throws IOException { + writer.write("[SkippedEntity] name=" + name + "\n"); + } + } + + public final static class StartPrefixMapping implements SaxBit, Serializable { + public final String prefix; + public final String uri; + + public StartPrefixMapping(String prefix, String uri) { + this.prefix = prefix; + this.uri = uri; + } + + public void send(ContentHandler contentHandler) throws SAXException { + contentHandler.startPrefixMapping(prefix, uri); + } + + public void dump(Writer writer) throws IOException { + writer.write("[StartPrefixMapping] prefix=" + prefix + ",uri=" + uri + "\n"); + } + } + + public final static class EndPrefixMapping implements SaxBit, Serializable { + public final String prefix; + + public EndPrefixMapping(String prefix) { + this.prefix = prefix; + } + + public void send(ContentHandler contentHandler) throws SAXException { + contentHandler.endPrefixMapping(prefix); + } + + public void dump(Writer writer) throws IOException { + writer.write("[EndPrefixMapping] prefix=" + prefix + "\n"); + } + } + + public final static class StartElement implements SaxBit, Serializable { + public final String namespaceURI; + public final String localName; + public final String qName; + public final Attributes attrs; + + public StartElement(String namespaceURI, String localName, String qName, Attributes attrs) { + this.namespaceURI = namespaceURI; + this.localName = localName; + this.qName = qName; + this.attrs = new org.xml.sax.helpers.AttributesImpl(attrs); + } + + public void send(ContentHandler contentHandler) throws SAXException { + contentHandler.startElement(namespaceURI, localName, qName, attrs); + } + + public void dump(Writer writer) throws IOException { + writer.write("[StartElement] namespaceURI=" + namespaceURI + ",localName=" + localName + ",qName=" + qName + "\n"); + for (int i = 0; i < attrs.getLength(); i++) { + writer.write(" [Attribute] namespaceURI=" + attrs.getURI(i) + ",localName=" + attrs.getLocalName(i) + ",qName=" + attrs.getQName(i) + ",type=" + attrs.getType(i) + ",value=" + attrs.getValue(i) + "\n"); + } + } + } + + public final static class EndElement implements SaxBit, Serializable { + public final String namespaceURI; + public final String localName; + public final String qName; + + public EndElement(String namespaceURI, String localName, String qName) { + this.namespaceURI = namespaceURI; + this.localName = localName; + this.qName = qName; + } + + public void send(ContentHandler contentHandler) throws SAXException { + contentHandler.endElement(namespaceURI, localName, qName); + } + + public void dump(Writer writer) throws IOException { + writer.write("[EndElement] namespaceURI=" + namespaceURI + ",localName=" + localName + ",qName=" + qName + "\n"); + } + } + + public final static class Characters implements SaxBit, Serializable { + public final char[] ch; + + public Characters(char[] ch, int start, int length) { + // make a copy so that we don't hold references to a potentially large array we don't control + 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 void toString(StringBuffer value) { + value.append(ch); + } + + public void dump(Writer writer) throws IOException { + writer.write("[Characters] ch=" + new String(ch) + "\n"); + } + } + + public final static class Comment implements SaxBit, Serializable { + public final char[] ch; + + public Comment(char[] ch, int start, int length) { + // make a copy so that we don't hold references to a potentially large array we don't control + this.ch = new char[length]; + System.arraycopy(ch, start, this.ch, 0, length); + } + + public void send(ContentHandler contentHandler) throws SAXException { + if (contentHandler instanceof LexicalHandler) + ((LexicalHandler)contentHandler).comment(ch, 0, ch.length); + } + + public void dump(Writer writer) throws IOException { + writer.write("[Comment] ch=" + new String(ch) + "\n"); + } + } + + public final static class StartCDATA implements SaxBit, Serializable { + public static final StartCDATA SINGLETON = new StartCDATA(); + + public void send(ContentHandler contentHandler) throws SAXException { + if (contentHandler instanceof LexicalHandler) + ((LexicalHandler)contentHandler).startCDATA(); + } + + public void dump(Writer writer) throws IOException { + writer.write("[StartCDATA]\n"); + } + } + + public final static class EndCDATA implements SaxBit, Serializable { + public static final EndCDATA SINGLETON = new EndCDATA(); + + public void send(ContentHandler contentHandler) throws SAXException { + if (contentHandler instanceof LexicalHandler) + ((LexicalHandler)contentHandler).endCDATA(); + } + + public void dump(Writer writer) throws IOException { + writer.write("[EndCDATA]\n"); + } + } + + public final static class IgnorableWhitespace implements SaxBit, Serializable { + public final char[] ch; + + public IgnorableWhitespace(char[] ch, int start, int length) { + // make a copy so that we don't hold references to a potentially large array we don't control + 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 dump(Writer writer) throws IOException { + writer.write("[IgnorableWhitespace] ch=" + new String(ch) + "\n"); + } + } + + public final static class XMLizableBit implements SaxBit, Serializable { + public final XMLizable xml; + + public XMLizableBit(XMLizable xml) { + this.xml = xml; + } + + public void send(ContentHandler contentHandler) throws SAXException { + this.xml.toSAX(new EmbeddedXMLPipe(contentHandler)); + } + + public void dump(Writer writer) throws IOException { + if (xml instanceof SaxBuffer) { + writer.write("[XMLizable] Begin nested SaxBuffer\n"); + ((SaxBuffer)xml).dump(writer); + writer.write("[XMLizable] End nested SaxBuffer\n"); + } else { + writer.write("[XMLizable] xml=" + xml + "\n"); + } + } + } +} Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/SaxBuffer.java ------------------------------------------------------------------------------ svn:eol-style = native Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/StringXMLizable.java URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/StringXMLizable.java?rev=330548&view=auto ============================================================================== --- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/StringXMLizable.java (added) +++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/StringXMLizable.java Thu Nov 3 05:41:06 2005 @@ -0,0 +1,59 @@ +/* + * Copyright 2004 The Apache Software Foundation. + * + * Licensed 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 org.apache.excalibur.xml.sax.XMLizable; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.InputSource; + +import javax.xml.parsers.SAXParserFactory; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.ParserConfigurationException; +import java.io.IOException; +import java.io.StringReader; + +/** + * XMLizable a String + * + * @since 2.1.7 + * @author Bruno Dumon + */ +public class StringXMLizable implements XMLizable { + private String data; + + public StringXMLizable(String data) { + this.data = data; + } + + public void toSAX(ContentHandler contentHandler) throws SAXException { + SAXParserFactory parserFactory = SAXParserFactory.newInstance(); + parserFactory.setNamespaceAware(true); + SAXParser parser = null; + try { + parser = parserFactory.newSAXParser(); + } catch (ParserConfigurationException e) { + throw new SAXException("Error creating SAX parser.", e); + } + parser.getXMLReader().setContentHandler(contentHandler); + InputSource is = new InputSource(new StringReader(data)); + try { + parser.getXMLReader().parse(is); + } catch (IOException e) { + throw new SAXException(e); + } + } +} Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/StringXMLizable.java ------------------------------------------------------------------------------ svn:eol-style = native Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLBaseSupport.java URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLBaseSupport.java?rev=330548&view=auto ============================================================================== --- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLBaseSupport.java (added) +++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLBaseSupport.java Thu Nov 3 05:41:06 2005 @@ -0,0 +1,152 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed 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 org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.apache.excalibur.source.SourceResolver; +import org.apache.excalibur.source.Source; +import org.apache.avalon.framework.logger.Logger; + +import java.util.Stack; +import java.util.Collections; +import java.io.IOException; + +/** + * Helper class for handling xml:base attributes. + * + *Usage: + *
External entities are not yet taken into account when determing the current base. + */ +public class XMLBaseSupport { + public static final String XMLBASE_NAMESPACE_URI = "http://www.w3.org/XML/1998/namespace"; + public static final String XMLBASE_ATTRIBUTE = "base"; + + /** Increased on each startElement, decreased on each endElement. */ + private int level = 0; + /** + * The stack contains an instance of {@link BaseInfo} for each XML element + * that contained an xml:base attribute (not for the other elements). + */ + private Stack bases = new Stack(); + private SourceResolver resolver; + private Logger logger; + + public XMLBaseSupport(SourceResolver resolver, Logger logger) { + this.resolver = resolver; + this.logger = logger; + } + + public void setDocumentLocation(String loc) throws SAXException { + // -2 is used as level to avoid this BaseInfo to be ever popped of the stack + bases.push(new BaseInfo(loc, -2)); + } + + public void startElement(String namespaceURI, String localName, String qName, Attributes attrs) throws SAXException { + level++; + String base = attrs.getValue(XMLBASE_NAMESPACE_URI, XMLBASE_ATTRIBUTE); + if (base != null) { + Source baseSource = null; + String baseUrl; + try { + baseSource = resolve(getCurrentBase(), base); + baseUrl = baseSource.getURI(); + } finally { + if (baseSource != null) { + resolver.release(baseSource); + } + } + bases.push(new BaseInfo(baseUrl, level)); + } + } + + public void endElement(String namespaceURI, String localName, String qName) { + if (getCurrentBaseLevel() == level) + bases.pop(); + level--; + } + + /** + * Warning: do not forget to release the source returned by this method. + */ + private Source resolve(String baseURI, String location) throws SAXException { + try { + Source source; + if (baseURI != null) { + source = resolver.resolveURI(location, baseURI, Collections.EMPTY_MAP); + } else { + source = resolver.resolveURI(location); + } + if (logger.isDebugEnabled()) { + logger.debug("XMLBaseSupport: resolved location " + location + + " against base URI " + baseURI + " to " + source.getURI()); + } + return source; + } catch (IOException e) { + throw new SAXException("XMLBaseSupport: problem resolving uri.", e); + } + } + + /** + * Makes the given path absolute based on the current base URL. Do not forget to release + * the returned source object! + * @param spec any URL (relative or absolute, containing a scheme or not) + */ + public Source makeAbsolute(String spec) throws SAXException { + return resolve(getCurrentBase(), spec); + } + + private String getCurrentBase() { + if (bases.size() > 0) { + BaseInfo baseInfo = (BaseInfo)bases.peek(); + return baseInfo.getUrl(); + } + return null; + } + + private int getCurrentBaseLevel() { + if (bases.size() > 0) { + BaseInfo baseInfo = (BaseInfo)bases.peek(); + return baseInfo.getLevel(); + } + return -1; + } + + private static final class BaseInfo { + private String url; + private int level; + + public BaseInfo(String url, int level) { + this.url = url; + this.level = level; + } + + public String getUrl() { + return url; + } + + public int getLevel() { + return level; + } + } +} Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLBaseSupport.java ------------------------------------------------------------------------------ svn:eol-style = native Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLConsumer.java URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLConsumer.java?rev=330548&view=auto ============================================================================== --- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLConsumer.java (added) +++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLConsumer.java Thu Nov 3 05:41:06 2005 @@ -0,0 +1,46 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed 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; + +/** + * This interfaces identifies classes that consume XML data, receiving + * notification of SAX events. + *
+ * An XMLConsumer is also a SAX ContentHandler and a SAX LexicalHandler. That + * means the XMLConsumer has to respect all the contracts with the SAX + * interfaces. SAX stands for Serialized API for XML. A document start, and + * each element start must be matched by the corresponding element end or + * document end. So why does Cocoon use SAX instead of manipulating a DOM? + * For two main reasons: performance and scalability. A DOM tree is much more + * heavy on system memory than successive calls to an API. SAX events can be + * sent as soon as they are read from the originating XML, the parsing and + * processing can happen essentially at the same time. + *
+ *+ * Most people's needs will be handled just fine with the ContentHandler + * interface, as that declares your namespaces. However if you need lexical + * support to resolve entity names and such, you need the LexicalHandler + * interface. The AbstractXMLConsumer base class can make implementing this + * interface easier so that you only need to override the events you intend to + * do anything with. + *
+ * + * @author Pierpaolo Fumagalli + * (Apache Software Foundation) + * @version CVS $Id: XMLConsumer.java 279586 2005-09-08 17:12:20Z bloritsch $ + */ +public interface XMLConsumer extends org.apache.excalibur.xml.sax.XMLConsumer { +} Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLConsumer.java ------------------------------------------------------------------------------ svn:eol-style = native Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLFragment.java URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLFragment.java?rev=330548&view=auto ============================================================================== --- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLFragment.java (added) +++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLFragment.java Thu Nov 3 05:41:06 2005 @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed 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 org.w3c.dom.Node; + +/** + * This interface must be implemented by classes willing + * to provide an XML representation of their current state. + * + *This interface exists in both Cocoon 1 and Cocoon 2 and to ensure + * a minimal compatibility between the two versions.
+ * + *Cocoon 2 only objects can implement the SAX-only XMLizable
+ * interface.
+ * XMLProducer -> (XMLConsumer)XMLPipe(XMLProducer) -> XMLConsumer + *+ *
+ * A typical example would be using the FileGenerator (an XMLProducer), sending + * events to an XSLTTransformer (an XMLPipe), which then sends events to an + * HTMLSerializer (an XMLConsumer). The XSLTTransformer acts as an XMLConsumer + * to the FileGenerator, and also acts as an XMLProducer to the HTMLSerializer. + * It is still the responsibility of the XMLPipe component to ensure that the + * XML passed on to the next component is valid--provided the XML received from + * the previous component is valid. In layman's terms it means if you don't + * intend to alter the input, just pass it on. In most cases we just want to + * transform a small snippet of XML. For example, inserting a snippet of XML + * based on an embedded element in a certain namespace. Anything that doesn't + * belong to the namespace you are worried about should be passed on as is. + *
+ * + * @author Stefano Mazzocchi + * @version CVS $Id: XMLPipe.java 279586 2005-09-08 17:12:20Z bloritsch $ + */ +public interface XMLPipe extends XMLConsumer, XMLProducer {} Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLPipe.java ------------------------------------------------------------------------------ svn:eol-style = native Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLProducer.java URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLProducer.java?rev=330548&view=auto ============================================================================== --- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLProducer.java (added) +++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLProducer.java Thu Nov 3 05:41:06 2005 @@ -0,0 +1,53 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed 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; + +/** + * This interfaces identifies classes that produce XML data, sending SAX + * events to the configuredXMLConsumer
.
+ *
+ * The XMLProducer is comprised of only one method to give the component the
+ * next element of the pipeline. Cocoon calls the setConsumer()
+ * method with the reference to the next XMLConsumer in the pipeline. The
+ * approach allows the XMLProducer to call the different SAX related methods on
+ * the XMLConsumer without knowing ahead of time what that consumer will be.
+ * The design is very simple and very powerful in that it allows Cocoon to
+ * daisy chain several components in any order and then execute the pipeline.
+ *
+ * Any producer can be paired with any consumer and we have a pipeline. The
+ * core design is very powerful and allows the end user to mix and match
+ * sitemap components as they see fit. Cocoon will always call
+ * setConsumer()
on every XMLProducer in a pipeline or it will
+ * throw an exception saying that the pipeline is invalid (i.e. there is no
+ * serializer for the pipeline). The only contract that the XMLProducer has to
+ * worry about is that it must always make calls to the XMLConsumer passed in
+ * through the setConsumer()
method.
+ *
XMLConsumer
that will receive XML data.
+ *
+ * @param consumer The XMLConsumer target for SAX events.
+ */
+ void setConsumer(XMLConsumer consumer);
+}
Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/xml/XMLProducer.java
------------------------------------------------------------------------------
svn:eol-style = native