snichol 2002/11/18 06:23:06 Modified: java/src/org/apache/soap/util/xml NSStack.java Log: Submitted by: Pavel Ausianik <[EMAIL PROTECTED]> I have prepared patch for NSStack, moving from growing number of Vectors to 3 arrays per stack. I also used intern() String comparison, but this only do benefits for large number of comparisons, and it may happen that having just String.equals() could be better. Revision Changes Path 1.5 +200 -135 xml-soap/java/src/org/apache/soap/util/xml/NSStack.java Index: NSStack.java =================================================================== RCS file: /home/cvs/xml-soap/java/src/org/apache/soap/util/xml/NSStack.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- NSStack.java 10 Nov 2000 15:20:58 -0000 1.4 +++ NSStack.java 18 Nov 2002 14:23:06 -0000 1.5 @@ -2,7 +2,7 @@ * The Apache Software License, Version 1.1 * * - * Copyright (c) 2000 The Apache Software Foundation. All rights + * Copyright (c) 2000 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -10,7 +10,7 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in @@ -18,7 +18,7 @@ * distribution. * * 3. The end-user documentation included with the redistribution, - * if any, must include the following acknowledgment: + * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, @@ -26,7 +26,7 @@ * * 4. The names "SOAP" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this - * software without prior written permission. For written + * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", @@ -57,9 +57,10 @@ package org.apache.soap.util.xml; -import java.io.*; -import java.util.*; -import org.apache.soap.util.xml.* ; +import java.io.IOException; +import java.io.Writer; + +import org.apache.soap.util.xml.*; /** * This class implements a namespace stack for XML apps to use. If @@ -79,134 +80,198 @@ * declaration. * * @author Sanjiva Weerawarana ([EMAIL PROTECTED]) + * @author Pavel Ausianik <[EMAIL PROTECTED]> */ -public class NSStack { - Vector nss = new Vector (); // vector holding vectors of ns decls (stack) - int nssCount = 0; // number of items on the stack - Vector tos; // the vector @ the top of the stack - private final static String nsPrefixPrefix = "ns"; - private int nsPrefixCount = 1; - - /** - * Enter a new scope: after calling this I'm ready to accept new - * declarations into that scope. - */ - public void pushScope () { - nss.addElement (tos = new Vector ()); - nssCount++; - } - - /** - * Leave a scope: this removes any NS declarations that were added - * in the last scope. Note that I don't bother to validate that you - * don't call popScope too many times; that's your problem. - */ - public void popScope () { - nss.removeElementAt (--nssCount); - tos = (nssCount != 0) ? (Vector) nss.elementAt (nssCount-1) : null; - } - - /** - * Add a new declaration to the current scope. This is visible within - * the current scope as well as from any nested scopes. - * - * @param prefix the prefix to be used for this namespace - * @param URI the namespace name of this namespace. - */ - synchronized public void addNSDeclaration (String prefix, String URI) { - tos.addElement (new NSDecl (prefix, URI)); - } - - /** - * Add a new declaration to the current scope using a unique prefix - * and return the prefix. This is useful when one just wants to add a - * decl and doesn't want to have to deal with creating unique prefixes. - * If the namespace name is already declared and in scope, then the - * previously declared prefix is returned. - * - * @param URI the namespace name of this namespace - * @return the unique prefix created or previously declared - * for this namespace - */ - synchronized public String addNSDeclaration (String URI) { - String uniquePrefix = getPrefixFromURI (URI); - if (uniquePrefix == null) { - do { - uniquePrefix = nsPrefixPrefix + nsPrefixCount++; - } while (getURIFromPrefix (uniquePrefix) != null); - addNSDeclaration (uniquePrefix, URI); - } - return uniquePrefix; - } - - /** - * Return the prefix associated with the given namespace name by - * looking thru all the namespace declarations that are in scope. - * - * @param URI the namespace name for whom a declared prefix is desired - * @return the prefix or null if namespace name not found - */ - public String getPrefixFromURI (String URI) { - for (int i = nssCount-1; i >= 0; i--) { - Vector scope = (Vector) nss.elementAt (i); - for (Enumeration e = scope.elements (); e.hasMoreElements (); ) { - NSDecl nsd = (NSDecl) e.nextElement (); - if (nsd.URI.equals (URI)) { - return nsd.prefix; - } - } - } - return null; - } - - /** - * Return the prefix associated with the given namespace name by - * looking thru all the namespace declarations that are in scope. - * If the namespace declaration is not found, create one and - * return the generated prefix. - * - * @param URI the namespace name for whom a declared prefix is desired - * @return the prefix (will never return null) - */ - synchronized public String getPrefixFromURI (String namespaceURI, - Writer sink) - throws IOException { - String prefix = getPrefixFromURI (namespaceURI); - - if (prefix == null) { - prefix = addNSDeclaration (namespaceURI); - - sink.write (" xmlns:" + prefix + "=\"" + namespaceURI + '\"'); - } - - return prefix; - } - - /** - * Return the namespace name associated with the given prefix by - * looking thru all the namespace declarations that are in scope. - * - * @param prefix the prefix for whom a declared namespace name is desired - * @return the namespace name or null if prefix not found - */ - public String getURIFromPrefix (String prefix) { - for (int i = nssCount-1; i >= 0; i--) { - Vector scope = (Vector) nss.elementAt (i); - for (Enumeration e = scope.elements (); e.hasMoreElements (); ) { - NSDecl nsd = (NSDecl) e.nextElement (); - if (nsd.prefix.equals (prefix)) { - return nsd.URI; - } - } - } - return null; - } - - // MJD - debug - public String toString() - { - return nss.toString(); - } - // MJD - debug +public final class NSStack { + private String[] URIStack; + private String[] prefixStack; + + private int[] scope; + private int top = 0; + private int iterator = -1; + private final static String NSPREFIX = "ns"; + private int nsPrefixCount = 0; + + private static String[] predefinedNamespaces; + + private static final int START_ARRAY_SIZE = 32; + + public NSStack() { + URIStack = new String[START_ARRAY_SIZE]; + prefixStack = new String[START_ARRAY_SIZE]; + scope = new int[START_ARRAY_SIZE]; + scope[0] = -1; + } + + /** + * Creates a predefined Namespace string + * Assuming that in the single application , the number of names is the same + * between calls. We'll benefit from caching on continuous operations + */ + synchronized private static String getPredefinedNamespace(int nsCount) { + if (predefinedNamespaces == null) + { + predefinedNamespaces = new String[START_ARRAY_SIZE]; + for (int i=0; i<START_ARRAY_SIZE; i++) + predefinedNamespaces[i] = NSPREFIX + (i+1); + } else if (nsCount >= predefinedNamespaces.length) { + int length = predefinedNamespaces.length; + String[] newnamespace = new String[length * 2]; + System.arraycopy(predefinedNamespaces, 0, newnamespace, 0, length); + for (int i=0; i<length; i++) + predefinedNamespaces[i+length] = NSPREFIX + (i+length+1); + } + return predefinedNamespaces[nsCount]; + } + + /** + * Enter a new scope: after calling this I'm ready to accept new + * declarations into that scope. + */ + public void pushScope() { + + top++; + int length = scope.length; + + if (top >= length) { + int newscope[] = new int[length * 2]; + System.arraycopy(scope, 0, newscope, 0, length); + scope = newscope; + } + + scope[top] = iterator; + + } + + /** + * Leave a scope: this removes any NS declarations that were added + * in the last scope. Note that I don't bother to validate that you + * don't call popScope too many times; that's your problem. + */ + public void popScope() { + scope[top] = 0; + top--; + iterator = top >= 0 ? scope[top] : 0; + } + + /** + * Add a new declaration to the current scope. This is visible within + * the current scope as well as from any nested scopes. + * + * @param prefix the prefix to be used for this namespace + * @param URI the namespace name of this namespace. + */ + public void addNSDeclaration(String prefix, String namespaceURI) { + int length = URIStack.length; + iterator++; + + if (iterator >= length) { + String newstack[] = new String[length * 2]; + System.arraycopy(URIStack, 0, newstack, 0, length); + URIStack = newstack; + newstack = new String[length * 2]; + System.arraycopy(prefixStack, 0, newstack, 0, length); + prefixStack = newstack; + } + // scope too small - expand - very unlikely + URIStack[iterator] = namespaceURI.intern(); + prefixStack[iterator] = prefix.intern(); + } + + /** + * Add a new declaration to the current scope using a unique prefix + * and return the prefix. This is useful when one just wants to add a + * decl and doesn't want to have to deal with creating unique prefixes. + * If the namespace name is already declared and in scope, then the + * previously declared prefix is returned. + * + * @param URI the namespace name of this namespace + * @return the unique prefix created or previously declared + * for this namespace + */ + public String addNSDeclaration(String URI) { + String uniquePrefix = getPrefixFromURI(URI); + if (uniquePrefix == null) { + do { + uniquePrefix = getPredefinedNamespace(nsPrefixCount++); + } while (getURIFromPrefix(uniquePrefix) != null); + addNSDeclaration(uniquePrefix, URI); + } + return uniquePrefix; + } + + /** + * Return the prefix associated with the given namespace name by + * looking thru all the namespace declarations that are in scope. + * + * @param URI the namespace name for whom a declared prefix is desired + * @return the prefix or null if namespace name not found + */ + public String getPrefixFromURI(String namespaceURI) { + if ((namespaceURI == null) || (namespaceURI.equals(""))) + return null; + + namespaceURI = namespaceURI.intern(); + for (int cursor = iterator; cursor >= 0; cursor--) { + if (URIStack[cursor] == namespaceURI) + return prefixStack[cursor]; + } + return null; + } + + /** + * Return the prefix associated with the given namespace name by + * looking thru all the namespace declarations that are in scope. + * If the namespace declaration is not found, create one and + * return the generated prefix. + * + * @param URI the namespace name for whom a declared prefix is desired + * @return the prefix (will never return null) + */ + public String getPrefixFromURI(String namespaceURI, Writer sink) + throws IOException { + String prefix = getPrefixFromURI(namespaceURI); + + if (prefix == null) { + prefix = addNSDeclaration(namespaceURI); + + sink.write(" xmlns:"); + sink.write(prefix); + sink.write("=\""); + sink.write(namespaceURI); + sink.write('\"'); + } + + return prefix; + } + + /** + * Given a prefix, return the associated namespace (if any). + */ + public String getURIFromPrefix(String prefix) { + if (prefix == null) + prefix = ""; + prefix = prefix.intern(); + for (int cursor = iterator; cursor >= 0; cursor--) { + if (prefixStack[cursor] == prefix) + return URIStack[cursor]; + } + + return null; + } + + public void dump() { + int end = iterator; + int start = 0; + for (int cursor = top; cursor >= 0; cursor--, end = start - 1) { + start = scope[cursor] + 1; + + System.out.println("Level: " + cursor); + + for (int j = start; j <= end; j++) { + System.out.println(" Map:" + URIStack[cursor] + " -> " +prefixStack[cursor]); + } + } + } }
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>