001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.components.serializers.util;
018:
019: import org.xml.sax.SAXException;
020:
021: /**
022: * The <code>Namespaces</code> class is an utility class implementing a
023: * stack for XML namespaces declarations.
024: *
025: * @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>, February 2003
026: * @version CVS $Id: Namespaces.java 433543 2006-08-22 06:22:54Z crossley $
027: */
028: public class Namespaces {
029: /** The array of all URIs in this stack. */
030: private String uri[] = new String[512];
031: /** The array of all prefixes in this stack. */
032: private String pre[] = new String[512];
033: /** The number of URI/prefix mappings in this stack. */
034: private int depth = 0;
035: /** The last "committed" namespace. */
036: private int last = 0;
037:
038: /** The index of the namespace prefix in for <code>commit()</code>. */
039: public static final int NAMESPACE_PREFIX = 0;
040: /** The index of the namespace uri in for <code>commit()</code>. */
041: public static final int NAMESPACE_URI = 1;
042:
043: /**
044: * Create a new <code>Namespaces</code> instance.
045: */
046: public Namespaces() {
047: super ();
048:
049: this .push("", "");
050: this .push("xml", "http://www.w3.org/XML/1998/namespace");
051: this .last = this .depth;
052: }
053:
054: /**
055: * Push a new namespace declaration into this stack.
056: *
057: * @param prefix The prefix to associate with the specified URI.
058: * @param uri The URI associated with the namespace.
059: */
060: public synchronized void push(String prefix, String uri) {
061: if (this .depth == this .uri.length) {
062: int newDepth = this .uri.length + (this .uri.length >> 1);
063: String newUri[] = new String[newDepth];
064: String newPre[] = new String[newDepth];
065: System.arraycopy(this .uri, 0, newUri, 0, this .depth);
066: System.arraycopy(this .pre, 0, newPre, 0, this .depth);
067: this .uri = newUri;
068: this .pre = newPre;
069: }
070:
071: this .uri[this .depth] = uri;
072: this .pre[this .depth] = prefix;
073: this .depth++;
074: }
075:
076: /**
077: * Pop a new namespace declaration out of this stack.
078: * <br />
079: * If more than one namespace is associated with the specified namespace,
080: * only the last pushed namespace will be popped out.
081: *
082: * @param prefix The prefix to associate with the specified URI.
083: * @throws SAXException If the prefix was not mapped in this stack.
084: */
085: public synchronized void pop(String prefix) throws SAXException {
086: for (int x = this .position(prefix, pre); x < this .depth; x++) {
087: int k = (x + 1);
088: this .pre[x] = this .pre[k];
089: this .uri[x] = this .uri[k];
090: }
091: //this.pre[this.depth] = null;
092: //this.uri[this.depth] = null;
093: this .last--;
094: this .depth--;
095: }
096:
097: /**
098: * Qualify an XML name.
099: * <br />
100: * Given a URI, local name and qualified name as passed to the SAX
101: * <code>ContentHandler</code> interface in the <code>startElement()</code>
102: * method, this method will always return a valid XML name token usable
103: * for serialization (checking namespaces URIs and prefixes).
104: *
105: * @param nsuri The Namespace URI, or the empty string if the element has
106: * no namespace URI or if namespace processing is not being
107: * performed.
108: * @param local The local name (without prefix), or the empty string if
109: * namespace processing is not being performed.
110: * @param qualified The qualified name (with prefix), or the empty string
111: * if qualified names are not available.
112: * @throws SAXException If the specified URI is not mapped with a prefix.
113: */
114: public String qualify(String nsuri, String local, String qualified)
115: throws SAXException {
116: if (nsuri == null)
117: nsuri = "";
118: if (local == null)
119: local = "";
120: if (qualified == null)
121: qualified = "";
122:
123: /** No namespaces processing. */
124: if ((nsuri.length() == 0) && (local.length() == 0))
125: return (qualified);
126:
127: /*
128: * Get the prefix for the given namespace and return the qualified
129: * name: "prefix:local" if prefix is not empty, "local" otherwise.
130: */
131: int position = position(nsuri, this .uri);
132: if (this .pre[position].length() > 0) {
133: return (this .pre[position] + ':' + local);
134: }
135: return (local);
136: }
137:
138: /**
139: * Checkpoint this stack, returning the list of all namespaces added since
140: * the last <code>commit()</code> or <code>pop(...)</code> call.
141: */
142: public String[][] commit() {
143: int size = this .depth - this .last;
144: String result[][] = new String[size][2];
145: int k = 0;
146: for (int x = this .last; x < this .depth; x++) {
147: result[k][NAMESPACE_PREFIX] = this .pre[x];
148: result[k][NAMESPACE_URI] = this .uri[x];
149: k++;
150: }
151: this .last = this .depth;
152: return (result);
153: }
154:
155: /**
156: * Return the namespace URI associated with the specified prefix.
157: *
158: * @throws SAXException If the prefix cannot be mapped.
159: */
160: public String getUri(String prefix) throws SAXException {
161: return (this .uri[this .position(prefix, this .pre)]);
162: }
163:
164: /**
165: * Return the namespace prefix associated with the specified URI.
166: *
167: * @throws SAXException If the URI cannot be mapped.
168: */
169: public String getPrefix(String nsuri) throws SAXException {
170: return (this .pre[this .position(nsuri, this .uri)]);
171: }
172:
173: /**
174: * Return the position of the given check <code>String</code> in the
175: * specified <code>String</code> array.
176: */
177: private int position(String check, String array[])
178: throws SAXException {
179: int x = this .depth;
180: while (true) {
181: if (check.equals(array[--x]))
182: return (x);
183: if (x == 0)
184: break;
185: }
186: throw new SAXException("Unable to map \"" + check + "\"");
187: }
188:
189: }
|