001/*
002 * Copyright 2002-2015 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.util.xml;
018
019import java.util.Collections;
020import java.util.HashMap;
021import java.util.Iterator;
022import java.util.LinkedHashSet;
023import java.util.Map;
024import java.util.Set;
025import javax.xml.XMLConstants;
026import javax.xml.namespace.NamespaceContext;
027
028import org.springframework.util.Assert;
029
030/**
031 * Simple {@code javax.xml.namespace.NamespaceContext} implementation.
032 * Follows the standard {@code NamespaceContext} contract, and is loadable
033 * via a {@code java.util.Map} or {@code java.util.Properties} object
034 *
035 * @author Arjen Poutsma
036 * @author Juergen Hoeller
037 * @since 3.0
038 */
039public class SimpleNamespaceContext implements NamespaceContext {
040
041        private final Map<String, String> prefixToNamespaceUri = new HashMap<String, String>();
042
043        private final Map<String, Set<String>> namespaceUriToPrefixes = new HashMap<String, Set<String>>();
044
045        private String defaultNamespaceUri = "";
046
047
048        @Override
049        public String getNamespaceURI(String prefix) {
050                Assert.notNull(prefix, "No prefix given");
051                if (XMLConstants.XML_NS_PREFIX.equals(prefix)) {
052                        return XMLConstants.XML_NS_URI;
053                }
054                else if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) {
055                        return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
056                }
057                else if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
058                        return this.defaultNamespaceUri;
059                }
060                else if (this.prefixToNamespaceUri.containsKey(prefix)) {
061                        return this.prefixToNamespaceUri.get(prefix);
062                }
063                return "";
064        }
065
066        @Override
067        public String getPrefix(String namespaceUri) {
068                Set<String> prefixes = getPrefixesSet(namespaceUri);
069                return (!prefixes.isEmpty() ? prefixes.iterator().next() : null);
070        }
071
072        @Override
073        public Iterator<String> getPrefixes(String namespaceUri) {
074                return getPrefixesSet(namespaceUri).iterator();
075        }
076
077        private Set<String> getPrefixesSet(String namespaceUri) {
078                Assert.notNull(namespaceUri, "No namespaceUri given");
079                if (this.defaultNamespaceUri.equals(namespaceUri)) {
080                        return Collections.singleton(XMLConstants.DEFAULT_NS_PREFIX);
081                }
082                else if (XMLConstants.XML_NS_URI.equals(namespaceUri)) {
083                        return Collections.singleton(XMLConstants.XML_NS_PREFIX);
084                }
085                else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceUri)) {
086                        return Collections.singleton(XMLConstants.XMLNS_ATTRIBUTE);
087                }
088                else {
089                        Set<String> prefixes = this.namespaceUriToPrefixes.get(namespaceUri);
090                        return (prefixes != null ?  Collections.unmodifiableSet(prefixes) : Collections.<String>emptySet());
091                }
092        }
093
094
095        /**
096         * Set the bindings for this namespace context.
097         * The supplied map must consist of string key value pairs.
098         */
099        public void setBindings(Map<String, String> bindings) {
100                for (Map.Entry<String, String> entry : bindings.entrySet()) {
101                        bindNamespaceUri(entry.getKey(), entry.getValue());
102                }
103        }
104
105        /**
106         * Bind the given namespace as default namespace.
107         * @param namespaceUri the namespace uri
108         */
109        public void bindDefaultNamespaceUri(String namespaceUri) {
110                bindNamespaceUri(XMLConstants.DEFAULT_NS_PREFIX, namespaceUri);
111        }
112
113        /**
114         * Bind the given prefix to the given namespace.
115         * @param prefix the namespace prefix
116         * @param namespaceUri the namespace uri
117         */
118        public void bindNamespaceUri(String prefix, String namespaceUri) {
119                Assert.notNull(prefix, "No prefix given");
120                Assert.notNull(namespaceUri, "No namespaceUri given");
121                if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
122                        this.defaultNamespaceUri = namespaceUri;
123                }
124                else {
125                        this.prefixToNamespaceUri.put(prefix, namespaceUri);
126                        Set<String> prefixes = this.namespaceUriToPrefixes.get(namespaceUri);
127                        if (prefixes == null) {
128                                prefixes = new LinkedHashSet<String>();
129                                this.namespaceUriToPrefixes.put(namespaceUri, prefixes);
130                        }
131                        prefixes.add(prefix);
132                }
133        }
134
135        /**
136         * Remove the given prefix from this context.
137         * @param prefix the prefix to be removed
138         */
139        public void removeBinding(String prefix) {
140                if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
141                        this.defaultNamespaceUri = "";
142                }
143                else if (prefix != null) {
144                        String namespaceUri = this.prefixToNamespaceUri.remove(prefix);
145                        if (namespaceUri != null) {
146                                Set<String> prefixes = this.namespaceUriToPrefixes.get(namespaceUri);
147                                if (prefixes != null) {
148                                        prefixes.remove(prefix);
149                                        if (prefixes.isEmpty()) {
150                                                this.namespaceUriToPrefixes.remove(namespaceUri);
151                                        }
152                                }
153                        }
154                }
155        }
156
157        /**
158         * Remove all declared prefixes.
159         */
160        public void clear() {
161                this.prefixToNamespaceUri.clear();
162                this.namespaceUriToPrefixes.clear();
163        }
164
165        /**
166         * Return all declared prefixes.
167         */
168        public Iterator<String> getBoundPrefixes() {
169                return this.prefixToNamespaceUri.keySet().iterator();
170        }
171
172}