jlibs.xml.DefaultNamespaceContext Maven / Gradle / Ivy
/**
* Copyright 2015 Santhosh Kumar Tekuri
*
* The JLibs authors license 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 jlibs.xml;
import jlibs.core.net.URLUtil;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import java.util.*;
/**
* This is an implementation of {@link NamespaceContext}.
*
* Example Usage:
*
* import jlibs.core.lang.StringUtil;
* import jlibs.xml.DefaultNamespaceContext;
* import jlibs.xml.Namespaces;
*
* DefaultNamespaceContext nsContext = new DefaultNamespaceContext();
* nsContext.declarePrefix("xsd", Namespaces.URI_XSD)
* nsContext.declarePrefix("jlibs", "http://code.google.com/p/jlibs");
* nsContext.declarePrefix("tns", "http://code.google.com/p/jlibs");
*
* System.out.println(nsContext.getPrefix("http://code.google.com/p/jlibs")); // prints "jlibs"
* System.out.println(nsContext.getNamespaceURI("jlibs"); // prints "http://code.google.com/p/jlibs"
* System.out.println(StringUtil.{@link jlibs.core.lang.StringUtil#join(java.util.Iterator) join}(nsContext.getPrefixes("http://code.google.com/p/jlibs"))); // prints "jlibs, tns"
*
*
* Prefix Suggestions:
*
* You can speficy the suggested {@code prefix} for a {@code uri} by passing {@link java.util.Properties} to the {@link #DefaultNamespaceContext(java.util.Properties) constructor}
* If {@link #DefaultNamespaceContext() no-arg constructor} is used, then it uses {@link Namespaces#getSuggested()} as suggestions.
*
* Thus you can declare a {@code uri} without specified {@code prefix} manually. It finds the {@code prefix} automatically and returns the {@code prefix} it used.
*
* System.out.println(nsContext.{@link #declarePrefix(String) declarePrefix}("http://www.google.com")); // returns "google"
*
*
* This class also provides a handy method to compute {@code javax.xml.namespace.QName}:
*
* javax.xml.namespace.QName qname = nsContext.{@link #toQName(String) toQName}("tns:myElement");
* System.out.println(qname); // prints "{http://code.google.com/p/jlibs}myElement"
*
* @author Santhosh Kumar T
*/
public class DefaultNamespaceContext implements NamespaceContext{
private Properties suggested;
private Map prefix2uriMap = new HashMap();
private Map uri2prefixMap = new HashMap();
private String defaultURI = XMLConstants.NULL_NS_URI;
/**
* Creates new instance of DefaultNamespaceContext with suggested prefixes
* {@link Namespaces#getSuggested()}
*
* @see #declarePrefix(String)
*/
public DefaultNamespaceContext(){
this(Namespaces.getSuggested());
}
/**
* Creates new instance of DefaultNamespaceContext with specified suggested prefixes
*
* @param suggested suggested prefixes, where key is {@code URI} and value is suggested {@code prefix}
*
* @see #declarePrefix(String)
*/
public DefaultNamespaceContext(Properties suggested){
this.suggested = suggested;
declarePrefix(XMLConstants.DEFAULT_NS_PREFIX, XMLConstants.NULL_NS_URI);
declarePrefix(XMLConstants.XML_NS_PREFIX, XMLConstants.XML_NS_URI);
declarePrefix(XMLConstants.XMLNS_ATTRIBUTE, XMLConstants.XMLNS_ATTRIBUTE_NS_URI);
}
@Override
public String getNamespaceURI(String prefix){
if(prefix==null)
throw new IllegalArgumentException("prefix is null");
if(prefix.length()==0)
return defaultURI;
return prefix2uriMap.get(prefix);
}
@Override
public String getPrefix(String namespaceURI){
if(namespaceURI==null)
throw new IllegalArgumentException("namespaceURI is null");
if(defaultURI.equals(namespaceURI))
return XMLConstants.DEFAULT_NS_PREFIX;
return uri2prefixMap.get(namespaceURI);
}
@Override
public Iterator getPrefixes(String namespaceURI){
List list = new ArrayList(prefix2uriMap.size());
for(Map.Entry entry: prefix2uriMap.entrySet()){
if(entry.getValue().equals(namespaceURI))
list.add(entry.getKey());
}
return list.iterator();
}
/**
* Binds specified {@code prefix} to the given {@code uri}
*
* @param prefix the prefix to be bound
* @param uri the uri to which specified {@code prefix} to be bound
*/
public void declarePrefix(String prefix, String uri){
if(prefix.length()==0)
defaultURI = uri;
prefix2uriMap.put(prefix, uri);
uri2prefixMap.put(uri, prefix);
}
/**
* Declared the specified {@code uri} in this namespaceContext and returns
* the prefix to which it is bound.
*
* the prefix is guessed from the suggested namespaces specified at construction
* or derived from the specified {@code uri}
*
* @param uri uri to be declared
*
* @return the prefix to which {@code uri} is bound
*
* @see jlibs.core.net.URLUtil#suggestPrefix(java.util.Properties, String)
*/
public String declarePrefix(String uri){
String prefix = getPrefix(uri);
if(prefix==null){
prefix = URLUtil.suggestPrefix(suggested, uri);
if(getNamespaceURI(prefix)!=null){
int i = 1;
String _prefix;
while(true){
_prefix = prefix + i;
if(getNamespaceURI(_prefix)==null){
prefix = _prefix;
break;
}
i++;
}
}
declarePrefix(prefix, uri);
}
return prefix;
}
/**
* Constructs {@link javax.xml.namespace.QName} for the specified {@code qname}.
*
* @param qname the qualified name
* @return {@link javax.xml.namespace.QName} object constructed.
*
* @throws IllegalArgumentException if the prefix in {@code qname} is undeclared.
*/
public QName toQName(String qname){
String prefix = "";
String localName = qname;
int colon = qname.indexOf(':');
if(colon!=-1){
prefix = qname.substring(0, colon);
localName = qname.substring(colon+1);
}
String ns = getNamespaceURI(prefix);
if(ns==null)
throw new IllegalArgumentException("undeclared prefix: "+prefix);
return new QName(ns, localName, prefix);
}
}