Skip to content

Commit f8860e2

Browse files
committed
SimpleNamespaceContext implements all subtleties of the NamespaceContext contract
Issue: SPR-13713
1 parent 4668aa7 commit f8860e2

File tree

2 files changed

+217
-126
lines changed

2 files changed

+217
-126
lines changed
Lines changed: 75 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2015 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,66 +16,85 @@
1616

1717
package org.springframework.util.xml;
1818

19-
import java.util.ArrayList;
2019
import java.util.Collections;
2120
import java.util.HashMap;
2221
import java.util.Iterator;
23-
import java.util.List;
22+
import java.util.LinkedHashSet;
2423
import java.util.Map;
24+
import java.util.Set;
2525
import javax.xml.XMLConstants;
2626
import javax.xml.namespace.NamespaceContext;
2727

2828
import org.springframework.util.Assert;
2929

3030
/**
31-
* Simple {@code javax.xml.namespace.NamespaceContext} implementation. Follows the standard
32-
* {@code NamespaceContext} contract, and is loadable via a {@code java.util.Map} or
33-
* {@code java.util.Properties} object
31+
* Simple {@code javax.xml.namespace.NamespaceContext} implementation.
32+
* Follows the standard {@code NamespaceContext} contract, and is loadable
33+
* via a {@code java.util.Map} or {@code java.util.Properties} object
3434
*
3535
* @author Arjen Poutsma
36+
* @author Juergen Hoeller
3637
* @since 3.0
3738
*/
3839
public class SimpleNamespaceContext implements NamespaceContext {
3940

40-
private Map<String, String> prefixToNamespaceUri = new HashMap<String, String>();
41+
private final Map<String, String> prefixToNamespaceUri = new HashMap<String, String>();
4142

42-
private Map<String, List<String>> namespaceUriToPrefixes = new HashMap<String, List<String>>();
43+
private final Map<String, Set<String>> namespaceUriToPrefixes = new HashMap<String, Set<String>>();
4344

4445
private String defaultNamespaceUri = "";
4546

47+
4648
@Override
4749
public String getNamespaceURI(String prefix) {
48-
Assert.notNull(prefix, "prefix is null");
50+
Assert.notNull(prefix, "No prefix given");
4951
if (XMLConstants.XML_NS_PREFIX.equals(prefix)) {
5052
return XMLConstants.XML_NS_URI;
5153
}
5254
else if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) {
5355
return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
5456
}
5557
else if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
56-
return defaultNamespaceUri;
58+
return this.defaultNamespaceUri;
5759
}
58-
else if (prefixToNamespaceUri.containsKey(prefix)) {
59-
return prefixToNamespaceUri.get(prefix);
60+
else if (this.prefixToNamespaceUri.containsKey(prefix)) {
61+
return this.prefixToNamespaceUri.get(prefix);
6062
}
6163
return "";
6264
}
6365

6466
@Override
6567
public String getPrefix(String namespaceUri) {
66-
List<?> prefixes = getPrefixesInternal(namespaceUri);
67-
return prefixes.isEmpty() ? null : (String) prefixes.get(0);
68+
Set<String> prefixes = getPrefixesSet(namespaceUri);
69+
return (!prefixes.isEmpty() ? prefixes.iterator().next() : null);
6870
}
6971

7072
@Override
7173
public Iterator<String> getPrefixes(String namespaceUri) {
72-
return getPrefixesInternal(namespaceUri).iterator();
74+
return getPrefixesSet(namespaceUri).iterator();
7375
}
7476

77+
private Set<String> getPrefixesSet(String namespaceUri) {
78+
Assert.notNull(namespaceUri, "No namespaceUri given");
79+
if (this.defaultNamespaceUri.equals(namespaceUri)) {
80+
return Collections.singleton(XMLConstants.DEFAULT_NS_PREFIX);
81+
}
82+
else if (XMLConstants.XML_NS_URI.equals(namespaceUri)) {
83+
return Collections.singleton(XMLConstants.XML_NS_PREFIX);
84+
}
85+
else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceUri)) {
86+
return Collections.singleton(XMLConstants.XMLNS_ATTRIBUTE);
87+
}
88+
else {
89+
Set<String> prefixes = this.namespaceUriToPrefixes.get(namespaceUri);
90+
return (prefixes != null ? Collections.unmodifiableSet(prefixes) : Collections.<String>emptySet());
91+
}
92+
}
93+
94+
7595
/**
76-
* Sets the bindings for this namespace context. The supplied map must consist of string key value pairs.
77-
*
78-
* @param bindings the bindings
96+
* Set the bindings for this namespace context.
97+
* The supplied map must consist of string key value pairs.
7998
*/
8099
public void setBindings(Map<String, String> bindings) {
81100
for (Map.Entry<String, String> entry : bindings.entrySet()) {
@@ -84,79 +103,70 @@ public void setBindings(Map<String, String> bindings) {
84103
}
85104

86105
/**
87-
* Binds the given namespace as default namespace.
88-
*
106+
* Bind the given namespace as default namespace.
89107
* @param namespaceUri the namespace uri
90108
*/
91109
public void bindDefaultNamespaceUri(String namespaceUri) {
92110
bindNamespaceUri(XMLConstants.DEFAULT_NS_PREFIX, namespaceUri);
93111
}
94112

95113
/**
96-
* Binds the given prefix to the given namespace.
97-
*
98-
* @param prefix the namespace prefix
114+
* Bind the given prefix to the given namespace.
115+
* @param prefix the namespace prefix
99116
* @param namespaceUri the namespace uri
100117
*/
101118
public void bindNamespaceUri(String prefix, String namespaceUri) {
102119
Assert.notNull(prefix, "No prefix given");
103120
Assert.notNull(namespaceUri, "No namespaceUri given");
104121
if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
105-
defaultNamespaceUri = namespaceUri;
122+
this.defaultNamespaceUri = namespaceUri;
106123
}
107124
else {
108-
prefixToNamespaceUri.put(prefix, namespaceUri);
109-
getPrefixesInternal(namespaceUri).add(prefix);
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);
110132
}
111133
}
112134

113-
/** Removes all declared prefixes. */
114-
public void clear() {
115-
prefixToNamespaceUri.clear();
116-
}
117-
118135
/**
119-
* Returns all declared prefixes.
120-
*
121-
* @return the declared prefixes
136+
* Remove the given prefix from this context.
137+
* @param prefix the prefix to be removed
122138
*/
123-
public Iterator<String> getBoundPrefixes() {
124-
return prefixToNamespaceUri.keySet().iterator();
125-
}
126-
127-
private List<String> getPrefixesInternal(String namespaceUri) {
128-
if (defaultNamespaceUri.equals(namespaceUri)) {
129-
return Collections.singletonList(XMLConstants.DEFAULT_NS_PREFIX);
130-
}
131-
else if (XMLConstants.XML_NS_URI.equals(namespaceUri)) {
132-
return Collections.singletonList(XMLConstants.XML_NS_PREFIX);
133-
}
134-
else if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceUri)) {
135-
return Collections.singletonList(XMLConstants.XMLNS_ATTRIBUTE);
139+
public void removeBinding(String prefix) {
140+
if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
141+
this.defaultNamespaceUri = "";
136142
}
137-
else {
138-
List<String> list = namespaceUriToPrefixes.get(namespaceUri);
139-
if (list == null) {
140-
list = new ArrayList<String>();
141-
namespaceUriToPrefixes.put(namespaceUri, list);
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+
}
142153
}
143-
return list;
144154
}
145155
}
146156

147157
/**
148-
* Removes the given prefix from this context.
149-
*
150-
* @param prefix the prefix to be removed
158+
* Remove all declared prefixes.
151159
*/
152-
public void removeBinding(String prefix) {
153-
if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
154-
defaultNamespaceUri = "";
155-
}
156-
else {
157-
String namespaceUri = prefixToNamespaceUri.remove(prefix);
158-
List<String> prefixes = getPrefixesInternal(namespaceUri);
159-
prefixes.remove(prefix);
160-
}
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();
161170
}
171+
162172
}

0 commit comments

Comments
 (0)