001: /*
002: * $Id: SimpleNamespaceContext.java,v 1.7 2004/07/14 13:23:54 cniles Exp $
003: *
004: * Copyright (c) 2004, Christian Niles, unit12.net
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions are met:
009: *
010: * * Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * * Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: *
017: * * Neither the name of Christian Niles, Unit12, nor the names of its
018: * contributors may be used to endorse or promote products derived from
019: * this software without specific prior written permission.
020: *
021: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
022: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
023: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
024: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
025: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
026: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
027: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
028: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
029: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
030: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
031: * POSSIBILITY OF SUCH DAMAGE.
032: *
033: */
034: package javanet.staxutils;
035:
036: import java.util.Collections;
037: import java.util.LinkedHashMap;
038: import java.util.HashSet;
039: import java.util.Iterator;
040: import java.util.Map;
041: import java.util.Set;
042:
043: import javax.xml.XMLConstants;
044: import javax.xml.namespace.NamespaceContext;
045:
046: /**
047: * Simple NamespaceContext implementation backed by a HashMap.
048: *
049: * @author Christian Niles
050: * @version $Revision: 1.7 $
051: */
052: public class SimpleNamespaceContext implements
053: ExtendedNamespaceContext, StaticNamespaceContext {
054:
055: /**
056: * The parent context, which may be <code>null</code>
057: */
058: protected NamespaceContext parent;
059:
060: /**
061: * map containing bound namespaces, keyed by their prefix. A LinkedHashMap
062: * is used to ensure that {@link #getPrefix(String)} always returns the same
063: * prefix, unless that prefix is removed.
064: */
065: protected Map namespaces = new LinkedHashMap();
066:
067: /**
068: * Constructs a SimpleNamespaceContext with no parent context or namespace
069: * declarations.
070: */
071: public SimpleNamespaceContext() {
072:
073: }
074:
075: /**
076: * Constructs a SimpleNamespaceContext with no parent context that contains
077: * the specified prefixes.
078: *
079: * @param namespaces A Map of namespace URIs, keyed by their prefixes.
080: */
081: public SimpleNamespaceContext(Map namespaces) {
082:
083: if (namespaces != null) {
084:
085: this .namespaces.putAll(namespaces);
086:
087: }
088:
089: }
090:
091: /**
092: * Constructs an empty SimpleNamespaceContext with the given parent. The
093: * parent context will be forwarded any requests for namespaces not declared
094: * in this context.
095: *
096: * @param parent The parent context.
097: */
098: public SimpleNamespaceContext(NamespaceContext parent) {
099:
100: this .parent = parent;
101:
102: }
103:
104: /**
105: * Constructs an empty SimpleNamespaceContext with the given parent. The
106: * parent context will be forwarded any requests for namespaces not declared
107: * in this context.
108: *
109: * @param parent The parent context.
110: * @param namespaces A Map of namespace URIs, keyed by their prefixes.
111: */
112: public SimpleNamespaceContext(NamespaceContext parent,
113: Map namespaces) {
114:
115: this .parent = parent;
116:
117: if (namespaces != null) {
118:
119: this .namespaces.putAll(namespaces);
120:
121: }
122:
123: }
124:
125: /**
126: * Returns a reference to the parent of this context.
127: *
128: * @return The parent context, or <code>null</code> if this is a root
129: * context.
130: */
131: public NamespaceContext getParent() {
132:
133: return parent;
134:
135: }
136:
137: /**
138: * Sets the parent context used to inherit namespace bindings.
139: *
140: * @param parent The new parent context.
141: */
142: public void setParent(NamespaceContext parent) {
143:
144: this .parent = parent;
145:
146: }
147:
148: /**
149: * Determines if this is a root context.
150: *
151: * @return <code>true</code> if this is a root context, <code>false</code>
152: * otherwise.
153: */
154: public boolean isRootContext() {
155:
156: return parent == null;
157:
158: }
159:
160: public String getNamespaceURI(String prefix) {
161:
162: if (prefix == null) {
163:
164: throw new IllegalArgumentException(
165: "prefix argument was null");
166:
167: } else if (prefix.equals(XMLConstants.XML_NS_PREFIX)) {
168:
169: return XMLConstants.XML_NS_URI;
170:
171: } else if (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE)) {
172:
173: return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
174:
175: } else if (namespaces.containsKey(prefix)) {
176:
177: // The StAX spec says to return null for any undefined prefix. To support
178: // undefining a prefix as specified in the Namespaces spec, we store
179: // undefined prefixes as the empty string.
180:
181: String uri = (String) namespaces.get(prefix);
182: if (uri.length() == 0) {
183:
184: return null;
185:
186: } else {
187:
188: return uri;
189:
190: }
191:
192: } else if (parent != null) {
193:
194: return parent.getNamespaceURI(prefix);
195:
196: } else {
197:
198: return null;
199:
200: }
201:
202: }
203:
204: public String getPrefix(String nsURI) {
205:
206: if (nsURI == null) {
207:
208: throw new IllegalArgumentException("nsURI was null");
209:
210: } else if (nsURI.length() == 0) {
211:
212: throw new IllegalArgumentException("nsURI was empty");
213:
214: } else if (nsURI.equals(XMLConstants.XML_NS_URI)) {
215:
216: return XMLConstants.XML_NS_PREFIX;
217:
218: } else if (nsURI.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
219:
220: return XMLConstants.XMLNS_ATTRIBUTE;
221:
222: }
223:
224: Iterator iter = namespaces.entrySet().iterator();
225: while (iter.hasNext()) {
226:
227: Map.Entry entry = (Map.Entry) iter.next();
228: String uri = (String) entry.getValue();
229:
230: if (uri.equals(nsURI)) {
231:
232: return (String) entry.getKey();
233:
234: }
235:
236: }
237:
238: if (parent != null) {
239:
240: return parent.getPrefix(nsURI);
241:
242: } else if (nsURI.length() == 0) {
243:
244: return "";
245:
246: } else {
247:
248: return null;
249:
250: }
251:
252: }
253:
254: /**
255: * Determines if the specified prefix is declared within this context,
256: * irrespective of any ancestor contexts.
257: *
258: * @param prefix The prefix to check.
259: * @return <code>true</code> if the prefix is declared in this context,
260: * <code>false</code> otherwise.
261: */
262: public boolean isPrefixDeclared(String prefix) {
263:
264: return namespaces.containsKey(prefix);
265:
266: }
267:
268: public Iterator getDeclaredPrefixes() {
269:
270: return Collections.unmodifiableCollection(
271: this .namespaces.keySet()).iterator();
272:
273: }
274:
275: /**
276: * Returns the number of namespace prefixes declared in this context.
277: *
278: * @return The number of namespace prefixes declared in this context.
279: */
280: public int getDeclaredPrefixCount() {
281:
282: return namespaces.size();
283:
284: }
285:
286: public Iterator getPrefixes() {
287:
288: if (parent == null
289: || !(parent instanceof ExtendedNamespaceContext)) {
290:
291: return getDeclaredPrefixes();
292:
293: } else {
294:
295: Set prefixes = new HashSet(this .namespaces.keySet());
296:
297: ExtendedNamespaceContext super Ctx = (ExtendedNamespaceContext) parent;
298: for (Iterator i = super Ctx.getPrefixes(); i.hasNext();) {
299:
300: String prefix = (String) i.next();
301: prefixes.add(prefix);
302:
303: }
304:
305: return prefixes.iterator();
306:
307: }
308:
309: }
310:
311: public Iterator getPrefixes(String nsURI) {
312:
313: if (nsURI == null) {
314:
315: throw new IllegalArgumentException("nsURI was null");
316:
317: } else if (nsURI.equals(XMLConstants.XML_NS_URI)) {
318:
319: return Collections.singleton(XMLConstants.XML_NS_PREFIX)
320: .iterator();
321:
322: } else if (nsURI.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
323:
324: return Collections.singleton(XMLConstants.XMLNS_ATTRIBUTE)
325: .iterator();
326:
327: }
328:
329: Set prefixes = null;
330: Iterator iter = namespaces.entrySet().iterator();
331: while (iter.hasNext()) {
332:
333: Map.Entry entry = (Map.Entry) iter.next();
334: String uri = (String) entry.getValue();
335: if (uri.equals(nsURI)) {
336:
337: if (prefixes == null) {
338:
339: prefixes = new HashSet();
340:
341: }
342: prefixes.add(entry.getKey());
343:
344: }
345:
346: }
347:
348: if (parent != null) {
349:
350: for (Iterator i = parent.getPrefixes(nsURI); i.hasNext();) {
351:
352: String prefix = (String) i.next();
353:
354: if (prefixes == null) {
355:
356: prefixes = new HashSet();
357:
358: }
359: prefixes.add(prefix);
360:
361: }
362:
363: }
364:
365: if (prefixes != null) {
366:
367: return Collections.unmodifiableSet(prefixes).iterator();
368:
369: } else if (nsURI.length() == 0) {
370:
371: return Collections.singleton("").iterator();
372:
373: } else {
374:
375: return Collections.EMPTY_LIST.iterator();
376:
377: }
378:
379: }
380:
381: /**
382: * Sets the default namespace in this context.
383: *
384: * @param nsURI The default namespace URI.
385: * @return The previously declared namespace uri, or <code>null</code> if
386: * the default prefix wasn't previously declared in this context.
387: */
388: public String setDefaultNamespace(String nsURI) {
389:
390: if (nsURI != null) {
391:
392: if (nsURI.equals(XMLConstants.XML_NS_URI)) {
393:
394: throw new IllegalArgumentException(
395: "Attempt to map 'xml' uri");
396:
397: } else if (nsURI
398: .equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
399:
400: throw new IllegalArgumentException(
401: "Attempt to map 'xmlns' uri");
402:
403: }
404:
405: return (String) namespaces.put(
406: XMLConstants.DEFAULT_NS_PREFIX, nsURI);
407:
408: } else {
409:
410: // put the empty string to record an undefined prefix
411: return (String) namespaces.put(
412: XMLConstants.DEFAULT_NS_PREFIX, "");
413:
414: }
415:
416: }
417:
418: /**
419: * Declares a namespace binding in this context.
420: *
421: * @param prefix The namespace prefix.
422: * @param nsURI The namespace URI.
423: * @return The previously declared namespace uri, or <code>null</code> if
424: * the prefix wasn't previously declared in this context.
425: */
426: public String setPrefix(String prefix, String nsURI) {
427:
428: if (prefix == null) {
429:
430: throw new NullPointerException("Namespace Prefix was null");
431:
432: } else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
433:
434: return setDefaultNamespace(nsURI);
435:
436: } else if (prefix.equals(XMLConstants.XML_NS_PREFIX)) {
437:
438: throw new IllegalArgumentException(
439: "Attempt to map 'xml' prefix");
440:
441: } else if (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE)) {
442:
443: throw new IllegalArgumentException(
444: "Attempt to map 'xmlns' prefix");
445:
446: } else if (nsURI != null) {
447:
448: if (nsURI.equals(XMLConstants.XML_NS_URI)) {
449:
450: throw new IllegalArgumentException(
451: "Attempt to map 'xml' uri");
452:
453: } else if (nsURI
454: .equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
455:
456: throw new IllegalArgumentException(
457: "Attempt to map 'xmlns' uri");
458:
459: } else {
460:
461: return (String) namespaces.put(prefix, nsURI);
462:
463: }
464:
465: } else {
466:
467: // put the empty string to record an undefined prefix
468: return (String) namespaces.put(prefix, "");
469:
470: }
471:
472: }
473:
474: }
|