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