325N/A/*
325N/A * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
325N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
325N/A *
325N/A * This code is free software; you can redistribute it and/or modify it
325N/A * under the terms of the GNU General Public License version 2 only, as
325N/A * published by the Free Software Foundation. Oracle designates this
325N/A * particular file as subject to the "Classpath" exception as provided
325N/A * by Oracle in the LICENSE file that accompanied this code.
325N/A *
325N/A * This code is distributed in the hope that it will be useful, but WITHOUT
325N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
325N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
325N/A * version 2 for more details (a copy is included in the LICENSE file that
325N/A * accompanied this code).
325N/A *
325N/A * You should have received a copy of the GNU General Public License version
325N/A * 2 along with this work; if not, write to the Free Software Foundation,
325N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
325N/A *
325N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
325N/A * or visit www.oracle.com if you need additional information or have any
325N/A * questions.
325N/A */
325N/A
325N/Apackage com.sun.xml.internal.stream.buffer.stax;
325N/A
325N/Aimport java.util.ArrayList;
325N/Aimport java.util.Collections;
325N/Aimport java.util.Iterator;
325N/Aimport java.util.List;
325N/Aimport com.sun.xml.internal.org.jvnet.staxex.NamespaceContextEx;
325N/A
325N/A/**
325N/A * A helper class for managing the declaration of namespaces.
325N/A * <p>
325N/A * A namespace is declared on a namespace context.
325N/A * Namespace contexts are pushed on and popped off the namespace context stack.
325N/A * <p>
325N/A * A declared namespace will be in scope iff the context that it was declared on
325N/A * has not been popped off the stack.
325N/A * <p>
325N/A * When instantiated the namespace stack consists of the root namespace context,
325N/A * which contains, by default, the "xml" and "xmlns" declarations.
325N/A * Namespaces may be declarations may be declared on the root context.
325N/A * The root context cannot be popped but can be reset to contain just the
325N/A * "xml" and "xmlns" declarations.
325N/A * <p>
325N/A * Implementation note: determining the prefix from a namespace URI
325N/A * (or vice versa) is efficient when there are few namespace
325N/A * declarations i.e. what is considered to be the case for namespace
325N/A * declarations in 'average' XML documents. The look up of a namespace URI
325N/A * given a prefix is performed in O(n) time. The look up of a prefix given
325N/A * a namespace URI is performed in O(2n) time.
325N/A * <p>
325N/A * The implementation does not scale when there are many namespace
325N/A * declarations. TODO: Use a hash map when there are many namespace
325N/A * declarations.
325N/A *
325N/A * @author Paul.Sandoz@Sun.Com
325N/A */
325N/Afinal public class NamespaceContexHelper implements NamespaceContextEx {
325N/A private static int DEFAULT_SIZE = 8;
325N/A
325N/A // The prefixes of the namespace declarations
325N/A private String[] prefixes = new String[DEFAULT_SIZE];
325N/A // The URIs of the namespace declarations
325N/A private String[] namespaceURIs = new String[DEFAULT_SIZE];
325N/A // Current position to store the next namespace declaration
325N/A private int namespacePosition;
325N/A
325N/A // The namespace contexts
325N/A private int[] contexts = new int[DEFAULT_SIZE];
325N/A // Current position to store the next namespace context
325N/A private int contextPosition;
325N/A
325N/A // The current namespace context
325N/A private int currentContext;
325N/A
325N/A /**
325N/A * Create a new NamespaceContexHelper.
325N/A *
325N/A */
325N/A public NamespaceContexHelper() {
325N/A // The default namespace declarations that are always in scope
325N/A prefixes[0] = "xml";
325N/A namespaceURIs[0] = "http://www.w3.org/XML/1998/namespace";
325N/A prefixes[1] = "xmlns";
325N/A namespaceURIs[1] = "http://www.w3.org/2000/xmlns/";
325N/A
325N/A currentContext = namespacePosition = 2;
325N/A }
325N/A
325N/A
325N/A // NamespaceContext interface
325N/A
325N/A public String getNamespaceURI(String prefix) {
325N/A if (prefix == null) throw new IllegalArgumentException();
325N/A
325N/A prefix = prefix.intern();
325N/A
325N/A for (int i = namespacePosition - 1; i >= 0; i--) {
325N/A final String declaredPrefix = prefixes[i];
325N/A if (declaredPrefix == prefix) {
325N/A return namespaceURIs[i];
325N/A }
325N/A }
325N/A
325N/A return "";
325N/A }
325N/A
325N/A public String getPrefix(String namespaceURI) {
325N/A if (namespaceURI == null) throw new IllegalArgumentException();
325N/A
325N/A for (int i = namespacePosition - 1; i >= 0; i--) {
325N/A final String declaredNamespaceURI = namespaceURIs[i];
325N/A if (declaredNamespaceURI == namespaceURI || declaredNamespaceURI.equals(namespaceURI)) {
325N/A final String declaredPrefix = prefixes[i];
325N/A
325N/A // Check if prefix is out of scope
325N/A for (++i; i < namespacePosition; i++)
325N/A if (declaredPrefix == prefixes[i])
325N/A return null;
325N/A
325N/A return declaredPrefix;
325N/A }
325N/A }
325N/A
325N/A return null;
325N/A }
325N/A
325N/A public Iterator getPrefixes(String namespaceURI) {
325N/A if (namespaceURI == null) throw new IllegalArgumentException();
325N/A
325N/A List<String> l = new ArrayList<String>();
325N/A
325N/A NAMESPACE_LOOP: for (int i = namespacePosition - 1; i >= 0; i--) {
325N/A final String declaredNamespaceURI = namespaceURIs[i];
325N/A if (declaredNamespaceURI == namespaceURI || declaredNamespaceURI.equals(namespaceURI)) {
325N/A final String declaredPrefix = prefixes[i];
325N/A
325N/A // Check if prefix is out of scope
325N/A for (int j = i + 1; j < namespacePosition; j++)
325N/A if (declaredPrefix == prefixes[j])
325N/A continue NAMESPACE_LOOP;
325N/A
325N/A l.add(declaredPrefix);
325N/A }
325N/A }
325N/A
325N/A return l.iterator();
325N/A }
325N/A
325N/A // NamespaceContextEx interface
325N/A
325N/A public Iterator<NamespaceContextEx.Binding> iterator() {
325N/A if (namespacePosition == 2)
325N/A return Collections.EMPTY_LIST.iterator();
325N/A
325N/A final List<NamespaceContextEx.Binding> namespaces =
325N/A new ArrayList<NamespaceContextEx.Binding>(namespacePosition);
325N/A
325N/A NAMESPACE_LOOP: for (int i = namespacePosition - 1; i >= 2; i--) {
325N/A final String declaredPrefix = prefixes[i];
325N/A
325N/A // Check if prefix is out of scope
325N/A for (int j = i + 1; j < namespacePosition; j++) {
325N/A if (declaredPrefix == prefixes[j])
325N/A continue NAMESPACE_LOOP;
325N/A
325N/A namespaces.add(new NamespaceBindingImpl(i));
325N/A }
325N/A }
325N/A
325N/A return namespaces.iterator();
325N/A }
325N/A
325N/A final private class NamespaceBindingImpl implements NamespaceContextEx.Binding {
325N/A int index;
325N/A
325N/A NamespaceBindingImpl(int index) {
325N/A this.index = index;
325N/A }
325N/A
325N/A public String getPrefix() {
325N/A return prefixes[index];
325N/A }
325N/A
325N/A public String getNamespaceURI() {
325N/A return namespaceURIs[index];
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Declare a default namespace.
325N/A * <p>
325N/A * @param namespaceURI the namespace URI to declare, may be null.
325N/A */
325N/A public void declareDefaultNamespace(String namespaceURI) {
325N/A declareNamespace("", namespaceURI);
325N/A }
325N/A
325N/A /**
325N/A * Declare a namespace.
325N/A * <p>
325N/A * The namespace will be declared on the current namespace context.
325N/A * <p>
325N/A * The namespace can be removed by popping the current namespace
325N/A * context, or, if the declaration occured in the root context, by
325N/A * reseting the namespace context.
325N/A * <p>
325N/A * A default namespace can be declared by passing <code>""</code> as
325N/A * the value of the prefix parameter.
325N/A * A namespace may be undeclared by passing <code>null</code> as the
325N/A * value of the namespaceURI parameter.
325N/A * <p>
325N/A * @param prefix the namespace prefix to declare, may not be null.
325N/A * @param namespaceURI the namespace URI to declare, may be null.
325N/A * @throws IllegalArgumentException, if the prefix is null.
325N/A */
325N/A public void declareNamespace(String prefix, String namespaceURI) {
325N/A if (prefix == null) throw new IllegalArgumentException();
325N/A
325N/A prefix = prefix.intern();
325N/A // Ignore the "xml" or "xmlns" declarations
325N/A if (prefix == "xml" || prefix == "xmlns")
325N/A return;
325N/A
325N/A // Check for undeclaration
325N/A if (namespaceURI != null)
325N/A namespaceURI = namespaceURI.intern();
325N/A
325N/A if (namespacePosition == namespaceURIs.length)
325N/A resizeNamespaces();
325N/A
325N/A // Add new declaration
325N/A prefixes[namespacePosition] = prefix;
325N/A namespaceURIs[namespacePosition++] = namespaceURI;
325N/A }
325N/A
325N/A private void resizeNamespaces() {
325N/A final int newLength = namespaceURIs.length * 3 / 2 + 1;
325N/A
325N/A String[] newPrefixes = new String[newLength];
325N/A System.arraycopy(prefixes, 0, newPrefixes, 0, prefixes.length);
325N/A prefixes = newPrefixes;
325N/A
325N/A String[] newNamespaceURIs = new String[newLength];
325N/A System.arraycopy(namespaceURIs, 0, newNamespaceURIs, 0, namespaceURIs.length);
325N/A namespaceURIs = newNamespaceURIs;
325N/A }
325N/A
325N/A /**
325N/A * Push a namespace context on the stack.
325N/A */
325N/A public void pushContext() {
325N/A if (contextPosition == contexts.length)
325N/A resizeContexts();
325N/A
325N/A contexts[contextPosition++] = currentContext = namespacePosition;
325N/A }
325N/A
325N/A private void resizeContexts() {
325N/A int[] newContexts = new int[contexts.length * 3 / 2 + 1];
325N/A System.arraycopy(contexts, 0, newContexts, 0, contexts.length);
325N/A contexts = newContexts;
325N/A }
325N/A
325N/A /**
325N/A * Pop the namespace context off the stack.
325N/A * <p>
325N/A * Namespaces declared within the context (to be popped)
325N/A * will be removed and no longer be in scope.
325N/A */
325N/A public void popContext() {
325N/A if (contextPosition > 0) {
325N/A namespacePosition = currentContext = contexts[--contextPosition];
325N/A }
325N/A }
325N/A
325N/A /**
325N/A * Reset namespace contexts.
325N/A * <p>
325N/A * Pop all namespace contexts and reset the root context.
325N/A */
325N/A public void resetContexts() {
325N/A currentContext = namespacePosition = 2;
325N/A }
325N/A}