View Javadoc
1   /*
2    * Copyright 2011 Jakub Narloch
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the License
10   * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11   * or implied. See the License for the specific language governing permissions and limitations under
12   * the License.
13   */
14  package org.exolab.castor.xml;
15  
16  import java.util.ArrayList;
17  import java.util.Enumeration;
18  import java.util.List;
19  
20  import org.apache.commons.logging.Log;
21  import org.apache.commons.logging.LogFactory;
22  import org.xml.sax.helpers.AttributeListImpl;
23  
24  /**
25   * This class is an actual namespace stack implementation, responsible for adding and removing
26   * namespace scopes, as well as resolving namespace urls and prefixes by traversing all the
27   * namespace stack.
28   * 
29   * @author <a href="mailto:jmnarloch AT gmail DOT com">Jakub Narloch</a>
30   * @since 1.3.3
31   */
32  @SuppressWarnings("deprecation")
33  public class NamespacesStack {
34  
35    private final Log logger = LogFactory.getLog(this.getClass());
36  
37    /**
38     * Represents the string used for indicating default namespace, by default empty string is used.
39     */
40    private static final String DEFAULT_NAMESPACE = "";
41  
42    /**
43     * Represents a stack of namespaces.
44     */
45    private List<Namespaces> namespaceStack = new ArrayList<Namespaces>();
46  
47    /**
48     * Adds a namespace to current scope.
49     * 
50     * @param namespacePrefix the namespace prefix
51     * @param namespaceUri the namespace uri
52     */
53    public void addNamespace(String namespacePrefix, String namespaceUri) {
54      Namespaces namespaces = getCurrentNamespaceScope();
55      if (namespaces != null) {
56        namespaces.addNamespace(namespacePrefix, namespaceUri);
57      }
58    }
59  
60    /**
61     * Adds the default namespace to current scope.
62     * 
63     * @param namespaceUri the namespace uri
64     */
65    public void addDefaultNamespace(String namespaceUri) {
66      addNamespace(DEFAULT_NAMESPACE, namespaceUri);
67    }
68  
69    /**
70     * Removes the namespace from current scope using the namespace prefix
71     * 
72     * @param namespacePrefix the prefix of the namespace to remove
73     */
74    public void removeNamespace(String namespacePrefix) {
75      getCurrentNamespaceScope().removeNamespace(namespacePrefix);
76    }
77  
78    /**
79     * Retrieves the namespace uri bound to specified prefix.
80     * 
81     * @param namespacePrefix the namespace prefix
82     * 
83     * @return the namespace uri bound to the prefix, or null if no namespace has been bound for the
84     *         given prefix
85     */
86    public String getNamespaceURI(String namespacePrefix) {
87      String namespaceUri = null;
88      for (int ind = namespaceStack.size() - 1; ind >= 0 && namespaceUri == null; ind--) {
89        namespaceUri = namespaceStack.get(ind).getNamespaceURI(namespacePrefix);
90      }
91      return namespaceUri;
92    }
93  
94    /**
95     * Declares the namespaces using the attribute list.
96     * 
97     * @param attributeList the list of attributes containing the namespaces
98     * @param localOnly whether the namespaces will only registered in current namespace context or in
99     *        entire stack
100    */
101   @SuppressWarnings("deprecation")
102   public void declareAsAttributes(AttributeListImpl attributeList, boolean localOnly) {
103     getCurrentNamespaceScope().declareAsAttributes(attributeList);
104     if (!localOnly) {
105       for (int ind = namespaceStack.size() - 1; ind >= 0; ind--) {
106 
107         namespaceStack.get(ind).declareAsAttributes(attributeList);
108       }
109     }
110   }
111 
112   /**
113    * Retrieves the default namespace namespace uri.
114    * 
115    * @return the default namespace uri
116    */
117   public String getDefaultNamespaceURI() {
118     return getNamespaceURI(DEFAULT_NAMESPACE);
119   }
120 
121   /**
122    * Retrieves the namespace prefix for the given namespace uri.
123    * 
124    * @param namespaceUri the namespace uri
125    * 
126    * @return the
127    */
128   public String getNamespacePrefix(String namespaceUri) {
129     String namespacePrefix = null;
130     for (int ind = namespaceStack.size() - 1; ind >= 0 && namespacePrefix == null; ind--) {
131       namespacePrefix = namespaceStack.get(ind).getNamespacePrefix(namespaceUri);
132     }
133     return namespacePrefix;
134   }
135 
136   /**
137    * Retrieves the non default namespace prefix for the given namespace uri.
138    * 
139    * @param namespaceUri the namespace uri
140    * 
141    * @return the
142    */
143   public String getNonDefaultNamespacePrefix(String namespaceUri) {
144     String namespacePrefix = null;
145     for (int ind = namespaceStack.size() - 1; ind >= 0 && namespacePrefix == null; ind--) {
146       namespacePrefix = namespaceStack.get(ind).getNonDefaultNamespacePrefix(namespaceUri);
147     }
148     return namespacePrefix;
149   }
150 
151   /**
152    * Retrieves the namespace prefixes registered in current scope.
153    * 
154    * @return the enumeration of namespace prefixes
155    */
156   public Enumeration<String> getLocalNamespacePrefixes() {
157     Namespaces namespaces = getCurrentNamespaceScope();
158     return namespaces != null ? namespaces.getLocalNamespacePrefixes() : null;
159   }
160 
161   /**
162    * Adds a new namespace scope.
163    */
164   public void addNewNamespaceScope() {
165     namespaceStack.add(new Namespaces());
166   }
167 
168   /**
169    * Removes the namespace scope.
170    */
171   public void removeNamespaceScope() {
172     // removes the current namespace
173     if (!namespaceStack.isEmpty()) {
174       namespaceStack.remove(namespaceStack.size() - 1);
175     } else {
176       this.logger.error("Trying to remove a namespaces scope from an empty stack of Namespaces");
177     }
178   }
179 
180   /**
181    * Retrieves the current namespace scope.
182    * 
183    * @return the current namespace scope.
184    */
185   public Namespaces getCurrentNamespaceScope() {
186     if (namespaceStack.isEmpty()) {
187       addNewNamespaceScope();
188     }
189     return namespaceStack.get(namespaceStack.size() - 1);
190   }
191 }