All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.ode.utils.NamespaceStack Maven / Gradle / Ivy

There is a newer version: 1.3.8
Show newest version
/*
 * 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.ode.utils;

import java.util.EmptyStackException;
import java.util.HashMap;
import java.util.Iterator;

import javax.xml.namespace.QName;

import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;


/**
 * 

* This is a utility for a SAX ContentHandler implementation to use in * tracking namespace declarations during a parse. The assumption is that the * handler has access to the full stream of events relevant to managing the * declarations. The primary use case is the resolution of Strings, * e.g., from attribute values or element content, to QName objects. *

*/ public class NamespaceStack { private Frame _current; /** *

* Construct a new instance with the bare minimum bindings for the * xmlns, xml, and empty prefixes. Note that the empty * prefix is bound to the empty (non-null) URI. *

*/ public NamespaceStack() { _current = new Frame(); /* * As per the Namespaces in XML Errata: * http://www.w3.org/XML/xml-names-19990114-errata */ _current.declarePrefix("xmlns","http://www.w3.org/2000/xmlns/"); /* * As per the Namespaces in XML Rec: * http://www.w3.org/TR/1999/REC-xml-names-19990114 */ _current.declarePrefix("xml","http://www.w3.org/XML/1998/namespace"); /* * As per the Namespaces in XML Rec: * http://www.w3.org/TR/1999/REC-xml-names-19990114 */ _current.declarePrefix("",""); } /** *

* Convert the current stack of contexts into a single NSContext. *

* @return the NSContext instance */ public NSContext toNSContext() { NSContext n = new NSContext(); for (Frame f = _current;f != null; f=f._parent) { if (f._bindings == null) continue; for (Iterator it = f._bindings.keySet().iterator();it.hasNext();) { String pfx = (String) it.next(); if (n.getNamespaceURI(pfx) == null) { n.register(pfx, f._bindings.get(pfx)); } } } return n; } /** *

* Push a fresh context onto the stack. This method should be called somewhere in * the body of a startElement(), as it represents the namespace * resolution context for the events that occur between that event and the * corresponding endElement(). *

* @see org.xml.sax.ContentHandler */ public void pushNewContext() { _current = new Frame(_current); } /** *

* Pop a context from the stack. This method should be called somewhere in the * body of an endElement, as it clears the context that was used for * namespace resolution within the body of the corresponding element. *

* @see org.xml.sax.ContentHandler */ public void pop() { if (_current._parent == null) { throw new EmptyStackException(); } _current = _current._parent; } /** *

* Declare a new prefix binding. This binding will supercede a binding with the * same prefix in the same scope. As a crutch, null arguments may be * passed and will be interpreted as "". Note that binding * a non-empty prefix to an empty URI is not permitted in XML 1.0 but is not * flagged as an error by the method. *

* @param prefix the prefix to bind * @param uri the URI to bind it to */ public void declarePrefix(String prefix, String uri) { _current.declarePrefix(prefix==null?"":prefix, uri==null?"":uri); } /** *

* Retrieve the URI bound to the supplied prefix or null if no URI * is bound to the supplied prefix. As a crutch, a null argument * may be passed and will be interpreted as the empty prefix * (""). *

* @returns the URI or null if no URI is bound. */ public String getNamespaceUri(String prefix) { return _current.getNamespaceURI(prefix==null?"":prefix); } /** *

* Fire the events for the current frame's prefixes into a ContentHandler. *

* @param ch the target ContentHandler * @throws SAXException if the target method does. */ public void startPrefixMappings(ContentHandler ch) throws SAXException { _current.startPrefixMappings(ch); } /** *

* Fire the events for the current frame's prefixes into a ContentHandler. *

* @param ch the target ContentHandler. * @throws SAXException if the target method does. */ public void endPrefixMappings(ContentHandler ch) throws SAXException { _current.endPrefixMappings(ch); } /** *

* Allocate and declare a new namespace prefix for the current context that uses * the supplied "hint" as a start. The algorithm used will defer to an * existing binding, then try the hint, then use a variant of the hint until it * finds an available prefix. *

* @param hint a hint as to the desired prefix or null if any prefix * will do. * @param uri the URI to bind to the prefix. * @return the suggested prefix. */ public String allocatePrefix(String hint, String uri) { String pfx = getPrefix(uri); if (pfx == null) { hint = hint==null?"ns":hint; String u = getNamespaceUri(hint); if (u == null) { declarePrefix(hint,uri); pfx = hint; } else if (u.equals(uri)) { pfx = hint; } else { // ?? } } return pfx; } public String getPrefix(String uri) { return toNSContext().getPrefix(uri); } /** *

* Derference the prefix on a QName in String form and return a Java * QName object. *

* @param qname the QName in string form. * @return the dereferenced QName. * @throws IllegalArgumentException if a null argument is passed, * a malformed argument (e.g., :foo or foo:) is passed, * or if the prefix cannot be resolved to a URI. */ public QName dereferenceQName(String qname) { if (qname == null) { throw new IllegalArgumentException("Unable to dereference as a QName."); } int pos = qname.indexOf(':'); QName qn; if (pos == qname.length() - 1 || pos == 0) { throw new IllegalArgumentException("\"" + qname + "\" is a malformed QName."); } else if (pos == -1) { qn = new QName (getNamespaceUri(""),qname); } else { String uri = getNamespaceUri(qname.substring(0,pos)); if (uri == null) { throw new IllegalArgumentException("No URI is bound to " + qname.substring(0,pos) + "."); } qn = new QName(uri,qname.substring(pos+1)); } return qn; } private class Frame { Frame _parent; HashMap _bindings; Frame() { // This space intentionally left blank. } Frame(Frame parent) { _parent = parent; } void startPrefixMappings(ContentHandler ch) throws SAXException { if (_bindings != null) { for(Iterator it = _bindings.keySet().iterator();it.hasNext();) { String prefix = (String) it.next(); ch.startPrefixMapping(prefix, _bindings.get(prefix)); } } } void endPrefixMappings(ContentHandler ch) throws SAXException { if (_bindings != null) { for (Iterator it = _bindings.keySet().iterator();it.hasNext();) { ch.endPrefixMapping((String) it.next()); } } } void declarePrefix(String prefix, String uri) { if (_bindings == null) { _bindings = new HashMap(); } _bindings.put(prefix,uri); } String getPrefix(String uri) { return ""; } String getNamespaceURI(String prefix) { String uri = null; if (_bindings != null) { uri = _bindings.get(prefix); } if (uri == null) { uri= _parent==null ? null:(_parent.getNamespaceURI(prefix)); } return uri; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy