001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.jxpath.ri;
018
019 import java.io.Serializable;
020 import java.util.HashMap;
021
022 import org.apache.commons.jxpath.Pointer;
023 import org.apache.commons.jxpath.ri.model.NodeIterator;
024 import org.apache.commons.jxpath.ri.model.NodePointer;
025
026 /**
027 * Namespace resolver for {@link JXPathContextReferenceImpl}.
028 *
029 * @author Dmitri Plotnikov
030 * @version $Revision: 668329 $ $Date: 2008-06-16 16:59:48 -0500 (Mon, 16 Jun 2008) $
031 */
032 public class NamespaceResolver implements Cloneable, Serializable {
033 private static final long serialVersionUID = 1085590057838651311L;
034
035 /** Parent NamespaceResolver */
036 protected final NamespaceResolver parent;
037 /** namespace map */
038 protected HashMap namespaceMap = new HashMap();
039 /** reverse lookup map */
040 protected HashMap reverseMap = new HashMap();
041 /** pointer */
042 protected NodePointer pointer;
043 private boolean sealed;
044
045 /**
046 * Find the namespace prefix for the specified namespace URI and NodePointer.
047 * @param pointer location
048 * @param namespaceURI to check
049 * @return prefix if found
050 * @since JXPath 1.3
051 */
052 protected static String getPrefix(NodePointer pointer, String namespaceURI) {
053 NodePointer currentPointer = pointer;
054 while (currentPointer != null) {
055 NodeIterator ni = currentPointer.namespaceIterator();
056 for (int position = 1; ni != null && ni.setPosition(position); position++) {
057 NodePointer nsPointer = ni.getNodePointer();
058 String uri = nsPointer.getNamespaceURI();
059 if (uri.equals(namespaceURI)) {
060 String prefix = nsPointer.getName().getName();
061 if (!"".equals(prefix)) {
062 return prefix;
063 }
064 }
065 }
066 currentPointer = pointer.getParent();
067 }
068 return null;
069 }
070
071 /**
072 * Create a new NamespaceResolver.
073 */
074 public NamespaceResolver() {
075 this(null);
076 }
077
078 /**
079 * Create a new NamespaceResolver.
080 * @param parent NamespaceResolver
081 */
082 public NamespaceResolver(NamespaceResolver parent) {
083 this.parent = parent;
084 }
085
086 /**
087 * Registers a namespace prefix.
088 *
089 * @param prefix A namespace prefix
090 * @param namespaceURI A URI for that prefix
091 */
092 public synchronized void registerNamespace(String prefix, String namespaceURI) {
093 if (isSealed()) {
094 throw new IllegalStateException(
095 "Cannot register namespaces on a sealed NamespaceResolver");
096 }
097 namespaceMap.put(prefix, namespaceURI);
098 reverseMap.put(namespaceURI, prefix);
099 }
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 }