package org.exolab.castor.xml.parsing;
import java.util.Enumeration;
import java.util.HashMap;
import org.castor.core.util.StringUtil;
import org.exolab.castor.mapping.FieldHandler;
import org.exolab.castor.mapping.MapItem;
import org.exolab.castor.xml.Namespaces;
import org.exolab.castor.xml.NodeType;
import org.exolab.castor.xml.UnmarshalHandler;
import org.exolab.castor.xml.XMLClassDescriptor;
import org.exolab.castor.xml.XMLFieldDescriptor;
import org.xml.sax.SAXException;
/**
* This class is used by the {@link UnmarshalHandler} to handle name spaces. It
* manages a stack of name spaces, keeps track of when an new name space scope
* is needed and maps name space URIs to package names.
*
* @author <a href="mailto:philipp DOT erlacher AT gmail DOT com">Philipp
* Erlacher</a>
*
* @since 1.3.2
*/
public class NamespaceHandling {
/**
* The name space stack.
*/
private Namespaces _namespaces = new Namespaces();
/**
* A map of name space URIs to package names.
*/
private HashMap<String, String> _namespaceToPackage = new HashMap<String, String>();
/**
* A flag to keep track of when a new name space scope is needed.
*/
private boolean _createNamespaceScope = true;
/**
* The built-in XML prefix used for xml:space, xml:lang and, as the XML 1.0
* Namespaces document specifies, are reserved for use by XML and XML
* related specs.
**/
private static final String XML_PREFIX = "xml";
/**
* Adds a mapping from the given namespace URI to the given package name.
*
* @param nsURI
* the namespace URI to map from.
* @param packageName
* the package name to map to.
*/
public void addNamespaceToPackageMapping(String nsURI, String packageName) {
_namespaceToPackage.put(StringUtil.defaultString(nsURI), StringUtil
.defaultString(packageName));
}
/**
* Looks up the package name from the given namespace URI.
*
* @param namespace
* the namespace URI to lookup
* @return the package name or null.
*/
public String getMappedPackage(final String namespace) {
return _namespaceToPackage.get(StringUtil.defaultString(namespace));
}
/**
* Saves local namespace declarations to the object model if necessary.
*
* @param classDesc
* the current ClassDescriptor.
* @param object
* the Object of the current state
**/
public void processNamespaces(XMLClassDescriptor classDesc, Object object) {
if (classDesc == null) {
return;
}
// -- process namespace nodes
XMLFieldDescriptor nsDescriptor = classDesc.getFieldDescriptor(null,
null, NodeType.Namespace);
if (nsDescriptor != null) {
FieldHandler handler = nsDescriptor.getHandler();
if (handler != null) {
Enumeration<String> enumeration = _namespaces
.getLocalNamespacePrefixes();
while (enumeration.hasMoreElements()) {
String nsPrefix = StringUtil.defaultString(enumeration
.nextElement());
String nsURI = StringUtil.defaultString(_namespaces
.getNamespaceURI(nsPrefix));
MapItem mapItem = new MapItem(nsPrefix, nsURI);
handler.setValue(object, mapItem);
}
}
}
}
/**
* Extracts the prefix and resolves it to it's associated namespace. If the
* prefix is 'xml', then no resolution will occur, however in all other
* cases the resolution will change the prefix:value as {NamespaceURI}value
*
* @param value
* the QName to resolve.
* @return
* @throws SAXException
* if the nammespace associated with the prefix is null
*/
public Object resolveNamespace(Object value) throws SAXException {
if ((value == null) || !(value instanceof String)) {
return value;
}
String result = (String) value;
int idx = result.indexOf(':');
String prefix = null;
if (idx > 0) {
prefix = result.substring(0, idx);
if (XML_PREFIX.equals(prefix)) {
// -- Do NOT Resolve the 'xml' prefix.
return value;
}
result = result.substring(idx + 1);
}
String namespace = getNamespaceURI(prefix);
if (StringUtil.isNotEmpty(namespace)) {
result = '{' + namespace + '}' + result;
return result;
} else if ((namespace == null) && (prefix != null)) {
throw new SAXException(
"The namespace associated with the prefix: '" + prefix
+ "' is null.");
} else {
return result;
}
}
/**
* Pops the current namespace instance
*/
public void removeCurrentNamespaceInstance() {
_namespaces = _namespaces.getParent();
}
/**
* Binds the namespaceURI to the default namespace.
*
* @param namespaceURI
* Namespace URI
*/
public void addDefaultNamespace(String namespaceURI) {
_namespaces.addNamespace("", namespaceURI);
}
/**
* Binds the namespaceURI to the prefix
*
* @param prefix
* XML name space prefix
* @param namespaceURI
* XML name space URI.
*/
public void addNamespace(String prefix, String namespaceURI) {
_namespaces.addNamespace(prefix, namespaceURI);
}
/**
* Gets the prefix that is bound to a namespaceURI.
*
* @param namespaceURI
* the namespaceURI to get the prefix from
* @return prefix
*/
public String getNamespacePrefix(String namespaceURI) {
return _namespaces.getNamespacePrefix(namespaceURI);
}
/**
* Gets the namespaceURI that is bound to a prefix.
*
* @param prefix
* the prefix to get the namespaceURI from
* @return namespaceURI The corresponding namespace URI.
*/
public String getNamespaceURI(String prefix) {
return _namespaces.getNamespaceURI(prefix);
}
/**
* Gets the namespace URI that is bound to the default name space.
*
* @return namespaceURI The namespace URI bound to the default namespace.
*/
public String getDefaultNamespaceURI() {
return _namespaces.getNamespacePrefix("");
}
/**
* Creates a new name space.
*/
public void createNamespace() {
_namespaces = _namespaces.createNamespaces();
}
/**
* Returns the current name space context.
* @return The current name space stack (context).
*/
public Namespaces getNamespaceContext() {
return _namespaces;
}
/**
* Indicates whether a new name space scope is needed.
*
* @return true if a new name space scope is necessary.
*/
public boolean isNewNamespaceScopeNecessary() {
if (_createNamespaceScope) {
return true;
}
return false;
}
/**
* Starts a new name space scope, and resets the corresponding flag.
*/
public void startNamespaceScope() {
createNamespace();
_createNamespaceScope = true;
}
/**
* Stops a name space scope, and resets the corresponding flag to false.
*/
public void stopNamespaceScope() {
createNamespace();
_createNamespaceScope = false;
}
}