FileDocCategorySizeDatePackage
NSStack.javaAPI DocApache Axis 1.49602Sat Apr 22 18:57:28 BST 2006org.apache.axis.utils

NSStack

public class NSStack extends Object
The abstraction this class provides is a push down stack of variable length frames of prefix to namespace mappings. Used for keeping track of what namespaces are active at any given point as an XML document is traversed or produced. From a performance point of view, this data will both be modified frequently (at a minimum, there will be one push and pop per XML element processed), and scanned frequently (many of the "good" mappings will be at the bottom of the stack). The one saving grace is that the expected maximum cardinalities of the number of frames and the number of total mappings is only in the dozens, representing the nesting depth of an XML document and the number of active namespaces at any point in the processing. Accordingly, this stack is implemented as a single array, will null values used to indicate frame boundaries.
author
James Snell
author
Glen Daniels (gdaniels@apache.org)
author
Sam Ruby (rubys@us.ibm.com)

Fields Summary
protected static Log
log
private Mapping[]
stack
private int
top
private int
iterator
private int
currentDefaultNS
private boolean
optimizePrefixes
private final boolean
traceEnabled
Constructors Summary
public NSStack(boolean optimizePrefixes)


       
        this.optimizePrefixes = optimizePrefixes;
        stack = new Mapping[32];
        stack[0] = null;
    
public NSStack()

        stack = new Mapping[32];
        stack[0] = null;
    
Methods Summary
public voidadd(java.lang.String namespaceURI, java.lang.String prefix)
Add a mapping for a namespaceURI to the specified prefix to the top frame in the stack. If the prefix is already mapped in that frame, remap it to the (possibly different) namespaceURI.

        int idx = top;
        prefix = prefix.intern();
        try {
            // Replace duplicate prefixes (last wins - this could also fault)
            for (int cursor=top; stack[cursor]!=null; cursor--) {
                if (stack[cursor].getPrefix() == prefix) {
                    stack[cursor].setNamespaceURI(namespaceURI);
                    idx = cursor;
                    return;
                }
            }
            
            push();
            stack[top] = new Mapping(namespaceURI, prefix);
            idx = top;
        } finally {
            // If this is the default namespace, note the new in-scope
            // default is here.
            if (prefix.length() == 0) {
                currentDefaultNS = idx;
            }
        }
    
private voidclearFrame()
Remove all mappings from the current frame.

        while (stack[top] != null) top--;
    
public java.util.ArrayListcloneFrame()
Return a copy of the current frame. Returns null if none are present.

        if (stack[top] == null) return null;

        ArrayList clone = new ArrayList();

        for (Mapping map=topOfFrame(); map!=null; map=next()) {
            clone.add(map);
        }

        return clone;
    
public voiddump(java.lang.String dumpPrefix)
Produce a trace dump of the entire stack, starting from the top and including frame markers.

        for (int cursor=top; cursor>0; cursor--) {
            Mapping map = stack[cursor];

            if (map == null) {
                log.trace(dumpPrefix + Messages.getMessage("stackFrame00"));
            } else {
                log.trace(dumpPrefix + map.getNamespaceURI() + " -> " + map.getPrefix());
            }
        }
    
public java.lang.StringgetNamespaceURI(java.lang.String prefix)
Given a prefix, return the associated namespace (if any).

        if (prefix == null)
            prefix = "";

        prefix = prefix.intern();

        for (int cursor=top; cursor>0; cursor--) {
            Mapping map = stack[cursor];
            if (map == null) continue;
        
            if (map.getPrefix() == prefix)
                return map.getNamespaceURI();
        }
        
        return null;
    
public java.lang.StringgetPrefix(java.lang.String namespaceURI, boolean noDefault)
Return an active prefix for the given namespaceURI. NOTE : This may return null even if the namespaceURI was actually mapped further up the stack IF the prefix which was used has been repeated further down the stack. I.e.: *here's where we're looking* If we look for a prefix for "namespace" at the indicated spot, we won't find one because "pre" is actually mapped to "otherNamespace"

        if ((namespaceURI == null) || (namespaceURI.length()==0))
            return null;
        
        if(optimizePrefixes) {
            // If defaults are OK, and the given NS is the current default,
            // return "" as the prefix to favor defaults where possible.
            if (!noDefault && currentDefaultNS > 0 && stack[currentDefaultNS] != null &&
                    namespaceURI == stack[currentDefaultNS].getNamespaceURI())
                return "";
        }
        namespaceURI = namespaceURI.intern();

        for (int cursor=top; cursor>0; cursor--) {
            Mapping map = stack[cursor];
            if (map == null) 
                continue;

            if (map.getNamespaceURI() == namespaceURI) {
                String possiblePrefix = map.getPrefix();
                if (noDefault && possiblePrefix.length() == 0)
                    continue;
    
                // now make sure that this is the first occurance of this 
                // particular prefix
                for (int cursor2 = top; true; cursor2--) {
                    if (cursor2 == cursor)
                        return possiblePrefix;
                    map = stack[cursor2];
                    if (map == null)
                        continue;
                    if (possiblePrefix == map.getPrefix())
                        break;
                }
            }
        }
        
        return null;
    
public java.lang.StringgetPrefix(java.lang.String namespaceURI)
Return an active prefix for the given namespaceURI, including the default prefix ("").

        return getPrefix(namespaceURI, false);
    
public Mappingnext()
Return the next namespace mapping in the top frame.

        if (iterator > top) {
            return null;
        } else {
            return stack[iterator++];
        }
    
public voidpop()
Remove the top frame from the stack.

        clearFrame();

        top--;

        // If we've moved below the current default NS, figure out the new
        // default (if any)
        if (top < currentDefaultNS) {
            // Reset the currentDefaultNS to ignore the frame just removed.
            currentDefaultNS = top;
            while (currentDefaultNS > 0) {
                if (stack[currentDefaultNS] != null &&
                        stack[currentDefaultNS].getPrefix().length() == 0)
                    break;
                currentDefaultNS--;
            }
        }
        
        if (top == 0) {
            if (traceEnabled)
                log.trace("NSPop (" + Messages.getMessage("empty00") + ")");

            return;
        }
        
        if (traceEnabled){
            log.trace("NSPop (" + stack.length + ")");
        }
    
public voidpush()
Create a new frame at the top of the stack.

        top ++;

        if (top >= stack.length) {
           Mapping newstack[] = new Mapping[stack.length*2];
           System.arraycopy (stack, 0, newstack, 0, stack.length);
           stack = newstack;
        }

        if (traceEnabled)
            log.trace("NSPush (" + stack.length + ")");

        stack[top] = null;
    
public MappingtopOfFrame()
Reset the embedded iterator in this class to the top of the current (i.e., last) frame. Note that this is not threadsafe, nor does it provide multiple iterators, so don't use this recursively. Nor should you modify the stack while iterating over it.

        iterator = top;
        while (stack[iterator] != null) iterator--;
        iterator++;
        return next();