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 */ 017package org.apache.commons.jxpath.ri; 018 019import java.io.Serializable; 020import java.util.HashMap; 021 022import org.apache.commons.jxpath.Pointer; 023import org.apache.commons.jxpath.ri.model.NodeIterator; 024import org.apache.commons.jxpath.ri.model.NodePointer; 025 026/** 027 * Namespace resolver for {@link JXPathContextReferenceImpl}. 028 * 029 * @author Dmitri Plotnikov 030 * @version $Revision: 918623 $ $Date: 2010-03-03 19:47:47 +0100 (Mi, 03 Mär 2010) $ 031 */ 032public 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(final 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 = currentPointer.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}