/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.jxpath.ri;
import java.io.Serializable;
import java.util.HashMap;
import org.apache.commons.jxpath.Pointer;
import org.apache.commons.jxpath.ri.model.NodeIterator;
import org.apache.commons.jxpath.ri.model.NodePointer;
/**
* Namespace resolver for {@link JXPathContextReferenceImpl}.
*
* @author Dmitri Plotnikov
* @version $Revision: 668329 $ $Date: 2008-06-16 16:59:48 -0500 (Mon, 16 Jun 2008) $
*/
public class NamespaceResolver implements Cloneable, Serializable {
private static final long serialVersionUID = 1085590057838651311L;
/** Parent NamespaceResolver */
protected final NamespaceResolver parent;
/** namespace map */
protected HashMap namespaceMap = new HashMap();
/** reverse lookup map */
protected HashMap reverseMap = new HashMap();
/** pointer */
protected NodePointer pointer;
private boolean sealed;
/**
* Find the namespace prefix for the specified namespace URI and NodePointer.
* @param pointer location
* @param namespaceURI to check
* @return prefix if found
* @since JXPath 1.3
*/
protected static String getPrefix(NodePointer pointer, String namespaceURI) {
NodePointer currentPointer = pointer;
while (currentPointer != null) {
NodeIterator ni = currentPointer.namespaceIterator();
for (int position = 1; ni != null && ni.setPosition(position); position++) {
NodePointer nsPointer = ni.getNodePointer();
String uri = nsPointer.getNamespaceURI();
if (uri.equals(namespaceURI)) {
String prefix = nsPointer.getName().getName();
if (!"".equals(prefix)) {
return prefix;
}
}
}
currentPointer = pointer.getParent();
}
return null;
}
/**
* Create a new NamespaceResolver.
*/
public NamespaceResolver() {
this(null);
}
/**
* Create a new NamespaceResolver.
* @param parent NamespaceResolver
*/
public NamespaceResolver(NamespaceResolver parent) {
this.parent = parent;
}
/**
* Registers a namespace prefix.
*
* @param prefix A namespace prefix
* @param namespaceURI A URI for that prefix
*/
public synchronized void registerNamespace(String prefix, String namespaceURI) {
if (isSealed()) {
throw new IllegalStateException(
"Cannot register namespaces on a sealed NamespaceResolver");
}
namespaceMap.put(prefix, namespaceURI);
reverseMap.put(namespaceURI, prefix);
}
/**
* Register a namespace for the expression context.
* @param pointer the Pointer to set.
*/
public void setNamespaceContextPointer(NodePointer pointer) {
this.pointer = pointer;
}
/**
* Get the namespace context pointer.
* @return Pointer
*/
public Pointer getNamespaceContextPointer() {
if (pointer == null && parent != null) {
return parent.getNamespaceContextPointer();
}
return pointer;
}
/**
* Given a prefix, returns a registered namespace URI. If the requested
* prefix was not defined explicitly using the registerNamespace method,
* JXPathContext will then check the context node to see if the prefix is
* defined there. See
* {@link #setNamespaceContextPointer(NodePointer) setNamespaceContextPointer}.
*
* @param prefix The namespace prefix to look up
* @return namespace URI or null if the prefix is undefined.
*/
public synchronized String getNamespaceURI(String prefix) {
String uri = getExternallyRegisteredNamespaceURI(prefix);
return uri == null && pointer != null ? pointer.getNamespaceURI(prefix)
: uri;
}
/**
* Given a prefix, returns an externally registered namespace URI.
*
* @param prefix The namespace prefix to look up
* @return namespace URI or null if the prefix is undefined.
* @since JXPath 1.3
*/
protected synchronized String getExternallyRegisteredNamespaceURI(
String prefix) {
String uri = (String) namespaceMap.get(prefix);
return uri == null && parent != null ? parent
.getExternallyRegisteredNamespaceURI(prefix) : uri;
}
/**
* Get the prefix associated with the specifed namespace URI.
* @param namespaceURI the ns URI to check.
* @return String prefix
*/
public synchronized String getPrefix(String namespaceURI) {
String prefix = getExternallyRegisteredPrefix(namespaceURI);
return prefix == null && pointer != null ? getPrefix(pointer,
namespaceURI) : prefix;
}
/**
* Get the nearest prefix found that matches an externally-registered namespace.
* @param namespaceURI the ns URI to check.
* @return String prefix if found.
* @since JXPath 1.3
*/
protected synchronized String getExternallyRegisteredPrefix(String namespaceURI) {
String prefix = (String) reverseMap.get(namespaceURI);
return prefix == null && parent != null ? parent
.getExternallyRegisteredPrefix(namespaceURI) : prefix;
}
/**
* Learn whether this NamespaceResolver has been sealed.
* @return boolean
*/
public boolean isSealed() {
return sealed;
}
/**
* Seal this {@link NamespaceResolver}.
*/
public void seal() {
sealed = true;
if (parent != null) {
parent.seal();
}
}
public Object clone() {
try {
NamespaceResolver result = (NamespaceResolver) super.clone();
result.sealed = false;
return result;
}
catch (CloneNotSupportedException e) {
// Of course, it's supported.
e.printStackTrace();
return null;
}
}
}
|