View Javadoc
1   package org.exolab.castor.xml.parsing;
2   
3   import java.util.Enumeration;
4   import java.util.HashMap;
5   
6   import org.apache.commons.lang3.StringUtils;
7   import org.exolab.castor.mapping.FieldHandler;
8   import org.exolab.castor.mapping.MapItem;
9   import org.exolab.castor.xml.*;
10  import org.xml.sax.SAXException;
11  
12  /**
13   * This class is used by the {@link UnmarshalHandler} to handle name spaces. It manages a stack of
14   * name spaces, keeps track of when an new name space scope is needed and maps name space URIs to
15   * package names.
16   * 
17   * @author <a href="mailto:philipp DOT erlacher AT gmail DOT com">Philipp Erlacher</a>
18   * 
19   * @since 1.3.2
20   */
21  public class NamespaceHandling {
22  
23    /**
24     * Represents the namespace stack.
25     */
26    private NamespacesStack namespacesStack = new NamespacesStack();
27  
28    /**
29     * A map of name space URIs to package names.
30     */
31    private HashMap<String, String> _namespaceToPackage = new HashMap<String, String>();
32  
33    /**
34     * A flag to keep track of when a new name space scope is needed.
35     */
36    private boolean _createNamespaceScope = true;
37  
38    /**
39     * The built-in XML prefix used for xml:space, xml:lang and, as the XML 1.0 Namespaces document
40     * specifies, are reserved for use by XML and XML related specs.
41     **/
42    private static final String XML_PREFIX = "xml";
43  
44    /**
45     * Adds a mapping from the given namespace URI to the given package name.
46     * 
47     * @param nsURI the namespace URI to map from.
48     * @param packageName the package name to map to.
49     */
50    public void addNamespaceToPackageMapping(String nsURI, String packageName) {
51      _namespaceToPackage.put(StringUtils.defaultString(nsURI),
52          StringUtils.defaultString(packageName));
53  
54    }
55  
56    /**
57     * Looks up the package name from the given namespace URI.
58     * 
59     * @param namespace the namespace URI to lookup
60     * @return the package name or null.
61     */
62    public String getMappedPackage(final String namespace) {
63      return _namespaceToPackage.get(StringUtils.defaultString(namespace));
64    }
65  
66    /**
67     * Saves local namespace declarations to the object model if necessary.
68     * 
69     * @param classDesc the current ClassDescriptor.
70     * @param object the Object of the current state
71     **/
72    public void processNamespaces(XMLClassDescriptor classDesc, Object object) {
73  
74      if (classDesc == null) {
75        return;
76      }
77  
78      // -- process namespace nodes
79      XMLFieldDescriptor nsDescriptor = classDesc.getFieldDescriptor(null, null, NodeType.Namespace);
80  
81      if (nsDescriptor != null) {
82        FieldHandler handler = nsDescriptor.getHandler();
83        if (handler != null) {
84          Enumeration<String> enumeration = namespacesStack.getLocalNamespacePrefixes();
85          while (enumeration.hasMoreElements()) {
86            String nsPrefix = StringUtils.defaultString(enumeration.nextElement());
87            String nsURI = StringUtils.defaultString(namespacesStack.getNamespaceURI(nsPrefix));
88            MapItem mapItem = new MapItem(nsPrefix, nsURI);
89            handler.setValue(object, mapItem);
90          }
91        }
92      }
93    }
94  
95    /**
96     * Extracts the prefix and resolves it to it's associated namespace. If the prefix is 'xml', then
97     * no resolution will occur, however in all other cases the resolution will change the
98     * prefix:value as {NamespaceURI}value
99     * 
100    * @param value the QName to resolve.
101    * @return
102    * @throws SAXException if the nammespace associated with the prefix is null
103    */
104   public Object resolveNamespace(Object value) throws SAXException {
105 
106     if ((value == null) || !(value instanceof String)) {
107       return value;
108     }
109 
110     String result = (String) value;
111     int idx = result.indexOf(':');
112     String prefix = null;
113     if (idx > 0) {
114       prefix = result.substring(0, idx);
115       if (XML_PREFIX.equals(prefix)) {
116         // -- Do NOT Resolve the 'xml' prefix.
117         return value;
118       }
119       result = result.substring(idx + 1);
120     }
121     String namespace = getNamespaceURI(prefix);
122     if (StringUtils.isNotEmpty(namespace)) {
123       result = '{' + namespace + '}' + result;
124       return result;
125     } else if ((namespace == null) && (prefix != null)) {
126       throw new SAXException("The namespace associated with the prefix: '" + prefix + "' is null.");
127     } else {
128       return result;
129     }
130 
131   }
132 
133   /**
134    * Pops the current namespace instance
135    */
136   public void removeCurrentNamespaceInstance() {
137     namespacesStack.removeNamespaceScope();
138   }
139 
140   /**
141    * Binds the namespaceURI to the default namespace.
142    * 
143    * @param namespaceURI Namespace URI
144    */
145   public void addDefaultNamespace(String namespaceURI) {
146     namespacesStack.addDefaultNamespace(namespaceURI);
147   }
148 
149   /**
150    * Binds the namespaceURI to the prefix
151    * 
152    * @param prefix XML name space prefix
153    * @param namespaceURI XML name space URI.
154    */
155   public void addNamespace(String prefix, String namespaceURI) {
156     namespacesStack.addNamespace(prefix, namespaceURI);
157 
158   }
159 
160   /**
161    * Gets the prefix that is bound to a namespaceURI.
162    * 
163    * @param namespaceURI the namespaceURI to get the prefix from
164    * @return prefix
165    */
166   public String getNamespacePrefix(String namespaceURI) {
167     return namespacesStack.getNamespacePrefix(namespaceURI);
168   }
169 
170   /**
171    * Gets the namespaceURI that is bound to a prefix.
172    * 
173    * @param prefix the prefix to get the namespaceURI from
174    * @return namespaceURI The corresponding namespace URI.
175    */
176   public String getNamespaceURI(String prefix) {
177     return namespacesStack.getNamespaceURI(prefix);
178   }
179 
180   /**
181    * Gets the namespace URI that is bound to the default name space.
182    * 
183    * @return namespaceURI The namespace URI bound to the default namespace.
184    */
185   public String getDefaultNamespaceURI() {
186     return namespacesStack.getDefaultNamespaceURI();
187   }
188 
189   /**
190    * Creates a new name space.
191    */
192   public void createNamespace() {
193     namespacesStack.addNewNamespaceScope();
194   }
195 
196   /**
197    * Returns the namespace stack.
198    * 
199    * @return the namespace stack.
200    */
201   public NamespacesStack getNamespaceStack() {
202     return namespacesStack;
203   }
204 
205   /**
206    * Indicates whether a new name space scope is needed.
207    * 
208    * @return true if a new name space scope is necessary.
209    */
210   public boolean isNewNamespaceScopeNecessary() {
211     if (_createNamespaceScope) {
212       return true;
213     }
214     return false;
215   }
216 
217   /**
218    * Starts a new name space scope, and resets the corresponding flag.
219    */
220   public void startNamespaceScope() {
221     createNamespace();
222     _createNamespaceScope = true;
223   }
224 
225   /**
226    * Stops a name space scope, and resets the corresponding flag to false.
227    */
228   public void stopNamespaceScope() {
229     createNamespace();
230     _createNamespaceScope = false;
231   }
232 
233   public void setNewNamespaceScopeNecessary(boolean value) {
234     _createNamespaceScope = value;
235 
236   }
237 }