1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.jxpath.ri;
18
19 import java.io.Serializable;
20 import java.util.HashMap;
21
22 import org.apache.commons.jxpath.Pointer;
23 import org.apache.commons.jxpath.ri.model.NodeIterator;
24 import org.apache.commons.jxpath.ri.model.NodePointer;
25
26 /**
27 * Namespace resolver for {@link JXPathContextReferenceImpl}.
28 *
29 * @author Dmitri Plotnikov
30 * @version $Revision: 918623 $ $Date: 2010-03-03 13:47:47 -0500 (Wed, 03 Mar 2010) $
31 */
32 public class NamespaceResolver implements Cloneable, Serializable {
33 private static final long serialVersionUID = 1085590057838651311L;
34
35 /** Parent NamespaceResolver */
36 protected final NamespaceResolver parent;
37 /** namespace map */
38 protected HashMap namespaceMap = new HashMap();
39 /** reverse lookup map */
40 protected HashMap reverseMap = new HashMap();
41 /** pointer */
42 protected NodePointer pointer;
43 private boolean sealed;
44
45 /**
46 * Find the namespace prefix for the specified namespace URI and NodePointer.
47 * @param pointer location
48 * @param namespaceURI to check
49 * @return prefix if found
50 * @since JXPath 1.3
51 */
52 protected static String getPrefix(final NodePointer pointer, String namespaceURI) {
53 NodePointer currentPointer = pointer;
54 while (currentPointer != null) {
55 NodeIterator ni = currentPointer.namespaceIterator();
56 for (int position = 1; ni != null && ni.setPosition(position); position++) {
57 NodePointer nsPointer = ni.getNodePointer();
58 String uri = nsPointer.getNamespaceURI();
59 if (uri.equals(namespaceURI)) {
60 String prefix = nsPointer.getName().getName();
61 if (!"".equals(prefix)) {
62 return prefix;
63 }
64 }
65 }
66 currentPointer = currentPointer.getParent();
67 }
68 return null;
69 }
70
71 /**
72 * Create a new NamespaceResolver.
73 */
74 public NamespaceResolver() {
75 this(null);
76 }
77
78 /**
79 * Create a new NamespaceResolver.
80 * @param parent NamespaceResolver
81 */
82 public NamespaceResolver(NamespaceResolver parent) {
83 this.parent = parent;
84 }
85
86 /**
87 * Registers a namespace prefix.
88 *
89 * @param prefix A namespace prefix
90 * @param namespaceURI A URI for that prefix
91 */
92 public synchronized void registerNamespace(String prefix, String namespaceURI) {
93 if (isSealed()) {
94 throw new IllegalStateException(
95 "Cannot register namespaces on a sealed NamespaceResolver");
96 }
97 namespaceMap.put(prefix, namespaceURI);
98 reverseMap.put(namespaceURI, prefix);
99 }
100
101 /**
102 * Register a namespace for the expression context.
103 * @param pointer the Pointer to set.
104 */
105 public void setNamespaceContextPointer(NodePointer pointer) {
106 this.pointer = pointer;
107 }
108
109 /**
110 * Get the namespace context pointer.
111 * @return Pointer
112 */
113 public Pointer getNamespaceContextPointer() {
114 if (pointer == null && parent != null) {
115 return parent.getNamespaceContextPointer();
116 }
117 return pointer;
118 }
119
120 /**
121 * Given a prefix, returns a registered namespace URI. If the requested
122 * prefix was not defined explicitly using the registerNamespace method,
123 * JXPathContext will then check the context node to see if the prefix is
124 * defined there. See
125 * {@link #setNamespaceContextPointer(NodePointer) setNamespaceContextPointer}.
126 *
127 * @param prefix The namespace prefix to look up
128 * @return namespace URI or null if the prefix is undefined.
129 */
130 public synchronized String getNamespaceURI(String prefix) {
131 String uri = getExternallyRegisteredNamespaceURI(prefix);
132 return uri == null && pointer != null ? pointer.getNamespaceURI(prefix)
133 : uri;
134 }
135
136 /**
137 * Given a prefix, returns an externally registered namespace URI.
138 *
139 * @param prefix The namespace prefix to look up
140 * @return namespace URI or null if the prefix is undefined.
141 * @since JXPath 1.3
142 */
143 protected synchronized String getExternallyRegisteredNamespaceURI(
144 String prefix) {
145 String uri = (String) namespaceMap.get(prefix);
146 return uri == null && parent != null ? parent
147 .getExternallyRegisteredNamespaceURI(prefix) : uri;
148 }
149
150 /**
151 * Get the prefix associated with the specifed namespace URI.
152 * @param namespaceURI the ns URI to check.
153 * @return String prefix
154 */
155 public synchronized String getPrefix(String namespaceURI) {
156 String prefix = getExternallyRegisteredPrefix(namespaceURI);
157 return prefix == null && pointer != null ? getPrefix(pointer,
158 namespaceURI) : prefix;
159 }
160
161 /**
162 * Get the nearest prefix found that matches an externally-registered namespace.
163 * @param namespaceURI the ns URI to check.
164 * @return String prefix if found.
165 * @since JXPath 1.3
166 */
167 protected synchronized String getExternallyRegisteredPrefix(String namespaceURI) {
168 String prefix = (String) reverseMap.get(namespaceURI);
169 return prefix == null && parent != null ? parent
170 .getExternallyRegisteredPrefix(namespaceURI) : prefix;
171 }
172
173 /**
174 * Learn whether this NamespaceResolver has been sealed.
175 * @return boolean
176 */
177 public boolean isSealed() {
178 return sealed;
179 }
180
181 /**
182 * Seal this {@link NamespaceResolver}.
183 */
184 public void seal() {
185 sealed = true;
186 if (parent != null) {
187 parent.seal();
188 }
189 }
190
191 public Object clone() {
192 try {
193 NamespaceResolver result = (NamespaceResolver) super.clone();
194 result.sealed = false;
195 return result;
196 }
197 catch (CloneNotSupportedException e) {
198 // Of course, it's supported.
199 e.printStackTrace();
200 return null;
201 }
202 }
203 }