blob: d7e6f08d5836db91fb3bd66f3bdcbb047057f9ed [file] [log] [blame]
/*
* 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.components.serializers.util;
import org.xml.sax.SAXException;
/**
* The <code>Namespaces</code> class is an utility class implementing a
* stack for XML namespaces declarations.
*
* @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>, February 2003
* @version CVS $Id$
*/
public class Namespaces {
/** The array of all URIs in this stack. */
private String uri[] = new String[512];
/** The array of all prefixes in this stack. */
private String pre[] = new String[512];
/** The number of URI/prefix mappings in this stack. */
private int depth = 0;
/** The last "committed" namespace. */
private int last = 0;
/** The index of the namespace prefix in for <code>commit()</code>. */
public static final int NAMESPACE_PREFIX = 0;
/** The index of the namespace uri in for <code>commit()</code>. */
public static final int NAMESPACE_URI = 1;
/**
* Create a new <code>Namespaces</code> instance.
*/
public Namespaces() {
super();
this.push("", "");
this.push("xml", "http://www.w3.org/XML/1998/namespace");
this.last = this.depth;
}
/**
* Push a new namespace declaration into this stack.
*
* @param prefix The prefix to associate with the specified URI.
* @param uri The URI associated with the namespace.
*/
public synchronized void push(String prefix, String uri) {
if (this.depth == this.uri.length) {
int newDepth = this.uri.length + (this.uri.length >> 1);
String newUri[] = new String[newDepth];
String newPre[] = new String[newDepth];
System.arraycopy(this.uri, 0, newUri, 0, this.depth);
System.arraycopy(this.pre, 0, newPre, 0, this.depth);
this.uri = newUri;
this.pre = newPre;
}
this.uri[this.depth] = uri;
this.pre[this.depth] = prefix;
this.depth ++;
}
/**
* Pop a new namespace declaration out of this stack.
* <br />
* If more than one namespace is associated with the specified namespace,
* only the last pushed namespace will be popped out.
*
* @param prefix The prefix to associate with the specified URI.
* @throws SAXException If the prefix was not mapped in this stack.
*/
public synchronized void pop(String prefix)
throws SAXException {
for (int x = this.position(prefix, pre); x < this.depth; x++) {
int k = (x + 1);
this.pre[x] = this.pre[k];
this.uri[x] = this.uri[k];
}
//this.pre[this.depth] = null;
//this.uri[this.depth] = null;
this.last--;
this.depth--;
}
/**
* Qualify an XML name.
* <br />
* Given a URI, local name and qualified name as passed to the SAX
* <code>ContentHandler</code> interface in the <code>startElement()</code>
* method, this method will always return a valid XML name token usable
* for serialization (checking namespaces URIs and prefixes).
*
* @param nsuri The Namespace URI, or the empty string if the element has
* no namespace URI or if namespace processing is not being
* performed.
* @param local The local name (without prefix), or the empty string if
* namespace processing is not being performed.
* @param qualified The qualified name (with prefix), or the empty string
* if qualified names are not available.
* @throws SAXException If the specified URI is not mapped with a prefix.
*/
public String qualify(String nsuri, String local, String qualified)
throws SAXException {
if (nsuri == null) nsuri = "";
if (local == null) local = "";
if (qualified == null) qualified = "";
/** No namespaces processing. */
if ((nsuri.length() == 0 ) && (local.length() == 0)) return(qualified);
/*
* Get the prefix for the given namespace and return the qualified
* name: "prefix:local" if prefix is not empty, "local" otherwise.
*/
int position = position(nsuri, this.uri);
if (this.pre[position].length() > 0) {
return(this.pre[position] + ':' + local);
}
return(local);
}
/**
* Checkpoint this stack, returning the list of all namespaces added since
* the last <code>commit()</code> or <code>pop(...)</code> call.
*/
public String[][] commit() {
int size = this.depth - this.last;
String result[][] = new String[size][2];
int k = 0;
for (int x = this.last; x < this.depth; x++) {
result[k][NAMESPACE_PREFIX] = this.pre[x];
result[k][NAMESPACE_URI] = this.uri[x];
k++;
}
this.last = this.depth;
return(result);
}
/**
* Return the namespace URI associated with the specified prefix.
*
* @throws SAXException If the prefix cannot be mapped.
*/
public String getUri(String prefix)
throws SAXException {
return(this.uri[this.position(prefix, this.pre)]);
}
/**
* Return the namespace prefix associated with the specified URI.
*
* @throws SAXException If the URI cannot be mapped.
*/
public String getPrefix(String nsuri)
throws SAXException {
return(this.pre[this.position(nsuri, this.uri)]);
}
/**
* Return the position of the given check <code>String</code> in the
* specified <code>String</code> array.
*/
private int position(String check, String array[])
throws SAXException {
int x = this.depth;
while (true) {
if (check.equals(array[--x])) return(x);
if (x == 0) break;
}
throw new SAXException("Unable to map \"" + check + "\"");
}
}