This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to annotated tag jaxp-ri-1_2_0-fcs-02 in repository https://gitbox.apache.org/repos/asf/xalan-java.git
commit a78a29a4c1058914cc57ef8ba6f8cd0759b4c433 Author: No Author <[email protected]> AuthorDate: Tue Apr 9 18:55:56 2002 +0000 This commit was manufactured by cvs2svn to create tag 'jaxp-ri-1_2_0-fcs-02'. --- build.xml | 7 +- .../xalan/xsltc/compiler/ApplyTemplates.java | 5 +- src/org/apache/xalan/xsltc/compiler/Constants.java | 4 + .../apache/xalan/xsltc/compiler/Expression.java | 2 +- .../xalan/xsltc/compiler/FormatNumberCall.java | 2 +- .../xsltc/compiler/FunctionAvailableCall.java | 174 +++++++++++- .../apache/xalan/xsltc/compiler/FunctionCall.java | 77 ++++-- .../xalan/xsltc/compiler/LiteralElement.java | 87 ++++-- .../xalan/xsltc/compiler/ParentLocationPath.java | 2 + src/org/apache/xalan/xsltc/compiler/Parser.java | 10 +- .../xsltc/compiler/ProcessingInstruction.java | 6 +- src/org/apache/xalan/xsltc/compiler/Step.java | 16 -- .../apache/xalan/xsltc/compiler/StepPattern.java | 6 +- .../apache/xalan/xsltc/compiler/Stylesheet.java | 30 +- .../apache/xalan/xsltc/compiler/SymbolTable.java | 9 +- .../xalan/xsltc/compiler/SyntaxTreeNode.java | 14 +- .../apache/xalan/xsltc/compiler/XslAttribute.java | 73 +++-- .../apache/xalan/xsltc/compiler/XslElement.java | 4 + src/org/apache/xalan/xsltc/compiler/util/Util.java | 27 +- .../xalan/xsltc/dom/CurrentNodeListIterator.java | 17 +- src/org/apache/xalan/xsltc/dom/DOMBuilder.java | 2 +- src/org/apache/xalan/xsltc/dom/DOMImpl.java | 135 ++++++--- .../dom/{DOMBuilder.java => ExtendedSAX.java} | 4 +- .../apache/xalan/xsltc/dom/SortingIterator.java | 28 +- src/org/apache/xalan/xsltc/dom/UnionIterator.java | 4 +- .../xalan/xsltc/runtime/AbstractTranslet.java | 84 +++--- .../apache/xalan/xsltc/runtime/BasisLibrary.java | 2 +- src/org/apache/xalan/xsltc/runtime/Constants.java | 5 + .../xsltc/runtime/DefaultSAXOutputHandler.java | 45 +-- src/org/apache/xalan/xsltc/runtime/SAXAdapter.java | 42 ++- .../xalan/xsltc/runtime/StringValueHandler.java | 25 ++ src/org/apache/xalan/xsltc/runtime/TextOutput.java | 283 ++++++++++++------- .../apache/xalan/xsltc/runtime/TransletLoader.java | 19 +- src/org/apache/xalan/xsltc/trax/DOM2SAX.java | 302 +++++++++++++++++---- src/org/apache/xalan/xsltc/trax/SAX2DOM.java | 213 +++++++-------- .../xalan/xsltc/trax/TemplatesHandlerImpl.java | 7 +- src/org/apache/xalan/xsltc/trax/TemplatesImpl.java | 10 +- .../xalan/xsltc/trax/TransformerFactoryImpl.java | 4 +- .../apache/xalan/xsltc/trax/TransformerImpl.java | 28 +- src/trax/trax.properties | 11 - 40 files changed, 1215 insertions(+), 610 deletions(-) diff --git a/build.xml b/build.xml index 0e09c0f..5316f9c 100644 --- a/build.xml +++ b/build.xml @@ -361,7 +361,7 @@ Copyright: </javac> </target> - <target name="xsltc.jar" depends="xsltc.compile" + <target name="xsltc.unbundledjar" depends="xsltc.compile" description="Jar just the xsltc.jar file" > <!-- Copy over the manifest, with filtering (for version number) --> <filter token="impl.version" value="${impl.version}"/> @@ -374,7 +374,7 @@ Copyright: </target> - <target name="xsltc.bundledjar" depends="xsltc.compile" + <target name="xsltc.jar" depends="xsltc.compile" description="Jar xsltc, BCEL,JLex,java_cup,runtime and jakarta regexp"> <!-- make a tmp directory to work in --> <delete dir="${build.dir}/xsltctmp" includeEmptyDirs="true" quiet="true"/> @@ -449,11 +449,14 @@ Copyright: includeEmptyDirs="true" quiet="true"/> <!-- create new META-INF dir w/ transformer factory default --> + <!-- GTM: comment this out so that bundled xsltc.jar does not have + service provider default until further notice 2/20/2002 <mkdir dir="${build.dir}/xsltctmp/META-INF"/> <mkdir dir="${build.dir}/xsltctmp/META-INF/services"/> <copy todir="${build.dir}/xsltctmp/META-INF/services" file="${src.dir}/${xsltc.reldir}/javax.xml.transform.TransformerFactory" /> + --> <!-- Copy over the manifest, with filtering (for version number) --> <filter token="impl.version" value="${impl.version}"/> diff --git a/src/org/apache/xalan/xsltc/compiler/ApplyTemplates.java b/src/org/apache/xalan/xsltc/compiler/ApplyTemplates.java index b0143cb..985f683 100644 --- a/src/org/apache/xalan/xsltc/compiler/ApplyTemplates.java +++ b/src/org/apache/xalan/xsltc/compiler/ApplyTemplates.java @@ -139,6 +139,7 @@ final class ApplyTemplates extends Instruction { * some template in the stylesheet uses parameters. */ public void translate(ClassGenerator classGen, MethodGenerator methodGen) { + boolean setStartNodeCalled = false; final Stylesheet stylesheet = classGen.getStylesheet(); final ConstantPoolGen cpg = classGen.getConstantPool(); final InstructionList il = methodGen.getInstructionList(); @@ -165,6 +166,7 @@ final class ApplyTemplates extends Instruction { translateContents(classGen, methodGen); } + il.append(classGen.loadTranslet()); // The 'select' expression is a result-tree @@ -192,6 +194,7 @@ final class ApplyTemplates extends Instruction { NODE_ITERATOR_SIG); il.append(methodGen.loadCurrentNode()); il.append(new INVOKEINTERFACE(setStartNode,2)); + setStartNodeCalled = true; } else { if (_select == null) @@ -201,7 +204,7 @@ final class ApplyTemplates extends Instruction { } } - if (_select != null) { + if (_select != null && !setStartNodeCalled) { _select.startResetIterator(classGen, methodGen); } diff --git a/src/org/apache/xalan/xsltc/compiler/Constants.java b/src/org/apache/xalan/xsltc/compiler/Constants.java index 6772185..4e6acc7 100644 --- a/src/org/apache/xalan/xsltc/compiler/Constants.java +++ b/src/org/apache/xalan/xsltc/compiler/Constants.java @@ -486,6 +486,10 @@ public interface Constants extends InstructionConstants { public static final int POSITION_INDEX = 2; public static final int LAST_INDEX = 3; + public static final String XMLNS_PREFIX = "xmlns"; + public static final String XMLNS_STRING = "xmlns:"; + public static final String XMLNS_URI + = "http://www.w3.org/2000/xmlns/"; public static final String XSLT_URI = "http://www.w3.org/1999/XSL/Transform"; public static final String XHTML_URI diff --git a/src/org/apache/xalan/xsltc/compiler/Expression.java b/src/org/apache/xalan/xsltc/compiler/Expression.java index 3da80c6..727dc3b 100644 --- a/src/org/apache/xalan/xsltc/compiler/Expression.java +++ b/src/org/apache/xalan/xsltc/compiler/Expression.java @@ -103,7 +103,7 @@ abstract class Expression extends SyntaxTreeNode { public abstract String toString(); public boolean hasPositionCall() { - return true; + return false; // default should be 'false' for StepPattern } public boolean hasLastCall() { diff --git a/src/org/apache/xalan/xsltc/compiler/FormatNumberCall.java b/src/org/apache/xalan/xsltc/compiler/FormatNumberCall.java index 9558f1a..124576d 100644 --- a/src/org/apache/xalan/xsltc/compiler/FormatNumberCall.java +++ b/src/org/apache/xalan/xsltc/compiler/FormatNumberCall.java @@ -97,7 +97,7 @@ final class FormatNumberCall extends FunctionCall { _format = new CastExpr(_format, Type.String); } if (argumentCount() == 3) { - final Type tname = _format.typeCheck(stable); + final Type tname = _name.typeCheck(stable); if (tname instanceof StringType == false) { _name = new CastExpr(_name, Type.String); } diff --git a/src/org/apache/xalan/xsltc/compiler/FunctionAvailableCall.java b/src/org/apache/xalan/xsltc/compiler/FunctionAvailableCall.java index 1e6aafc..af45184 100644 --- a/src/org/apache/xalan/xsltc/compiler/FunctionAvailableCall.java +++ b/src/org/apache/xalan/xsltc/compiler/FunctionAvailableCall.java @@ -56,7 +56,7 @@ * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * - * @author Jacek Ambroziak + * @author G. Todd Miller * @author Santiago Pericas-Geertsen * */ @@ -64,38 +64,188 @@ package org.apache.xalan.xsltc.compiler; import java.util.Vector; -import java.util.HashSet; +import java.lang.reflect.Modifier; +import java.lang.reflect.Method; import org.apache.xalan.xsltc.compiler.util.Type; import org.apache.bcel.generic.*; import org.apache.xalan.xsltc.compiler.util.*; +import org.apache.xalan.xsltc.runtime.TransletLoader; final class FunctionAvailableCall extends FunctionCall { + private boolean _isFunctionAvailable = false; + private Expression _arg; + private String _namespaceOfFunct =null; + private String _nameOfFunct =null; + + + /** + * Constructs a FunctionAvailableCall FunctionCall. Takes the + * function name qname, for example, 'function-available', and a list + * of arguments where the arguments must be instances of + * LiteralExpression. The test for availability considers + * internal xsl functions such as 'floor' as well as external + * Java functions, such as 'java.lang.Math.sin'. The case of + * external functions is handled here, the case of internal + * functions is handled in getResult. + */ public FunctionAvailableCall(QName fname, Vector arguments) { super(fname, arguments); + _arg = (Expression)arguments.elementAt(0); + _type = null; + if (_arg instanceof LiteralExpr) { + LiteralExpr arg = (LiteralExpr)_arg; + _namespaceOfFunct = arg.getNamespace(); + _nameOfFunct = arg.getValue(); + if ((_namespaceOfFunct != null) && + (!_namespaceOfFunct.equals(Constants.EMPTYSTRING))) + { + // the function is external, such as a java function + _isFunctionAvailable = hasMethods(); + } + // the case of internal function is handled in getResult. + } + // case where _arg is not instanceof LiteralExpr can not be handled. } /** - * Force the argument to this function to be a literal string. + * Argument of function-available call must be literal, typecheck + * returns the type of function-available to be boolean. */ public Type typeCheck(SymbolTable stable) throws TypeCheckError { - if (argument() instanceof LiteralExpr) { - return _type = Type.Boolean; + // may be already set + if ( _type != null ) { + return _type; + } + if (_arg instanceof LiteralExpr) { + _type = Type.Boolean; + return Type.Boolean; } ErrorMsg err = new ErrorMsg(ErrorMsg.NEED_LITERAL_ERR, - "function-available", this); + "function-available", this); throw new TypeCheckError(err); } /** - * Returns the result that this function will return + * (For ext. java functions only) + * Parses the argument to function-available to extract the package + * qualified class name, for example, given the argument + * 'java:java.lang.Math.sin', getClassName would return + * 'java.lang.Math'. See also 'getMethodName'. + */ + private String getClassName(String argValue){ + int colonSep = argValue.indexOf(":"); + if (colonSep != -1) { + argValue = argValue.substring(colonSep+1); + } + int lastDot = argValue.lastIndexOf("."); + if (lastDot != -1) { + argValue = argValue.substring(0, lastDot); + } + return argValue; + } + + /** + * (For ext. java functions only) + * Parses the argument to function-available + * to extract the method name, for example, given the argument + * 'java.lang.Math.sin', getMethodName would return 'sin'. + */ + private String getMethodName(String argValue){ + int lastDot = argValue.lastIndexOf("."); + if (lastDot != -1) { + argValue = argValue.substring(lastDot+1); + } + return argValue; + } + + /** + * (For java external functions only) + * Creates a full package qualified + * function name taking into account the namespace and the + * function name derived from the argument passed to function-available. + * For example, given a name of 'java:java.lang.Math.sin' and a + * namespace of 'http://xml.apache.org/xalan/xsltc/java' this routine + * constructs a uri and then derives the class name + * 'java.lang.Math.sin' from the uri. The uri in this example would + * be 'http://xml.apache.org/xalan/xsltc/java.java.lang.Math.sin' + */ + private String getExternalFunctionName() { + int colonIndex = _nameOfFunct.indexOf(":"); + String uri = _namespaceOfFunct + + "." + _nameOfFunct.substring(colonIndex+1); + try{ + return getClassNameFromUri(uri); + } catch (TypeCheckError e) { + return null; + } + } + + /** + * for external java functions only: reports on whether or not + * the specified method is found in the specifed class. + */ + private boolean hasMethods() { + + LiteralExpr arg = (LiteralExpr)_arg; + final String externalFunctName = getExternalFunctionName(); + if (externalFunctName == null) { + return false; + } + final String className = getClassName(externalFunctName); + + if (_namespaceOfFunct.startsWith(JAVA_EXT_PREFIX) || + _namespaceOfFunct.startsWith(JAVA_EXT_XALAN)) { + try { + TransletLoader loader = new TransletLoader(); + final Class clazz = loader.loadClass(className); + + if (clazz == null) { + final ErrorMsg msg = + new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, className); + getParser().reportError(Constants.ERROR, msg); + } + else { + final String methodName = getMethodName(externalFunctName); + final Method[] methods = clazz.getDeclaredMethods(); + + for (int i = 0; i < methods.length; i++) { + final int mods = methods[i].getModifiers(); + + if (Modifier.isPublic(mods) + && Modifier.isStatic(mods) + && methods[i].getName().equals(methodName)) + { + return true; + } + } + } + } + catch (ClassNotFoundException e) { + final ErrorMsg msg = + new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, className); + getParser().reportError(Constants.ERROR, msg); + } + } + return false; + } + + /** + * reports on whether the function specified in the argument to + * xslt function 'function-available' was found. */ public boolean getResult() { - final Parser parser = getParser(); - final LiteralExpr arg = (LiteralExpr)argument(); - return(parser.functionSupported(arg.getValue())); + if ((_namespaceOfFunct == null) || + (_namespaceOfFunct.equals(Constants.EMPTYSTRING))) + { + // no namespace, so the function is an internal xslt function. + final Parser parser = getParser(); + _isFunctionAvailable = parser.functionSupported(_nameOfFunct); + } + return _isFunctionAvailable; } + /** * Calls to 'function-available' are resolved at compile time since * the namespaces declared in the stylsheet are not available at run @@ -103,7 +253,7 @@ final class FunctionAvailableCall extends FunctionCall { */ public void translate(ClassGenerator classGen, MethodGenerator methodGen) { final ConstantPoolGen cpg = classGen.getConstantPool(); - final boolean result = getResult(); - methodGen.getInstructionList().append(new PUSH(cpg, result)); + methodGen.getInstructionList().append(new PUSH(cpg, getResult())); } + } diff --git a/src/org/apache/xalan/xsltc/compiler/FunctionCall.java b/src/org/apache/xalan/xsltc/compiler/FunctionCall.java index 4bf5be5..e3dfc05 100644 --- a/src/org/apache/xalan/xsltc/compiler/FunctionCall.java +++ b/src/org/apache/xalan/xsltc/compiler/FunctionCall.java @@ -86,8 +86,8 @@ class FunctionCall extends Expression { private final static Vector EMPTY_ARG_LIST = new Vector(0); // Valid namespaces for Java function-call extension - private final static String JAVA_EXT_PREFIX = TRANSLET_URI + "/java"; - private final static String JAVA_EXT_XALAN = + protected final static String JAVA_EXT_PREFIX = TRANSLET_URI + "/java"; + protected final static String JAVA_EXT_XALAN = "http://xml.apache.org/xslt/java"; // External Java function's class/method/signature @@ -170,6 +170,7 @@ class FunctionCall extends Expression { public FunctionCall(QName fname, Vector arguments) { _fname = fname; _arguments = arguments; + _type = null; } public FunctionCall(QName fname) { @@ -192,11 +193,27 @@ class FunctionCall extends Expression { } } + public String getClassNameFromUri(String uri) + throws TypeCheckError + { + final int length = + uri.startsWith(JAVA_EXT_PREFIX) ? JAVA_EXT_PREFIX.length() + 1 : + uri.startsWith(JAVA_EXT_XALAN) ? JAVA_EXT_XALAN.length() + 1 : 0; + + if (length == 0) { + throw new TypeCheckError(this); + } + return (uri.length() > length) ? uri.substring(length) : EMPTYSTRING; + } + /** * Type check a function call. Since different type conversions apply, * type checking is different for standard and external (Java) functions. */ - public Type typeCheck(SymbolTable stable) throws TypeCheckError { + public Type typeCheck(SymbolTable stable) + throws TypeCheckError + { + if (_type != null) return _type; final String namespace = _fname.getNamespace(); final String local = _fname.getLocalPart(); @@ -207,33 +224,37 @@ class FunctionCall extends Expression { } // Handle extension functions (they all have a namespace) else { - final int len = JAVA_EXT_PREFIX.length(); - if (namespace.equals(JAVA_EXT_PREFIX) || - namespace.equals(JAVA_EXT_XALAN)) { - final int pos = local.indexOf('.'); - _className = local.substring(0, pos); - _fname = new QName(namespace, null, local.substring(pos+1)); - } - else if (namespace.length() >= len && - namespace.substring(0, len).equals(JAVA_EXT_PREFIX)) { - _className = namespace.substring(len + 1); - } - else { - /* - * Warn user if external function could not be resolved. - * Warning will _NOT_ be issued is the call is properly - * wrapped in an <xsl:if> or <xsl:when> element. For details - * see If.parserContents() and When.parserContents() - */ - final Parser parser = getParser(); - if (parser != null) { - reportWarning(this, parser, ErrorMsg.FUNCTION_RESOLVE_ERR, - _fname.toString()); + try { + _className = getClassNameFromUri(namespace); + + final int pos = local.lastIndexOf('.'); + if (pos > 0) { + _className = _className + local.substring(0, pos); + _fname = new QName(namespace, null, local.substring(pos + 1)); + } + else { + _fname = new QName(namespace, null, local); } - unresolvedExternal = true; - return _type = Type.Void; + if (_className.length() > 0) { + return typeCheckExternal(stable); + } + } catch (TypeCheckError e) { + // Falls through + } + + /* + * Warn user if external function could not be resolved. + * Warning will _NOT_ be issued is the call is properly + * wrapped in an <xsl:if> or <xsl:when> element. For details + * see If.parserContents() and When.parserContents() + */ + final Parser parser = getParser(); + if (parser != null) { + reportWarning(this, parser, ErrorMsg.FUNCTION_RESOLVE_ERR, + _fname.toString()); } - return typeCheckExternal(stable); + unresolvedExternal = true; + return _type = Type.Void; } } diff --git a/src/org/apache/xalan/xsltc/compiler/LiteralElement.java b/src/org/apache/xalan/xsltc/compiler/LiteralElement.java index fffa79b..a041344 100644 --- a/src/org/apache/xalan/xsltc/compiler/LiteralElement.java +++ b/src/org/apache/xalan/xsltc/compiler/LiteralElement.java @@ -77,10 +77,11 @@ import org.apache.bcel.generic.*; import org.apache.xalan.xsltc.compiler.util.*; final class LiteralElement extends Instruction { + private String _name; - private Hashtable _accessedPrefixes = null; - private LiteralElement _parent; + private LiteralElement _literalElemParent; private Vector _attributeElements = null; + private Hashtable _accessedPrefixes = null; private final static String XMLNS_STRING = "xmlns"; @@ -119,10 +120,10 @@ final class LiteralElement extends Instruction { SymbolTable stable, boolean declared) { // Check if the parent has a declaration for this namespace - if (_parent != null) { - final String parentUri = _parent.accessedNamespace(prefix); + if (_literalElemParent != null) { + final String parentUri = _literalElemParent.accessedNamespace(prefix); if (parentUri == null) { - _parent.registerNamespace(prefix, uri, stable, declared); + _literalElemParent.registerNamespace(prefix, uri, stable, declared); return; } if (parentUri.equals(uri)) return; @@ -139,7 +140,7 @@ final class LiteralElement extends Instruction { if (old != null) { if (old.equals(uri)) return; - else + else prefix = stable.generateNamespacePrefix(); } } @@ -207,7 +208,6 @@ final class LiteralElement extends Instruction { _attributeElements.insertElementAt(attribute,0); } - /** * Type-check the contents of this element. The element itself does not * need any type checking as it leaves nothign on the JVM's stack. @@ -255,23 +255,24 @@ final class LiteralElement extends Instruction { * Registers all namespaces that are used by the element/attributes */ public void parseContents(Parser parser) { - final SymbolTable stable = parser.getSymbolTable(); stable.setCurrentNode(this); // Find the closest literal element ancestor (if there is one) - SyntaxTreeNode _parent = getParent(); - while ((_parent != null) && !(_parent instanceof LiteralElement)) - _parent = _parent.getParent(); - if (!(_parent instanceof LiteralElement)) - _parent = null; + SyntaxTreeNode _literalElemParent = getParent(); + while (_literalElemParent != null && !(_literalElemParent instanceof LiteralElement)) { + _literalElemParent = _literalElemParent.getParent(); + } + + if (!(_literalElemParent instanceof LiteralElement)) { + _literalElemParent = null; + } _name = translateQName(_qname, stable); // Process all attributes and register all namespaces they use final int count = _attributes.getLength(); for (int i = 0; i < count; i++) { - final QName qname = parser.getQName(_attributes.getQName(i)); final String uri = qname.getNamespace(); final String val = _attributes.getValue(i); @@ -290,12 +291,15 @@ final class LiteralElement extends Instruction { else if (qname == parser.getExcludeResultPrefixes()) { stable.excludeNamespaces(val); } - // Ignore all other attributes in XSL namespace - else if ((uri != null) && (uri.equals(XSLT_URI))) { - - } - // Handle literal attributes (attributes not in XSL namespace) else { + // Ignore special attributes + final String prefix = qname.getPrefix(); + if (uri != null && uri.equals(XSLT_URI) || + prefix != null && prefix.equals(XMLNS_STRING)) { + continue; + } + + // Handle all other literal attributes final String name = translateQName(qname, stable); LiteralAttribute attr = new LiteralAttribute(name, val, parser); addAttribute(attr); @@ -311,9 +315,8 @@ final class LiteralElement extends Instruction { final String prefix = (String)include.nextElement(); if (!prefix.equals("xml")) { final String uri = lookupNamespace(prefix); - if ((uri != null) && (!uri.equals(XSLT_URI))) { - if (!stable.isExcludedNamespace(uri)) - registerNamespace(prefix,uri,stable,true); + if (uri != null && !stable.isExcludedNamespace(uri)) { + registerNamespace(prefix, uri, stable, true); } } } @@ -322,7 +325,6 @@ final class LiteralElement extends Instruction { // Process all attributes and register all namespaces they use for (int i = 0; i < count; i++) { - final QName qname = parser.getQName(_attributes.getQName(i)); final String val = _attributes.getValue(i); @@ -344,7 +346,9 @@ final class LiteralElement extends Instruction { /** * Compiles code that emits the literal element to the output handler, * first the start tag, then namespace declaration, then attributes, - * then the element contents, and then the element end tag. + * then the element contents, and then the element end tag. Since the + * value of an attribute may depend on a variable, variables must be + * compiled first. */ public void translate(ClassGenerator classGen, MethodGenerator methodGen) { @@ -354,23 +358,52 @@ final class LiteralElement extends Instruction { // Compile code to emit element start tag il.append(methodGen.loadHandler()); il.append(new PUSH(cpg, _name)); - il.append(DUP2); // duplicate these 2 args for endElement + il.append(DUP2); // duplicate these 2 args for endElement il.append(methodGen.startElement()); + // The value of an attribute may depend on a (sibling) variable + for (int i = 0; i < elementCount(); i++) { + final SyntaxTreeNode item = (SyntaxTreeNode) elementAt(i); + if (item instanceof Variable) { + item.translate(classGen, methodGen); + removeElement(item); // avoid translating it twice + } + } + // Compile code to emit namespace attributes if (_accessedPrefixes != null) { + boolean declaresDefaultNS = false; Enumeration e = _accessedPrefixes.keys(); + while (e.hasMoreElements()) { final String prefix = (String)e.nextElement(); final String uri = (String)_accessedPrefixes.get(prefix); - if ((uri != Constants.EMPTYSTRING) || - (prefix != Constants.EMPTYSTRING)) { + + if (uri != Constants.EMPTYSTRING || + prefix != Constants.EMPTYSTRING) + { + if (prefix == Constants.EMPTYSTRING) { + declaresDefaultNS = true; + } il.append(methodGen.loadHandler()); il.append(new PUSH(cpg,prefix)); il.append(new PUSH(cpg,uri)); il.append(methodGen.namespace()); } } + + /* + * If our XslElement parent redeclares the default NS, and this + * element doesn't, it must be redeclared one more time. + */ + if (!declaresDefaultNS && (_parent instanceof XslElement) + && ((XslElement) _parent).declaresDefaultNS()) + { + il.append(methodGen.loadHandler()); + il.append(new PUSH(cpg, Constants.EMPTYSTRING)); + il.append(new PUSH(cpg, Constants.EMPTYSTRING)); + il.append(methodGen.namespace()); + } } // Output all attributes diff --git a/src/org/apache/xalan/xsltc/compiler/ParentLocationPath.java b/src/org/apache/xalan/xsltc/compiler/ParentLocationPath.java index adca196..8ffd159 100644 --- a/src/org/apache/xalan/xsltc/compiler/ParentLocationPath.java +++ b/src/org/apache/xalan/xsltc/compiler/ParentLocationPath.java @@ -216,10 +216,12 @@ final class ParentLocationPath extends RelativeLocationPath { Expression stp = _step; if (stp instanceof ParentLocationPath) stp = ((ParentLocationPath)stp).getStep(); + if ((_path instanceof Step) && (stp instanceof Step)) { final int path = ((Step)_path).getAxis(); final int step = ((Step)stp).getAxis(); if ((path == Axis.DESCENDANTORSELF && step == Axis.CHILD) || + (path == Axis.DESCENDANTORSELF && step == Axis.ATTRIBUTE) || (path == Axis.PRECEDING && step == Axis.PARENT)) { final int incl = cpg.addMethodref(STEP_ITERATOR_CLASS, "includeSelf", diff --git a/src/org/apache/xalan/xsltc/compiler/Parser.java b/src/org/apache/xalan/xsltc/compiler/Parser.java index c4b2fd6..486a35d 100644 --- a/src/org/apache/xalan/xsltc/compiler/Parser.java +++ b/src/org/apache/xalan/xsltc/compiler/Parser.java @@ -265,6 +265,10 @@ public class Parser implements Constants, ContentHandler { } public QName getQName(final String stringRep) { + return getQName(stringRep, true); + } + + public QName getQName(final String stringRep, boolean reportError) { // parse and retrieve namespace final int colon = stringRep.lastIndexOf(':'); if (colon != -1) { @@ -275,7 +279,7 @@ public class Parser implements Constants, ContentHandler { // Get the namespace uri from the symbol table if (prefix.equals("xmlns") == false) { namespace = _symbolTable.lookupNamespace(prefix); - if (namespace == null) { + if (namespace == null && reportError) { final int line = _locator.getLineNumber(); ErrorMsg err = new ErrorMsg(ErrorMsg.NAMESPACE_UNDEF_ERR, line, prefix); @@ -1072,7 +1076,9 @@ public class Parser implements Constants, ContentHandler { * This has to be passed on to the symbol table! */ public void startPrefixMapping(String prefix, String uri) { - if (_prefixMapping == null) _prefixMapping = new Hashtable(); + if (_prefixMapping == null) { + _prefixMapping = new Hashtable(); + } _prefixMapping.put(prefix, uri); } diff --git a/src/org/apache/xalan/xsltc/compiler/ProcessingInstruction.java b/src/org/apache/xalan/xsltc/compiler/ProcessingInstruction.java index 91e40a4..fa2a188 100644 --- a/src/org/apache/xalan/xsltc/compiler/ProcessingInstruction.java +++ b/src/org/apache/xalan/xsltc/compiler/ProcessingInstruction.java @@ -109,13 +109,13 @@ final class ProcessingInstruction extends Instruction { // get String out of the handler il.append(new INVOKEVIRTUAL(cpg.addMethodref(STRING_VALUE_HANDLER, - "getValue", - "()"+STRING_SIG))); + "getValueOfPI", + "()" + STRING_SIG))); // call "processingInstruction" final int processingInstruction = cpg.addInterfaceMethodref(TRANSLET_OUTPUT_INTERFACE, "processingInstruction", - "("+STRING_SIG+STRING_SIG+")V"); + "(" + STRING_SIG + STRING_SIG + ")V"); il.append(new INVOKEINTERFACE(processingInstruction, 3)); // Restore old handler base from stack il.append(methodGen.storeHandler()); diff --git a/src/org/apache/xalan/xsltc/compiler/Step.java b/src/org/apache/xalan/xsltc/compiler/Step.java index 4d54224..9146616 100644 --- a/src/org/apache/xalan/xsltc/compiler/Step.java +++ b/src/org/apache/xalan/xsltc/compiler/Step.java @@ -508,22 +508,6 @@ final class Step extends RelativeLocationPath { il.append(new CHECKCAST(cpg.addClass(className))); } il.append(new INVOKESPECIAL(idx)); - - // Determine if the node set should be generated using the - // natural order of the node set or document order. - // See CurrentNodeListIterator's constructor(s) for details. - SyntaxTreeNode parent = getParent(); - while (!(parent instanceof Template)) { - if (parent == null) break; - if (parent instanceof ApplyTemplates) { - idx = cpg.addMethodref(CURRENT_NODE_LIST_ITERATOR, - "forceNaturalOrder", - "()"+NODE_ITERATOR_SIG); - il.append(new INVOKEVIRTUAL(idx)); - break; - } - parent = parent.getParent(); - } } } } diff --git a/src/org/apache/xalan/xsltc/compiler/StepPattern.java b/src/org/apache/xalan/xsltc/compiler/StepPattern.java index 78243a3..c14b743 100644 --- a/src/org/apache/xalan/xsltc/compiler/StepPattern.java +++ b/src/org/apache/xalan/xsltc/compiler/StepPattern.java @@ -162,10 +162,12 @@ class StepPattern extends RelativePathPattern { private int analyzeCases() { boolean noContext = true; final int n = _predicates.size(); + for (int i = 0; i < n && noContext; i++) { final Predicate pred = (Predicate)_predicates.elementAt(i); - final Expression exp = pred.getExpr(); - if (exp.hasPositionCall()) noContext = false; + if (pred.getExpr().hasPositionCall()) { + noContext = false; + } } if (noContext) { diff --git a/src/org/apache/xalan/xsltc/compiler/Stylesheet.java b/src/org/apache/xalan/xsltc/compiler/Stylesheet.java index 15b0522..fa2d816 100644 --- a/src/org/apache/xalan/xsltc/compiler/Stylesheet.java +++ b/src/org/apache/xalan/xsltc/compiler/Stylesheet.java @@ -284,7 +284,6 @@ public final class Stylesheet extends SyntaxTreeNode { super.addPrefixMapping(prefix, uri); } - /** * Store extension URIs */ @@ -308,8 +307,10 @@ public final class Stylesheet extends SyntaxTreeNode { public void excludeExtensionPrefixes(Parser parser) { final SymbolTable stable = parser.getSymbolTable(); final String excludePrefixes = getAttribute("exclude-result-prefixes"); - final String extensionPrefixes = - getAttribute("extension-element-prefixes"); + final String extensionPrefixes = getAttribute("extension-element-prefixes"); + + // Exclude XSLT uri + stable.excludeURI(Constants.XSLT_URI); stable.excludeNamespaces(excludePrefixes); stable.excludeNamespaces(extensionPrefixes); extensionURI(extensionPrefixes, stable); @@ -878,6 +879,18 @@ public final class Stylesheet extends SyntaxTreeNode { "("+OUTPUT_HANDLER_SIG+")V"); il.append(new INVOKEVIRTUAL(index)); + // Compile buildKeys -- TODO: omit if not needed + final String keySig = compileBuildKeys(classGen); + final int keyIdx = cpg.addMethodref(getClassName(), + "buildKeys", keySig); + il.append(classGen.loadTranslet()); // The 'this' pointer + il.append(classGen.loadTranslet()); + il.append(new GETFIELD(domField)); // The DOM reference + il.append(transf.loadIterator()); // Not really used, but... + il.append(transf.loadHandler()); // The output handler + il.append(new PUSH(cpg, DOM.ROOTNODE)); // Start with the root node + il.append(new INVOKEVIRTUAL(keyIdx)); + // Look for top-level elements that need handling final Enumeration toplevel = elements(); if ((_globals.size() > 0) || (toplevel.hasMoreElements())) { @@ -896,17 +909,6 @@ public final class Stylesheet extends SyntaxTreeNode { il.append(new INVOKEVIRTUAL(topLevelIdx)); } - final String keySig = compileBuildKeys(classGen); - final int keyIdx = cpg.addMethodref(getClassName(), - "buildKeys", keySig); - il.append(classGen.loadTranslet()); // The 'this' pointer - il.append(classGen.loadTranslet()); - il.append(new GETFIELD(domField)); // The DOM reference - il.append(transf.loadIterator()); // Not really used, but... - il.append(transf.loadHandler()); // The output handler - il.append(new PUSH(cpg, DOM.ROOTNODE)); // Start with the root node - il.append(new INVOKEVIRTUAL(keyIdx)); - // start document il.append(transf.loadHandler()); il.append(transf.startDocument()); diff --git a/src/org/apache/xalan/xsltc/compiler/SymbolTable.java b/src/org/apache/xalan/xsltc/compiler/SymbolTable.java index cf5c576..4b190d1 100644 --- a/src/org/apache/xalan/xsltc/compiler/SymbolTable.java +++ b/src/org/apache/xalan/xsltc/compiler/SymbolTable.java @@ -262,11 +262,10 @@ final class SymbolTable { * Check if a namespace should not be declared in the output (unless used) */ public boolean isExcludedNamespace(String uri) { - if (uri == null) return false; - if (_excludedURI == null) return false; - final Integer refcnt = (Integer)_excludedURI.get(uri); - if (refcnt == null) return false; - if (refcnt.intValue() > 0) return true; + if (uri != null && _excludedURI != null) { + final Integer refcnt = (Integer)_excludedURI.get(uri); + return (refcnt != null && refcnt.intValue() > 0); + } return false; } diff --git a/src/org/apache/xalan/xsltc/compiler/SyntaxTreeNode.java b/src/org/apache/xalan/xsltc/compiler/SyntaxTreeNode.java index 26f6c13..cd6f4d1 100644 --- a/src/org/apache/xalan/xsltc/compiler/SyntaxTreeNode.java +++ b/src/org/apache/xalan/xsltc/compiler/SyntaxTreeNode.java @@ -193,18 +193,16 @@ public abstract class SyntaxTreeNode implements Constants { * @return The value of the attribute of name 'qname'. */ protected String getAttribute(String qname) { - if (_attributes == null) - return(Constants.EMPTYSTRING); + if (_attributes == null) { + return EMPTYSTRING; + } final String value = _attributes.getValue(qname); - if (value == null) - return(Constants.EMPTYSTRING); - else - return(value); + return (value == null || value.equals(EMPTYSTRING)) ? + EMPTYSTRING : value; } protected boolean hasAttribute(String qname) { - if (_attributes == null) return false; - return (_attributes.getValue(qname) != null); + return (_attributes != null && _attributes.getValue(qname) != null); } /** diff --git a/src/org/apache/xalan/xsltc/compiler/XslAttribute.java b/src/org/apache/xalan/xsltc/compiler/XslAttribute.java index f6e8b6e..445eab0 100644 --- a/src/org/apache/xalan/xsltc/compiler/XslAttribute.java +++ b/src/org/apache/xalan/xsltc/compiler/XslAttribute.java @@ -73,10 +73,9 @@ import org.apache.xalan.xsltc.compiler.util.*; final class XslAttribute extends Instruction { - // Attribute contents - private AttributeValue _name; // name treated as AVT (7.1.3) - private AttributeValueTemplate _namespace = null; private String _prefix; + private AttributeValue _name; // name treated as AVT (7.1.3) + private AttributeValueTemplate _namespace = null; private boolean _ignore = false; /** @@ -99,15 +98,15 @@ final class XslAttribute extends Instruction { * Parses the attribute's contents. Special care taken for namespaces. */ public void parseContents(Parser parser) { - + boolean generated = false; final SymbolTable stable = parser.getSymbolTable(); - String namespace = getAttribute("namespace"); + String name = getAttribute("name"); - QName qname = parser.getQName(name); + String namespace = getAttribute("namespace"); + QName qname = parser.getQName(name, false); final String prefix = qname.getPrefix(); - boolean generated = false; - if ((prefix != null) && (prefix.equals("xmlns"))) { + if ((prefix != null) && (prefix.equals(XMLNS_PREFIX))) { reportError(this, parser, ErrorMsg.ILLEGAL_ATTR_NAME_ERR, name); return; } @@ -118,11 +117,13 @@ final class XslAttribute extends Instruction { for (int i = 0; i < parent.elementCount(); i++) { SyntaxTreeNode item = (SyntaxTreeNode)siblings.elementAt(i); if (item == this) break; + // These three objects result in one or more attribute output if (item instanceof XslAttribute) continue; if (item instanceof UseAttributeSets) continue; if (item instanceof LiteralAttribute) continue; if (item instanceof Text) continue; + // These objects _can_ result in one or more attribute // The output handler will generate an error if not (at runtime) if (item instanceof If) continue; @@ -134,24 +135,23 @@ final class XslAttribute extends Instruction { } // Get namespace from namespace attribute? - if ((namespace != null) && (namespace != Constants.EMPTYSTRING)) { - // Prefix could be in symbol table + if (namespace != null && namespace != Constants.EMPTYSTRING) { _prefix = lookupPrefix(namespace); _namespace = new AttributeValueTemplate(namespace, parser); } // Get namespace from prefix in name attribute? - else if ((prefix != null) && (prefix != Constants.EMPTYSTRING)) { + else if (prefix != null && prefix != Constants.EMPTYSTRING) { _prefix = prefix; namespace = lookupNamespace(prefix); - if (namespace != null) + if (namespace != null) { _namespace = new AttributeValueTemplate(namespace, parser); + } } // Common handling for namespaces: if (_namespace != null) { - // Generate prefix if we have none - if (_prefix == null) { + if (_prefix == null || _prefix == Constants.EMPTYSTRING) { if (prefix != null) { _prefix = prefix; } @@ -160,25 +160,25 @@ final class XslAttribute extends Instruction { generated = true; } } - - if (_prefix == Constants.EMPTYSTRING) { - name = qname.getLocalPart(); + else if (prefix != null && !prefix.equals(_prefix)) { + _prefix = prefix; } - else { - name = _prefix+":"+qname.getLocalPart(); - // PROBLEM: - // The namespace URI must be passed to the parent element, - // but we don't yet know what the actual URI is (as we only - // know it as an attribute value template). New design needed. - if ((parent instanceof LiteralElement) && (!generated)) { - ((LiteralElement)parent).registerNamespace(_prefix, - namespace, - stable,false); - } + + name = _prefix + ":" + qname.getLocalPart(); + + /* + * TODO: The namespace URI must be passed to the parent + * element but we don't yet know what the actual URI is + * (as we only know it as an attribute value template). + */ + if ((parent instanceof LiteralElement) && (!generated)) { + ((LiteralElement)parent).registerNamespace(_prefix, + namespace, + stable, false); } } - if (name.equals("xmlns")) { + if (name.equals(XMLNS_PREFIX)) { reportError(this, parser, ErrorMsg.ILLEGAL_ATTR_NAME_ERR, name); return; } @@ -191,15 +191,14 @@ final class XslAttribute extends Instruction { parseChildren(parser); } - /** - * - */ public Type typeCheck(SymbolTable stable) throws TypeCheckError { - if (_ignore) return(Type.Void); - _name.typeCheck(stable); - if (_namespace != null) - _namespace.typeCheck(stable); - typeCheckContents(stable); + if (!_ignore) { + _name.typeCheck(stable); + if (_namespace != null) { + _namespace.typeCheck(stable); + } + typeCheckContents(stable); + } return Type.Void; } diff --git a/src/org/apache/xalan/xsltc/compiler/XslElement.java b/src/org/apache/xalan/xsltc/compiler/XslElement.java index 84d7d38..8f79435 100644 --- a/src/org/apache/xalan/xsltc/compiler/XslElement.java +++ b/src/org/apache/xalan/xsltc/compiler/XslElement.java @@ -88,6 +88,10 @@ final class XslElement extends Instruction { displayContents(indent + IndentIncrement); } + public boolean declaresDefaultNS() { + return (_namespace != null && _prefix == EMPTYSTRING); + } + /** * Parses the element's contents. Special care taken for namespaces. * TODO: The namespace attribute that specifies the namespace to use diff --git a/src/org/apache/xalan/xsltc/compiler/util/Util.java b/src/org/apache/xalan/xsltc/compiler/util/Util.java index 2082fe1..0fc872b 100644 --- a/src/org/apache/xalan/xsltc/compiler/util/Util.java +++ b/src/org/apache/xalan/xsltc/compiler/util/Util.java @@ -108,17 +108,20 @@ public final class Util { * Replace all illegal Java chars by '_'. */ public static String toJavaName(String name) { - final StringBuffer result = new StringBuffer(); + if (name.length() > 0) { + final StringBuffer result = new StringBuffer(); - char ch = name.charAt(0); - result.append(Character.isJavaIdentifierStart(ch) ? ch : '_'); + char ch = name.charAt(0); + result.append(Character.isJavaIdentifierStart(ch) ? ch : '_'); - final int n = name.length(); - for (int i = 1; i < n; i++) { - ch = name.charAt(i); - result.append(Character.isJavaIdentifierPart(ch) ? ch : '_'); + final int n = name.length(); + for (int i = 1; i < n; i++) { + ch = name.charAt(i); + result.append(Character.isJavaIdentifierPart(ch) ? ch : '_'); + } + return result.toString(); } - return result.toString(); + return name; } public static Type getJCRefType(String signature) { @@ -130,15 +133,11 @@ public final class Util { } public static void println(String s) { - if (false) { - System.out.println(s); - } + System.out.println(s); } public static void println(char ch) { - if (false) { - System.out.println(ch); - } + System.out.println(ch); } public static void TRACE1() { diff --git a/src/org/apache/xalan/xsltc/dom/CurrentNodeListIterator.java b/src/org/apache/xalan/xsltc/dom/CurrentNodeListIterator.java index dfb9f3d..79df194 100644 --- a/src/org/apache/xalan/xsltc/dom/CurrentNodeListIterator.java +++ b/src/org/apache/xalan/xsltc/dom/CurrentNodeListIterator.java @@ -99,11 +99,6 @@ public final class CurrentNodeListIterator extends NodeIteratorBase { _currentNode = currentNode; } - public NodeIterator forceNaturalOrder() { - _docOrder = true; - return this; - } - public void setRestartable(boolean isRestartable) { _isRestartable = isRestartable; _source.setRestartable(isRestartable); @@ -139,9 +134,8 @@ public final class CurrentNodeListIterator extends NodeIteratorBase { final int currentNode = _currentNode; for (int index = _current; index < last; ) { - final int node = _nodes.at(index++); // note increment - final int position = docOrder ? index : last - index + 1; - if (_filter.test(node, position, last, currentNode, _translet, this)) { + final int node = _nodes.at(index++); // note increment + if (_filter.test(node, index, last, currentNode, _translet, this)) { _current = index; return returnNode(node); } @@ -156,9 +150,8 @@ public final class CurrentNodeListIterator extends NodeIteratorBase { final int currNode = _currentNode; for (int index = _current; index < last; ) { - int nodeIndex = _nodes.at(index++); // note increment - final int pos = docOrder ? index : last - index + 1; - if (_filter.test(nodeIndex, pos, last, currNode, _translet, this)) { + int nodeIndex = _nodes.at(index++); // note increment + if (_filter.test(nodeIndex, index, last, currNode, _translet, this)) { lastPosition++; } } @@ -185,7 +178,7 @@ public final class CurrentNodeListIterator extends NodeIteratorBase { } public int getLast() { - return ( _last == -1 ) ? computePositionOfLast() : _last; + return (_last == -1) ? computePositionOfLast() : _last; } public void setMark() { diff --git a/src/org/apache/xalan/xsltc/dom/DOMBuilder.java b/src/org/apache/xalan/xsltc/dom/DOMBuilder.java index cc67a53..dabd49e 100644 --- a/src/org/apache/xalan/xsltc/dom/DOMBuilder.java +++ b/src/org/apache/xalan/xsltc/dom/DOMBuilder.java @@ -64,4 +64,4 @@ package org.apache.xalan.xsltc.dom; import org.xml.sax.ContentHandler; import org.xml.sax.ext.LexicalHandler; -public interface DOMBuilder extends ContentHandler, LexicalHandler { } +public interface DOMBuilder extends ExtendedSAX { } diff --git a/src/org/apache/xalan/xsltc/dom/DOMImpl.java b/src/org/apache/xalan/xsltc/dom/DOMImpl.java index df1a7ea..a4ceb85 100644 --- a/src/org/apache/xalan/xsltc/dom/DOMImpl.java +++ b/src/org/apache/xalan/xsltc/dom/DOMImpl.java @@ -81,6 +81,7 @@ import org.w3c.dom.Document; import org.xml.sax.*; import org.xml.sax.ext.*; +import org.xml.sax.helpers.AttributesImpl; import org.apache.xalan.xsltc.*; import org.apache.xalan.xsltc.util.IntegerArray; import org.apache.xalan.xsltc.runtime.BasisLibrary; @@ -136,6 +137,9 @@ public final class DOMImpl implements DOM, Externalizable { // Tracks which textnodes are whitespaces and which are not private BitArray _whitespace; // takes xml:space into acc. + // Tracks which textnodes are not escaped + private BitArray _dontEscape = null; + // The URI to this document private String _documentURI; @@ -1053,6 +1057,7 @@ public final class DOMImpl implements DOM, Externalizable { while ((_ns == DOM.NULL) && (_node != DOM.NULL)) { _node = _parent[_node]; _ns = _lengthOrAttr[_node]; + while ((_ns != DOM.NULL) && (_type[_ns] != NAMESPACE)) { _ns = _nextSibling[_ns]; } @@ -1980,6 +1985,7 @@ public final class DOMImpl implements DOM, Externalizable { case ROOT: return getNodeValue(_offsetOrChild[node]); case TEXT: + // GTM - add escapign code here too. case COMMENT: return makeStringValue(node); case PROCESSING_INSTRUCTION: @@ -2162,6 +2168,13 @@ public final class DOMImpl implements DOM, Externalizable { out.writeObject(_whitespace); + if (_dontEscape != null) { + out.writeObject(_dontEscape); + } + else { + out.writeObject(new BitArray(0)); + } + out.flush(); } @@ -2190,6 +2203,11 @@ public final class DOMImpl implements DOM, Externalizable { _whitespace = (BitArray)in.readObject(); + _dontEscape = (BitArray)in.readObject(); + if (_dontEscape.size() == 0) { + _dontEscape = null; + } + _types = setupMapping(_namesArray); } @@ -2614,9 +2632,23 @@ public final class DOMImpl implements DOM, Externalizable { _lengthOrAttr[node])); break; case TEXT: + boolean last = false; + boolean escapeBit = false; + + if (_dontEscape != null) { + escapeBit = _dontEscape.getBit(node); + if (escapeBit) { + last = handler.setEscaping(false); + } + } + handler.characters(_text, _offsetOrChild[node], _lengthOrAttr[node]); + + if (_dontEscape != null && escapeBit) { + handler.setEscaping(last); + } break; case ATTRIBUTE: shallowCopy(node, handler); @@ -2628,6 +2660,7 @@ public final class DOMImpl implements DOM, Externalizable { if (isElement(node)) { // Start element definition final String name = copyElement(node, type, handler); + // Copy element attribute for (int a=_lengthOrAttr[node]; a!=NULL; a=_nextSibling[a]) { if (_type[a] != NAMESPACE) { @@ -2694,9 +2727,11 @@ public final class DOMImpl implements DOM, Externalizable { case ROOT: // do nothing return EMPTYSTRING; case TEXT: + handler.characters(_text, _offsetOrChild[node], _lengthOrAttr[node]); + return null; case PROCESSING_INSTRUCTION: copyPI(node, handler); @@ -2899,8 +2934,7 @@ public final class DOMImpl implements DOM, Externalizable { * DOM builder's interface is pure SAX2 (must investigate) */ public TransletOutputHandler getOutputDomBuilder() { - DOMBuilder builder = getBuilder(); - return new SAXAdapter(builder, builder); + return new SAXAdapter(new DOMBuilderImpl()); } /** @@ -2959,6 +2993,11 @@ public final class DOMImpl implements DOM, Externalizable { private static final String XML_STRING = "xml:"; private static final String XMLSPACE_STRING = "xml:space"; private static final String PRESERVE_STRING = "preserve"; + private static final String XML_PREFIX = "xml"; + private static final String XMLNS_PREFIX = "xmlns"; + + private boolean _escaping = true; + private boolean _disableEscaping = false; /** * Default constructor for the DOMBuiler class @@ -3076,7 +3115,6 @@ public final class DOMImpl implements DOM, Externalizable { */ private short makeElementNode(String uri, String localname) throws SAXException { - final String name; if (uri != EMPTYSTRING) name = uri + ':' + localname; @@ -3170,6 +3208,7 @@ public final class DOMImpl implements DOM, Externalizable { */ private int makeTextNode(boolean isWhitespace) { if (_currentOffset > _baseOffset) { + final int node = nextNode(); final int limit = _currentOffset; // Tag as whitespace node if the parser tells us that it is... @@ -3188,6 +3227,14 @@ public final class DOMImpl implements DOM, Externalizable { _type[node] = TEXT; linkChildren(node); storeTextRef(node); + + if (_disableEscaping) { + if (_dontEscape == null) { + _dontEscape = new BitArray(_whitespace.size()); + } + _dontEscape.setBit(node); + _disableEscaping = false; + } return node; } return -1; @@ -3217,33 +3264,29 @@ public final class DOMImpl implements DOM, Externalizable { * Creates an attribute node */ private int makeAttributeNode(int parent, Attributes attList, int i) - throws SAXException { - + throws SAXException + { final int node = nextAttributeNode(); - final String qname = attList.getQName(i); - final String localname = attList.getLocalName(i); + String localname = attList.getLocalName(i); final String value = attList.getValue(i); StringBuffer namebuf = new StringBuffer(EMPTYSTRING); - // Create the internal attribute node name (uri+@+localname) - if (qname.startsWith(XML_STRING)) { - if (qname.startsWith(XMLSPACE_STRING)) - xmlSpaceDefine(attList.getValue(i), parent); + if (qname.startsWith(XMLSPACE_STRING)) { + xmlSpaceDefine(attList.getValue(i), parent); } + + // Create the internal attribute node name (uri+@+localname) final String uri = attList.getURI(i); - if ((uri != null) && (!uri.equals(EMPTYSTRING))) { + if (uri != null && !uri.equals(EMPTYSTRING)) { namebuf.append(uri); namebuf.append(':'); } namebuf.append('@'); - if (localname != null ) - namebuf.append(localname); - else - namebuf.append(qname); + namebuf.append(localname.length() > 0 ? localname : qname); String name = namebuf.toString(); - + // Get the index of the attribute node name (create new if non-ex). Integer obj = (Integer)_names.get(name); if (obj == null) { @@ -3280,6 +3323,9 @@ public final class DOMImpl implements DOM, Externalizable { } System.arraycopy(ch, start, _text, _currentOffset, length); _currentOffset += length; + + _disableEscaping = !_escaping; + } /** @@ -3295,7 +3341,7 @@ public final class DOMImpl implements DOM, Externalizable { _type2[0] = NAMESPACE; startPrefixMapping(EMPTYSTRING, EMPTYSTRING); - startPrefixMapping("xml", "http://www.w3.org/XML/1998/namespace"); + startPrefixMapping(XML_PREFIX, "http://www.w3.org/XML/1998/namespace"); _lengthOrAttr[ROOTNODE] = _nextNamespace; _parent2[_nextNamespace] = ROOTNODE; _nextNamespace = DOM.NULL; @@ -3374,41 +3420,56 @@ public final class DOMImpl implements DOM, Externalizable { _lengthOrAttr[node] = DOM.NULL; + int last = -1; final int count = attributes.getLength(); // Append any namespace nodes if (_nextNamespace != DOM.NULL) { _lengthOrAttr[node] = _nextNamespace; + while (_nextNamespace != DOM.NULL) { _parent2[_nextNamespace] = node; - int tail = _nextNamespace; - _nextNamespace = _nextSibling2[_nextNamespace]; + _nextNamespace = _nextSibling2[last = _nextNamespace]; // Chain last namespace node to following attribute node(s) - if ((_nextNamespace == DOM.NULL) && (count > 0)) - _nextSibling2[tail] = _currentAttributeNode; + if (_nextNamespace == DOM.NULL && count > 0) { + _nextSibling2[last] = _currentAttributeNode; + } } } // Append any attribute nodes + boolean attrsAdded = false; if (count > 0) { int attr = _currentAttributeNode; - if (_lengthOrAttr[node] == DOM.NULL) + if (_lengthOrAttr[node] == DOM.NULL) { _lengthOrAttr[node] = attr; - for (int i = 0; i<count; i++) { - attr = makeAttributeNode(node, attributes, i); - _parent2[attr] = node; - _nextSibling2[attr] = attr + 1; } - _nextSibling2[attr] = DOM.NULL; + for (int i = 0; i < count; i++) { + if (!attributes.getQName(i).startsWith(XMLNS_PREFIX)) { + attr = makeAttributeNode(node, attributes, i); + _parent2[attr] = node; + _nextSibling2[attr] = attr + 1; + attrsAdded = true; + } + } + // Did we append namespace nodes only? + if (!attrsAdded && last != -1) { + _nextSibling2[last] = DOM.NULL; + } + else { + _nextSibling2[attr] = DOM.NULL; + } } final int col = qname.lastIndexOf(':'); // Assign an internal type to this element (may exist) - if ((uri != null) && (localName.length() > 0)) + if (uri != null && localName.length() > 0) { _type[node] = makeElementNode(uri, localName); - else + } + else { _type[node] = makeElementNode(qname, col); + } // Assign an internal type to the element's prefix (may exist) if (col > -1) { @@ -3502,7 +3563,8 @@ public final class DOMImpl implements DOM, Externalizable { else _nextSibling2[attr-1] = attr; _nextSibling2[attr] = DOM.NULL; - _prefix2[attr] = idx.shortValue(); + // _prefix2[attr] = idx.shortValue(); + _prefix2[attr] = ((Integer) stack.elementAt(0)).shortValue(); } } @@ -3587,6 +3649,11 @@ public final class DOMImpl implements DOM, Externalizable { // Resize the '_whitespace' array (a BitArray instance) _whitespace.resize(newSize); + // Resize the '_dontEscape' array (a BitArray instance) + if (_dontEscape != null) { + _dontEscape.resize(newSize); + } + // Resize the '_prefix' array final short[] newPrefix = new short[newSize]; System.arraycopy(_prefix, 0, newPrefix, 0, length); @@ -3656,5 +3723,11 @@ public final class DOMImpl implements DOM, Externalizable { } } + public boolean setEscaping(boolean value) { + final boolean temp = _escaping; + _escaping = value; + return temp; + } + } // end of DOMBuilder } diff --git a/src/org/apache/xalan/xsltc/dom/DOMBuilder.java b/src/org/apache/xalan/xsltc/dom/ExtendedSAX.java similarity index 95% copy from src/org/apache/xalan/xsltc/dom/DOMBuilder.java copy to src/org/apache/xalan/xsltc/dom/ExtendedSAX.java index cc67a53..8e87428 100644 --- a/src/org/apache/xalan/xsltc/dom/DOMBuilder.java +++ b/src/org/apache/xalan/xsltc/dom/ExtendedSAX.java @@ -64,4 +64,6 @@ package org.apache.xalan.xsltc.dom; import org.xml.sax.ContentHandler; import org.xml.sax.ext.LexicalHandler; -public interface DOMBuilder extends ContentHandler, LexicalHandler { } +public interface ExtendedSAX extends ContentHandler, LexicalHandler { + public boolean setEscaping(boolean escape); +} diff --git a/src/org/apache/xalan/xsltc/dom/SortingIterator.java b/src/org/apache/xalan/xsltc/dom/SortingIterator.java index 9d16c2b..e2ffd9e 100644 --- a/src/org/apache/xalan/xsltc/dom/SortingIterator.java +++ b/src/org/apache/xalan/xsltc/dom/SortingIterator.java @@ -66,11 +66,12 @@ package org.apache.xalan.xsltc.dom; import org.apache.xalan.xsltc.NodeIterator; import org.apache.xalan.xsltc.TransletException; +import org.apache.xalan.xsltc.runtime.BasisLibrary; public final class SortingIterator extends NodeIteratorBase { private final static int INIT_DATA_SIZE = 16; - private final NodeIterator _source; - private final NodeSortRecordFactory _factory; + private NodeIterator _source; + private NodeSortRecordFactory _factory; private NodeSortRecord[] _data; private int _free = 0; private int _current; // index in _nodes of the next node to try @@ -124,6 +125,29 @@ public final class SortingIterator extends NodeIteratorBase { _current = _markedNode; } + /** + * Clone a <code>SortingIterator</code> by cloning its source + * iterator and then sharing the factory and the array of + * <code>NodeSortRecords</code>. + */ + public NodeIterator cloneIterator() { + try { + final SortingIterator clone = (SortingIterator) super.clone(); + clone._source = _source.cloneIterator(); + clone._factory = _factory; // shared between clones + clone._data = _data; // shared between clones + clone._free = _free; + clone._current = _current; + clone.setRestartable(false); + return clone.reset(); + } + catch (CloneNotSupportedException e) { + BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR, + e.toString()); + return null; + } + } + private void addRecord(NodeSortRecord record) { if (_free == _data.length) { NodeSortRecord[] newArray = new NodeSortRecord[_data.length * 2]; diff --git a/src/org/apache/xalan/xsltc/dom/UnionIterator.java b/src/org/apache/xalan/xsltc/dom/UnionIterator.java index bfd1452..be22cd1 100644 --- a/src/org/apache/xalan/xsltc/dom/UnionIterator.java +++ b/src/org/apache/xalan/xsltc/dom/UnionIterator.java @@ -152,8 +152,10 @@ public final class UnionIterator extends NodeIteratorBase { final int smallest = _heap[0].node; if (smallest == END) { // iterator _heap[0] is done if (_heapSize > 1) { - // replace it with last + // Swap first and last (iterator must be restartable) + final LookAheadIterator temp = _heap[0]; _heap[0] = _heap[--_heapSize]; + _heap[_heapSize] = temp; } else { return END; diff --git a/src/org/apache/xalan/xsltc/runtime/AbstractTranslet.java b/src/org/apache/xalan/xsltc/runtime/AbstractTranslet.java index e363410..9b4c431 100644 --- a/src/org/apache/xalan/xsltc/runtime/AbstractTranslet.java +++ b/src/org/apache/xalan/xsltc/runtime/AbstractTranslet.java @@ -143,44 +143,15 @@ public abstract class AbstractTranslet implements Translet { */ public final void popParamFrame() { if (pbase > 0) { - int bot = pbase - 1; - int top = pframe - 1; - pframe = pbase - 1; - pbase = ((Integer) paramsStack.elementAt(pframe)).intValue(); - // bug fix #3424, John Howard. - // remove objects that are in the stack since objects are - // added with insertElementAt(int) and will cause memory retention - for (int i=top; i>=bot; i--) { - paramsStack.removeElementAt(i); + final int oldpbase = ((Integer)paramsStack.elementAt(--pbase)).intValue(); + for (int i = pbase; i < pframe; i++) { + paramsStack.setElementAt(null, i); // for the GC } + pframe = pbase; pbase = oldpbase; } } /** - * Replace a certain character in a string with a new substring. - */ - private static String replace(String base, char c, String str) { - final int len = base.length() - 1; - int pos; - while ((pos = base.indexOf(c)) > -1) { - if (pos == 0) { - final String after = base.substring(1); - base = str + after; - } - else if (pos == len) { - final String before = base.substring(0, pos); - base = before + str; - } - else { - final String before = base.substring(0, pos); - final String after = base.substring(pos+1); - base = before + str + after; - } - } - return base; - } - - /** * Add a new global parameter if not already in the current frame. */ public final Object addParameter(String name, Object value) { @@ -224,6 +195,7 @@ public abstract class AbstractTranslet implements Translet { * Clears the parameter stack. */ public void clearParameters() { + pbase = pframe = 0; paramsStack.clear(); } @@ -246,6 +218,7 @@ public abstract class AbstractTranslet implements Translet { varsStack.insertElementAt(new Integer(vbase), vframe); vbase = ++vframe; vframe += frameSize; + varsStack.setSize(vframe + 1); // clear stack frame } /** @@ -253,16 +226,11 @@ public abstract class AbstractTranslet implements Translet { */ public final void popVarFrame() { if (vbase > 0) { - int bot = vbase - 1; - int top = vframe - 1; - vframe = vbase - 1; - vbase = ((Integer)varsStack.elementAt(vframe)).intValue(); - // bug fix 3424, John Howard - // remove objects that are in the stack since objects are - // added with insertElementAt(int) and will cause memory retention - for (int i=top; i>=bot; i--) { - varsStack.removeElementAt(i); + final int oldvbase = ((Integer)varsStack.elementAt(--vbase)).intValue(); + for (int i = vbase; i < vframe; i++) { + varsStack.setElementAt(null, i); // for the GC } + vframe = vbase; vbase = oldvbase; } } @@ -270,18 +238,38 @@ public abstract class AbstractTranslet implements Translet { * Get the value of a variable given its index. */ public final Object getVariable(int vindex) { - // bug fix 3424, John Howard return varsStack.elementAt(vbase + vindex); } - /** * Set the value of a variable in the current frame. */ public final void addVariable(int vindex, Object value) { - final int index = vbase + vindex; - if (index > varsStack.size()) varsStack.setSize(index); - varsStack.insertElementAt(value, index); + varsStack.setElementAt(value, vbase + vindex); + } + + /** + * Replace a certain character in a string with a new substring. + */ + private static String replace(String base, char c, String str) { + final int len = base.length() - 1; + int pos; + while ((pos = base.indexOf(c)) > -1) { + if (pos == 0) { + final String after = base.substring(1); + base = str + after; + } + else if (pos == len) { + final String before = base.substring(0, pos); + base = before + str; + } + else { + final String before = base.substring(0, pos); + final String after = base.substring(pos+1); + base = before + str + after; + } + } + return base; } /************************************************************************ @@ -582,10 +570,10 @@ public abstract class AbstractTranslet implements Translet { // Transfer all settings relevant to XML output if (_method.equals("xml")) { if (_standalone != null) handler.setStandalone(_standalone); + if (_omitHeader) handler.omitHeader(true); handler.setType(TextOutput.XML); handler.setCdataElements(_cdata); if (_version != null) handler.setVersion(_version); - if (_omitHeader) handler.omitHeader(true); handler.setIndent(_indent); if (_doctypeSystem != null) handler.setDoctype(_doctypeSystem, _doctypePublic); diff --git a/src/org/apache/xalan/xsltc/runtime/BasisLibrary.java b/src/org/apache/xalan/xsltc/runtime/BasisLibrary.java index 18f223b..b800d89 100644 --- a/src/org/apache/xalan/xsltc/runtime/BasisLibrary.java +++ b/src/org/apache/xalan/xsltc/runtime/BasisLibrary.java @@ -427,7 +427,7 @@ public final class BasisLibrary implements Operators { if (name.equals("xsl:version")) return("1.0"); if (name.equals("xsl:vendor")) - return("Apache Xalan XSLTC"); + return("Apache Software Foundation"); if (name.equals("xsl:vendor-url")) return("http://xml.apache.org/xalan-j"); diff --git a/src/org/apache/xalan/xsltc/runtime/Constants.java b/src/org/apache/xalan/xsltc/runtime/Constants.java index 4f72e23..da2bdb3 100644 --- a/src/org/apache/xalan/xsltc/runtime/Constants.java +++ b/src/org/apache/xalan/xsltc/runtime/Constants.java @@ -83,4 +83,9 @@ public interface Constants { public static final String NAMESPACE_FEATURE = "http://xml.org/sax/features/namespaces"; + public static final String EMPTYSTRING = ""; + public static final String XML_PREFIX = "xml"; + public static final String XMLNS_PREFIX = "xmlns"; + public static final String XMLNS_STRING = "xmlns:"; + public static final String XMLNS_URI = "http://www.w3.org/2000/xmlns/"; } diff --git a/src/org/apache/xalan/xsltc/runtime/DefaultSAXOutputHandler.java b/src/org/apache/xalan/xsltc/runtime/DefaultSAXOutputHandler.java index 37e3c3e..b3d356f 100644 --- a/src/org/apache/xalan/xsltc/runtime/DefaultSAXOutputHandler.java +++ b/src/org/apache/xalan/xsltc/runtime/DefaultSAXOutputHandler.java @@ -63,6 +63,8 @@ package org.apache.xalan.xsltc.runtime; +import java.util.Vector; + import java.io.IOException; import java.io.Writer; import java.io.FileOutputStream; @@ -122,7 +124,7 @@ public class DefaultSAXOutputHandler implements ContentHandler, LexicalHandler { private int _indentLevel = 0; // This is used for aggregating namespace declarations - private AttributeList _namespaceDeclarations = new AttributeList(); + private Vector _namespaceDecls = null; /** * Constructor - set Writer to send output to and output encoding @@ -239,7 +241,8 @@ public class DefaultSAXOutputHandler implements ContentHandler, LexicalHandler { /** * SAX2: Receive notification of the beginning of a document. */ - public void startDocument() throws SAXException { } + public void startDocument() throws SAXException { + } /** * SAX2: Receive notification of the end of an element. @@ -266,7 +269,7 @@ public class DefaultSAXOutputHandler implements ContentHandler, LexicalHandler { if (_startTagOpen) closeStartTag(true); // Close any open element. _element = elementName; // Save element name - // Handle indentation (not a requirement) + // Handle inden3dcb50483dcb504tation (not a requirement) if (_indent) { if (!_emptyElements.containsKey(elementName.toLowerCase())) { indent(_lineFeedNextStartTag); @@ -283,24 +286,26 @@ public class DefaultSAXOutputHandler implements ContentHandler, LexicalHandler { _indentNextEndTag = false; // Output namespace declarations first... - int declCount = _namespaceDeclarations.getLength(); - for (int i=0; i<declCount; i++) { - final String prefix = _namespaceDeclarations.getQName(i); - _writer.write(XMLNS); - if ((prefix != null) && (prefix != EMPTYSTRING)) { - _writer.write(':'); - _writer.write(prefix); + if (_namespaceDecls != null) { + int nDecls = _namespaceDecls.size(); + for (int i = 0; i < nDecls; i++) { + final String prefix = (String) _namespaceDecls.elementAt(i++); + _writer.write(XMLNS); + if ((prefix != null) && (prefix != EMPTYSTRING)) { + _writer.write(':'); + _writer.write(prefix); + } + _writer.write('='); + _writer.write('\"'); + _writer.write((String) _namespaceDecls.elementAt(i)); + _writer.write('\"'); } - _writer.write('='); - _writer.write('\"'); - _writer.write(_namespaceDeclarations.getValue(i)); - _writer.write('\"'); - } - _namespaceDeclarations.clear(); + _namespaceDecls.clear(); + } // ...then output all attributes int attrCount = attrs.getLength(); - for (int i=0; i<attrCount; i++) { + for (int i = 0; i < attrCount; i++) { _writer.write(' '); _writer.write(attrs.getQName(i)); _writer.write('='); @@ -440,7 +445,11 @@ public class DefaultSAXOutputHandler implements ContentHandler, LexicalHandler { * Namespace declarations are output in startElement() */ public void startPrefixMapping(String prefix, String uri) { - _namespaceDeclarations.add(prefix,uri); + if (_namespaceDecls == null) { + _namespaceDecls = new Vector(2); + } + _namespaceDecls.addElement(prefix); + _namespaceDecls.addElement(uri); } /** diff --git a/src/org/apache/xalan/xsltc/runtime/SAXAdapter.java b/src/org/apache/xalan/xsltc/runtime/SAXAdapter.java index ae0e891..8642def 100644 --- a/src/org/apache/xalan/xsltc/runtime/SAXAdapter.java +++ b/src/org/apache/xalan/xsltc/runtime/SAXAdapter.java @@ -65,37 +65,32 @@ package org.apache.xalan.xsltc.runtime; import org.xml.sax.*; -import org.xml.sax.ext.LexicalHandler; -import org.apache.xalan.xsltc.*; +import org.xml.sax.ext.*; +import org.apache.xalan.xsltc.TransletException; +import org.apache.xalan.xsltc.TransletOutputHandler; +import org.apache.xalan.xsltc.dom.DOMBuilder; public final class SAXAdapter implements TransletOutputHandler { - private final ContentHandler _saxHandler; - private final LexicalHandler _lexHandler; + private final DOMBuilder _domBuilder; private final AttributeList _attributes = new AttributeList(); private String _openElementName; - public SAXAdapter(ContentHandler saxHandler) { - _saxHandler = saxHandler; - _lexHandler = null; - } - - public SAXAdapter(ContentHandler saxHandler, LexicalHandler lexHandler) { - _saxHandler = saxHandler; - _lexHandler = lexHandler; + public SAXAdapter(DOMBuilder domBuilder) { + _domBuilder = domBuilder; } private void maybeEmitStartElement() throws SAXException { if (_openElementName != null) { - _saxHandler.startElement(null, null, _openElementName, _attributes); + _domBuilder.startElement(null, null, _openElementName, _attributes); _openElementName = null; } } public void startDocument() throws TransletException { try { - _saxHandler.startDocument(); + _domBuilder.startDocument(); } catch (SAXException e) { throw new TransletException(e); @@ -104,7 +99,7 @@ public final class SAXAdapter implements TransletOutputHandler { public void endDocument() throws TransletException { try { - _saxHandler.endDocument(); + _domBuilder.endDocument(); } catch (SAXException e) { throw new TransletException(e); @@ -115,7 +110,7 @@ public final class SAXAdapter implements TransletOutputHandler { throws TransletException { try { maybeEmitStartElement(); - _saxHandler.characters(characters, offset, length); + _domBuilder.characters(characters, offset, length); } catch (SAXException e) { throw new TransletException(e); @@ -136,7 +131,7 @@ public final class SAXAdapter implements TransletOutputHandler { public void endElement(String elementName) throws TransletException { try { maybeEmitStartElement(); - _saxHandler.endElement(null, null, elementName); + _domBuilder.endElement(null, null, elementName); } catch (SAXException e) { throw new TransletException(e); @@ -161,9 +156,9 @@ public final class SAXAdapter implements TransletOutputHandler { public void comment(String comment) throws TransletException { try { maybeEmitStartElement(); - if (_lexHandler != null) { + if (_domBuilder != null) { char[] chars = comment.toCharArray(); - _lexHandler.comment(chars, 0, chars.length); + _domBuilder.comment(chars, 0, chars.length); } } catch (SAXException e) { @@ -175,13 +170,17 @@ public final class SAXAdapter implements TransletOutputHandler { throws TransletException { try { maybeEmitStartElement(); - _saxHandler.processingInstruction(target, data); + _domBuilder.processingInstruction(target, data); } catch (SAXException e) { throw new TransletException(e); } } + public boolean setEscaping(boolean escape) throws TransletException { + return _domBuilder.setEscaping(escape); + } + // The SAX handler does not handle these: public void setType(int type) {} public void setHeader(String header) {} @@ -189,8 +188,5 @@ public final class SAXAdapter implements TransletOutputHandler { public void omitHeader(boolean value) {} public void setCdataElements(Hashtable elements) { } public void close() {} - public boolean setEscaping(boolean escape) throws TransletException { - return(true); - } public String getPrefix(String uri) { return(""); } } diff --git a/src/org/apache/xalan/xsltc/runtime/StringValueHandler.java b/src/org/apache/xalan/xsltc/runtime/StringValueHandler.java index 2e47eb4..cd0f76e 100644 --- a/src/org/apache/xalan/xsltc/runtime/StringValueHandler.java +++ b/src/org/apache/xalan/xsltc/runtime/StringValueHandler.java @@ -86,4 +86,29 @@ public final class StringValueHandler extends TransletOutputBase { _free = 0; // getValue resets return new String(_buffer, 0, length); } + + /** + * The value of a PI must not contain the substring "?>". Should + * that substring be present, replace it by "? >". + */ + public String getValueOfPI() { + final String value = getValue(); + + if (value.indexOf("?>") > 0) { + final int n = value.length(); + final StringBuffer valueOfPI = new StringBuffer(); + + for (int i = 0; i < n;) { + final char ch = value.charAt(i++); + if (ch == '?' && value.charAt(i) == '>') { + valueOfPI.append("? >"); i++; + } + else { + valueOfPI.append(ch); + } + } + return valueOfPI.toString(); + } + return value; + } } diff --git a/src/org/apache/xalan/xsltc/runtime/TextOutput.java b/src/org/apache/xalan/xsltc/runtime/TextOutput.java index fd29db7..4e7a27e 100644 --- a/src/org/apache/xalan/xsltc/runtime/TextOutput.java +++ b/src/org/apache/xalan/xsltc/runtime/TextOutput.java @@ -72,10 +72,11 @@ import java.util.Enumeration; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.helpers.AttributesImpl; import org.apache.xalan.xsltc.*; -public final class TextOutput implements TransletOutputHandler { +public final class TextOutput implements TransletOutputHandler, Constants { // These are the various output types we handle public static final int UNKNOWN = 0; // determine type from output contents @@ -100,8 +101,6 @@ public final class TextOutput implements TransletOutputHandler { // Contains all elements that should be output as CDATA sections private Hashtable _cdata = null; - private static final String XML_PREFIX = "xml"; - private static final char[] AMP = "&".toCharArray(); private static final char[] LT = "<".toCharArray(); private static final char[] GT = ">".toCharArray(); @@ -124,15 +123,15 @@ public final class TextOutput implements TransletOutputHandler { private static final int BEGCOMM_length = BEGCOMM.length; private static final int ENDCOMM_length = ENDCOMM.length; - private static final String EMPTYSTRING = ""; private static final String HREF_STR = "href"; - private static final String SRC_STR = "str"; + private static final String CITE_STR = "cite"; + private static final String SRC_STR = "src"; private static final String CHAR_ESC_START = "&#"; private static final String CDATA_ESC_START = "]]>&#"; private static final String CDATA_ESC_END = ";<![CDATA["; - private AttributeList _attributes = new AttributeList(); - private String _elementName = null; + private AttributesImpl _attributes = new AttributesImpl(); + private String _elementName = null; // Each entry (prefix) in this hashtable points to a Stack of URIs private Hashtable _namespaces; @@ -252,8 +251,8 @@ public final class TextOutput implements TransletOutputHandler { AttributeList attrs = new AttributeList(); attrs.add("http-equiv", "Content-Type"); attrs.add("content", _mediaType+"; charset="+_encoding); - _saxHandler.startElement(null, null, "meta", attrs); - _saxHandler.endElement(null, null, "meta"); + _saxHandler.startElement(EMPTYSTRING, EMPTYSTRING, "meta", attrs); + _saxHandler.endElement(EMPTYSTRING, EMPTYSTRING, "meta"); } } @@ -264,27 +263,10 @@ public final class TextOutput implements TransletOutputHandler { public void closeStartTag() throws TransletException { try { _startTagOpen = false; - - // Final check to assure that the element is within a namespace - // that has been declared (all declarations for this element - // should have been processed at this point). - int col = _elementName.lastIndexOf(':'); - if (col > 0) { - final String prefix = _elementName.substring(0,col); - final String localname = _elementName.substring(col+1); - final String uri = lookupNamespace(prefix); - if (uri == null) - BasisLibrary.runTimeError(BasisLibrary.NAMESPACE_PREFIX_ERR, - prefix); - if (uri.equals(EMPTYSTRING)) _elementName = localname; - _saxHandler.startElement(uri, localname, - _elementName, _attributes); - } - else { - final String uri = lookupNamespace(EMPTYSTRING); - _saxHandler.startElement(uri, _elementName, - _elementName, _attributes); - } + + // Now is time to send the startElement event + _saxHandler.startElement(getNamespaceURI(_elementName, true), + getLocalName(_elementName), _elementName, _attributes); // Insert <META> tag directly after <HEAD> element in HTML output if (_headTagOpen) { @@ -467,9 +449,7 @@ public final class TextOutput implements TransletOutputHandler { * Start an element in the output document. This might be an XML * element (<elem>data</elem> type) or a CDATA section. */ - public void startElement(String elementName) - throws TransletException { - + public void startElement(String elementName) throws TransletException { try { switch(_outputType) { @@ -670,6 +650,14 @@ public final class TextOutput implements TransletOutputHandler { return(buf.toString()); } + private String makeHHString(int i) { + String s = Integer.toHexString(i).toUpperCase(); + if (s.length() == 1) { + s = "0"+s; + } + return s; + } + /** * This method escapes special characters used in HTML attribute values */ @@ -681,9 +669,17 @@ public final class TextOutput implements TransletOutputHandler { char[] ch = base.toCharArray(); StringBuffer buf = new StringBuffer(); for(int i=0; i<base.length(); i++){ - if (ch[i] > '\u007F') { - buf.append('%'); - buf.append(Integer.toHexString((int)ch[i])); + if (ch[i] <= 0x20) { + buf.append('%'); + buf.append(makeHHString(ch[i])); + } + else if (ch[i] > '\u007F') { + int high = (ch[i] >> 6) | 0xC0; + int low = (ch[i] & 0x3F) | 0x80; // First 6 bits + high bit + buf.append('%'); + buf.append(makeHHString(high)); + buf.append('%'); + buf.append(makeHHString(low)); } else { // These chars are reserved or unsafe in URLs @@ -705,7 +701,8 @@ public final class TextOutput implements TransletOutputHandler { buf.append(Integer.toHexString((int)ch[i])); break; case '\u0026' : - buf.append("&"); + //bug fix for customer/murphy3: buf.append("&"); + buf.append("&"); break; default: buf.append(ch[i]); break; @@ -758,27 +755,51 @@ public final class TextOutput implements TransletOutputHandler { return base; } - private String expandAttribute(String qname) throws TransletException { - // If this attribute was created using an <xsl:attribute> - // element with a 'namespace' attribute and a 'name' attribute - // containing an AVT, then we might get an attribute name on - // a strange format like 'prefix1:prefix2:localpart', where - // prefix1 is from the AVT and prefix2 from the namespace. - final int endcol = qname.lastIndexOf(':'); - if (endcol > 0) { - final int startcol = qname.indexOf(':'); - final String localname = qname.substring(endcol+1); - final String prefix = qname.substring(0,startcol); - final String uri = lookupNamespace(prefix); - if (uri == null) + /** + * Returns the URI of an element or attribute. Note that default namespaces + * do not apply directly to attributes. + */ + private String getNamespaceURI(String qname, boolean isElement) + throws TransletException + { + String uri = EMPTYSTRING; + int col = qname.lastIndexOf(':'); + final String prefix = (col > 0) ? qname.substring(0, col) : EMPTYSTRING; + + if (prefix != EMPTYSTRING || isElement) { + uri = lookupNamespace(prefix); + if (uri == null && !prefix.equals(XMLNS_PREFIX)) { BasisLibrary.runTimeError(BasisLibrary.NAMESPACE_PREFIX_ERR, - prefix); - // Omit prefix (use default) if the namespace URI is null - if (uri.equals(EMPTYSTRING)) - return(localname); - // Construct new QName if we've got two alt. prefixes - else if (endcol != startcol) - return(prefix+':'+localname); + qname.substring(0, col)); + } + } + return uri; + } + + /** + * Returns the local name of a qualified name. If the name has no prefix + * then return null. + */ + private static String getLocalName(String qname) throws TransletException { + final int col = qname.lastIndexOf(':'); + return (col > 0) ? qname.substring(col + 1) : null; + } + + /** + * TODO: This method is a HACK! Since XSLTC does not have access to the + * XML file, it sometimes generates a NS prefix of the form "ns?" for + * an attribute. If at runtime, when the qname of the attribute is + * known, another prefix is specified for the attribute, then we can get + * a qname of the form "ns?:otherprefix:name". This function patches the + * qname by simply ignoring "otherprefix". + */ + private static String patchQName(String qname) throws TransletException { + final int lastColon = qname.lastIndexOf(':'); + if (lastColon > 0) { + final int firstColon = qname.indexOf(':'); + if (firstColon != lastColon) { + return qname.substring(0, firstColon) + qname.substring(lastColon); + } } return qname; } @@ -790,59 +811,110 @@ public final class TextOutput implements TransletOutputHandler { public void attribute(String name, final String value) throws TransletException { + if (_outputType == TEXT) return; + + final String patchedName = patchQName(name); + final String localName = getLocalName(patchedName); + final String uri = getNamespaceURI(patchedName, false); + final int index = (localName == null) ? + _attributes.getIndex(name) : /* don't use patchedName */ + _attributes.getIndex(uri, localName); + switch(_outputType) { - case TEXT: - // Do not output attributes if output mode is 'text' - return; case XML: - if (!_startTagOpen) - BasisLibrary.runTimeError(BasisLibrary.STRAY_ATTRIBUTE_ERR,name); - // Attributes whose names start with XML need special handling - if (name.startsWith("xml")) { - // Output as namespace declaration - if (name.startsWith("xmlns")) { - if (name.length() == 5) - namespace(EMPTYSTRING, value); - else - namespace(name.substring(6),value); - return; - } - // Output as xml:<blah> attribute - _attributes.add(name, value); + if (!_startTagOpen) { + BasisLibrary.runTimeError(BasisLibrary.STRAY_ATTRIBUTE_ERR, patchedName); + } + +/* +System.err.println("TextOutput.attribute() uri = " + uri + + " localname = " + localName + + " qname = " + name + + "\n value = " + value + + " escapeString(value) = " + escapeString(value)); +*/ + + // Output as namespace declaration + if (name.startsWith(XMLNS_PREFIX)) { + namespace(name.length() > 6 ? name.substring(6) : EMPTYSTRING, value); } else { - // Output as regular attribute - _attributes.add(expandAttribute(name), escapeString(value)); + if (index >= 0) { // Duplicate attribute? + _attributes.setAttribute(index, uri, localName, patchedName, "CDATA", + escapeString(value)); + } + else { + _attributes.addAttribute(uri, localName, patchedName, "CDATA", + escapeString(value)); + } } - return; + break; case HTML: - if (!_startTagOpen) + if (!_startTagOpen) { BasisLibrary.runTimeError(BasisLibrary.STRAY_ATTRIBUTE_ERR,name); - // The following is an attempt to escape an URL stored in a href - // attribute of HTML output. Normally URLs should be encoded at - // the time they are created, since escaping or unescaping a - // completed URI might change its semantics. We limit or escaping - // to include space characters only - and nothing else. This is for - // two reasons: (1) performance and (2) we want to make sure that - // we do not change the meaning of the URL. - - // URL-encode href attributes in HTML output + } + + /* + * The following is an attempt to escape an URL stored in a href + * attribute of HTML output. Normally URLs should be encoded at + * the time they are created, since escaping or unescaping a + * completed URI might change its semantics. We limit or escaping + * to include space characters only - and nothing else. This is for + * two reasons: (1) performance and (2) we want to make sure that + * we do not change the meaning of the URL. + */ final String tmp = name.toLowerCase(); - if (tmp.equals(HREF_STR) || tmp.equals(SRC_STR)) { - _attributes.add(name,quickAndDirtyUrlEncode(escapeAttr(value))); + if (tmp.equals(HREF_STR) || tmp.equals(SRC_STR) || tmp.equals(CITE_STR)) { + if (index >= 0) { + _attributes.setAttribute(index, EMPTYSTRING, EMPTYSTRING, name, + "CDATA", quickAndDirtyUrlEncode(escapeAttr(value))); + } + else { + _attributes.addAttribute(EMPTYSTRING, EMPTYSTRING, name, "CDATA", + quickAndDirtyUrlEncode(escapeAttr(value))); + } } else { - _attributes.add(expandAttribute(name), escapeAttr(value)); + if (index >= 0) { + _attributes.setAttribute(index, EMPTYSTRING, EMPTYSTRING, + name, "CDATA", escapeNonURLAttr(value)); + } + else { + _attributes.addAttribute(EMPTYSTRING, EMPTYSTRING, + name, "CDATA", escapeNonURLAttr(value)); + } } - return; + break; } } /** + * Escape non ASCII characters (> u007F) as &#XXX; entities. + */ + private String escapeNonURLAttr(String base) { + final int len = base.length() - 1; + + char[] ch = base.toCharArray(); + StringBuffer buf = new StringBuffer(); + for(int i=0; i<base.length(); i++){ + if (ch[i] > '\u007F') { + buf.append(CHAR_ESC_START); + buf.append(Integer.toString((int)ch[i])); + buf.append(';'); + } + else { + buf.append(ch[i]); + } + } + base = buf.toString(); + return base; + } + + + /** * End an element or CDATA section in the output document */ public void endElement(String elementName) throws TransletException { - try { switch(_outputType) { case TEXT: @@ -853,7 +925,10 @@ public final class TextOutput implements TransletOutputHandler { if (_startTagOpen) closeStartTag(); if (_cdataTagOpen) closeCDATA(); - _saxHandler.endElement(null, null, (String)(_qnameStack.pop())); + final String qname = (String) _qnameStack.pop(); + _saxHandler.endElement(getNamespaceURI(qname, true), + getLocalName(qname), qname); + popNamespaces(); if (((Integer)_cdataStack.peek()).intValue() == _depth) _cdataStack.pop(); @@ -862,7 +937,8 @@ public final class TextOutput implements TransletOutputHandler { case HTML: // Close any open element if (_startTagOpen) closeStartTag(); - _saxHandler.endElement(null, null, (String)(_qnameStack.pop())); + _saxHandler.endElement(EMPTYSTRING, EMPTYSTRING, + (String)(_qnameStack.pop())); popNamespaces(); _depth--; return; @@ -929,10 +1005,15 @@ public final class TextOutput implements TransletOutputHandler { _prefixStack = new Stack(); // Define the default namespace (initially maps to "" uri) - Stack stack = new Stack(); - _namespaces.put(EMPTYSTRING, stack); + Stack stack; + _namespaces.put(EMPTYSTRING, stack = new Stack()); stack.push(EMPTYSTRING); _prefixStack.push(EMPTYSTRING); + + _namespaces.put(XML_PREFIX, stack = new Stack()); + stack.push("http://www.w3.org/XML/1998/namespace"); + _prefixStack.push(XML_PREFIX); + _nodeStack.push(new Integer(-1)); _depth = 0; } @@ -941,9 +1022,9 @@ public final class TextOutput implements TransletOutputHandler { * Declare a prefix to point to a namespace URI */ private void pushNamespace(String prefix, String uri) throws SAXException { - + // Prefixes "xml" and "xmlns" cannot be redefined if (prefix.equals(XML_PREFIX)) return; - + Stack stack; // Get the stack that contains URIs for the specified prefix if ((stack = (Stack)_namespaces.get(prefix)) == null) { @@ -958,15 +1039,15 @@ public final class TextOutput implements TransletOutputHandler { _prefixStack.push(prefix); _nodeStack.push(new Integer(_depth)); - if ((!prefix.equals(EMPTYSTRING)) && (uri.equals(EMPTYSTRING))) return; - _saxHandler.startPrefixMapping(prefix, uri); + // Inform the SAX handler + _saxHandler.startPrefixMapping(prefix, escapeString(uri)); } /** * Undeclare the namespace that is currently pointed to by a given prefix */ private void popNamespace(String prefix) throws SAXException { - + // Prefixes "xml" and "xmlns" cannot be redefined if (prefix.equals(XML_PREFIX)) return; Stack stack; diff --git a/src/org/apache/xalan/xsltc/runtime/TransletLoader.java b/src/org/apache/xalan/xsltc/runtime/TransletLoader.java index 1974afa..faa8861 100644 --- a/src/org/apache/xalan/xsltc/runtime/TransletLoader.java +++ b/src/org/apache/xalan/xsltc/runtime/TransletLoader.java @@ -57,6 +57,7 @@ * <http://www.apache.org/>. * * @author Morten Jorgensen + * @author Santiago Pericas-Geertsen * */ @@ -64,6 +65,9 @@ package org.apache.xalan.xsltc.runtime; import java.lang.Class; import java.lang.ClassLoader; +import java.lang.Thread; + +import java.net.*; // temporary /** * This class is intended used when the default Class.forName() method fails. @@ -91,14 +95,14 @@ final public class TransletLoader { * Get a handle to the system class loader */ public TransletLoader() { - // Get the default class loader - ClassLoader loader = this.getClass().getClassLoader(); - // If this is the extensions class loader we need to get the - // default system class loader instead. This is permitted if - // this class was loaded by the extensions class loader. - String loaderName = loader.getClass().getName(); - if (loaderName.equals("sun.misc.Launcher$ExtClassLoader")) + // Get the loader for the current thread (not the current class) + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + + // Avoid using the extensions class loader (see comment above) + final String loaderName = loader.getClass().getName(); + if (loaderName.equals("sun.misc.Launcher$ExtClassLoader")) { loader = ClassLoader.getSystemClassLoader(); + } _loader = loader; } @@ -108,6 +112,7 @@ final public class TransletLoader { public Class loadClass(String name) throws ClassNotFoundException { return(Class.forName(name, false, _loader)); } + /** * Loads a Class definition and runs static initializers. */ diff --git a/src/org/apache/xalan/xsltc/trax/DOM2SAX.java b/src/org/apache/xalan/xsltc/trax/DOM2SAX.java index af2ddb7..4f3af59 100644 --- a/src/org/apache/xalan/xsltc/trax/DOM2SAX.java +++ b/src/org/apache/xalan/xsltc/trax/DOM2SAX.java @@ -63,6 +63,10 @@ package org.apache.xalan.xsltc.trax; +import java.util.Stack; +import java.util.Vector; +import java.util.Hashtable; + import org.xml.sax.XMLReader; import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; @@ -74,6 +78,9 @@ import org.xml.sax.SAXNotRecognizedException; import org.xml.sax.SAXNotSupportedException; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.AttributeList; +import org.xml.sax.helpers.AttributeListImpl; + import org.w3c.dom.Node; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; @@ -81,49 +88,110 @@ import java.io.IOException; import org.w3c.dom.Entity; import org.w3c.dom.Notation; -import org.apache.xalan.xsltc.runtime.AttributeList; +// import org.apache.xalan.xsltc.runtime.AttributeList; + +class DOM2SAX implements XMLReader, Locator { -class DOM2SAX implements XMLReader , Locator { + private final static String EMPTYSTRING = ""; + private static final String XMLNS_PREFIX = "xmlns"; - private Document _dom = null; + private Node _dom = null; private ContentHandler _sax = null; - + private Hashtable _nsPrefixes = new Hashtable(); + public DOM2SAX(Node root) { - _dom = (Document)root; + _dom = root; } public ContentHandler getContentHandler() { return _sax; } - public DTDHandler getDTDHandler() { - return null; + public void setContentHandler(ContentHandler handler) throws + NullPointerException + { + if (handler == null) throw new NullPointerException(); + _sax = handler; } - public ErrorHandler getErrorHandler() { - return null; + /** + * Begin the scope of namespace prefix. Forward the event to the + * SAX handler only if the prefix is unknown or it is mapped to a + * different URI. + */ + private boolean startPrefixMapping(String prefix, String uri) + throws SAXException + { + boolean pushed = true; + Stack uriStack = (Stack) _nsPrefixes.get(prefix); + + if (uriStack != null) { + if (uriStack.isEmpty()) { + _sax.startPrefixMapping(prefix, uri); + uriStack.push(uri); + } + else { + final String lastUri = (String) uriStack.peek(); + if (!lastUri.equals(uri)) { + _sax.startPrefixMapping(prefix, uri); + uriStack.push(uri); + } + else { + pushed = false; + } + } + } + else { + _sax.startPrefixMapping(prefix, uri); + _nsPrefixes.put(prefix, uriStack = new Stack()); + uriStack.push(uri); + } + return pushed; } - public boolean getFeature(String name) throws SAXNotRecognizedException, - SAXNotSupportedException + /* + * End the scope of a name prefix by popping it from the stack and + * passing the event to the SAX Handler. + */ + private void endPrefixMapping(String prefix) + throws SAXException { - return false; + final Stack uriStack = (Stack) _nsPrefixes.get(prefix); + + if (uriStack != null) { + _sax.endPrefixMapping(prefix); + uriStack.pop(); + } } - public void setFeature(String name, boolean value) throws - SAXNotRecognizedException, SAXNotSupportedException - { - + /** + * If the DOM was created using a DOM 1.0 API, the local name may be + * null. If so, get the local name from the qualified name before + * generating the SAX event. + */ + private static String getLocalName(Node node) { + final String localName = node.getLocalName(); + + if (localName == null) { + final String qname = node.getNodeName(); + final int col = qname.lastIndexOf(':'); + return (col > 0) ? qname.substring(col + 1) : qname; + } + return localName; } public void parse(InputSource unused) throws IOException, SAXException { - Node currNode = _dom; - parse(currNode); + parse(_dom); } + /** + * Traverse the DOM and generate SAX events for a handler. A + * startElement() event passes all attributes, including namespace + * declarations. + */ private void parse(Node node) throws IOException, SAXException { Node first = null; - if (node == null ) return; + if (node == null) return; switch (node.getNodeType()) { case Node.ATTRIBUTE_NODE: // handled by ELEMENT_NODE @@ -139,6 +207,7 @@ class DOM2SAX implements XMLReader , Locator { case Node.DOCUMENT_NODE: _sax.setDocumentLocator(this); + _sax.startDocument(); Node next = node.getFirstChild(); while (next != null) { @@ -149,29 +218,85 @@ class DOM2SAX implements XMLReader , Locator { break; case Node.ELEMENT_NODE: - // Gather all attribute node of the element - AttributeList attrs = new AttributeList(); - NamedNodeMap map = node.getAttributes(); - int length = map.getLength(); - for (int i=0; i<length; i++ ) { - Node attr = map.item(i); - attrs.add(attr.getNodeName(), attr.getNodeValue()); + String prefix; + Vector pushedPrefixes = new Vector(); + final AttributesImpl attrs = new AttributesImpl(); + final NamedNodeMap map = node.getAttributes(); + final int length = map.getLength(); + + // Process all namespace declarations + for (int i = 0; i < length; i++) { + final Node attr = map.item(i); + final String qnameAttr = attr.getNodeName(); + + // Ignore everything but NS declarations here + if (qnameAttr.startsWith(XMLNS_PREFIX)) { + final String uriAttr = attr.getNodeValue(); + final int colon = qnameAttr.lastIndexOf(':'); + prefix = (colon > 0) ? qnameAttr.substring(colon + 1) : EMPTYSTRING; + if (startPrefixMapping(prefix, uriAttr)) { + pushedPrefixes.addElement(prefix); + } + } + } + + // Process all other attributes + for (int i = 0; i < length; i++) { + final Node attr = map.item(i); + final String qnameAttr = attr.getNodeName(); + + // Ignore NS declarations here + if (!qnameAttr.startsWith(XMLNS_PREFIX)) { + final String uriAttr = attr.getNamespaceURI(); + final String localNameAttr = getLocalName(attr); + + // Uri may be implicitly declared + if (uriAttr != null) { + final int colon = qnameAttr.lastIndexOf(':'); + prefix = (colon > 0) ? qnameAttr.substring(0, colon) : EMPTYSTRING; + if (startPrefixMapping(prefix, uriAttr)) { + pushedPrefixes.addElement(prefix); + } + } + + // Add attribute to list + attrs.addAttribute(attr.getNamespaceURI(), getLocalName(attr), + qnameAttr, "CDATA", attr.getNodeValue()); + } + } + + // Now process the element itself + final String qname = node.getNodeName(); + final String uri = node.getNamespaceURI(); + final String localName = getLocalName(node); + + // Uri may be implicitly declared + if (uri != null) { + final int colon = qname.lastIndexOf(':'); + prefix = (colon > 0) ? qname.substring(0, colon) : EMPTYSTRING; + if (startPrefixMapping(prefix, uri)) { + pushedPrefixes.addElement(prefix); + } } // Generate SAX event to start element - _sax.startElement(node.getNamespaceURI(), node.getLocalName(), - node.getNodeName(), attrs); + _sax.startElement(uri, localName, qname, attrs); // Traverse all child nodes of the element (if any) next = node.getFirstChild(); - while ( next != null ) { + while (next != null) { parse(next); next = next.getNextSibling(); } // Generate SAX event to close element - _sax.endElement(node.getNamespaceURI(), - node.getLocalName(), node.getNodeName()); + _sax.endElement(uri, localName, qname); + + // Generate endPrefixMapping() for all pushed prefixes + final int nPushedPrefixes = pushedPrefixes.size(); + for (int i = 0; i < nPushedPrefixes; i++) { + endPrefixMapping((String) pushedPrefixes.elementAt(i)); + } break; case Node.PROCESSING_INSTRUCTION_NODE: @@ -186,48 +311,133 @@ class DOM2SAX implements XMLReader , Locator { } } - public void parse(String sysId) throws IOException, SAXException { - throw new IOException("This method is not yet implemented."); + /** + * This class is only used internally so this method should never + * be called. + */ + public DTDHandler getDTDHandler() { + return null; } - public void setContentHandler(ContentHandler handler) throws - NullPointerException + + /** + * This class is only used internally so this method should never + * be called. + */ + public ErrorHandler getErrorHandler() { + return null; + } + + /** + * This class is only used internally so this method should never + * be called. + */ + public boolean getFeature(String name) throws SAXNotRecognizedException, + SAXNotSupportedException { - if (handler == null ) throw new NullPointerException(); - _sax = handler; + return false; + } + + /** + * This class is only used internally so this method should never + * be called. + */ + public void setFeature(String name, boolean value) throws + SAXNotRecognizedException, SAXNotSupportedException + { + } + + /** + * This class is only used internally so this method should never + * be called. + */ + public void parse(String sysId) throws IOException, SAXException { + throw new IOException("This method is not yet implemented."); } + + /** + * This class is only used internally so this method should never + * be called. + */ public void setDTDHandler(DTDHandler handler) throws NullPointerException { - if (handler == null ) throw new NullPointerException(); } + + /** + * This class is only used internally so this method should never + * be called. + */ public void setEntityResolver(EntityResolver resolver) throws NullPointerException { - if (resolver == null ) throw new NullPointerException(); } + + /** + * This class is only used internally so this method should never + * be called. + */ public EntityResolver getEntityResolver() { return null; } + + /** + * This class is only used internally so this method should never + * be called. + */ public void setErrorHandler(ErrorHandler handler) throws NullPointerException { - if (handler == null ) throw new NullPointerException(); } + + /** + * This class is only used internally so this method should never + * be called. + */ public void setProperty(String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException { } + + /** + * This class is only used internally so this method should never + * be called. + */ public Object getProperty(String name) throws SAXNotRecognizedException, SAXNotSupportedException { return null; } - // Locator methods - public int getColumnNumber() { return 0; } - public int getLineNumber() { return 0; } - public String getPublicId() { return null; } - public String getSystemId() { return null; } + /** + * This class is only used internally so this method should never + * be called. + */ + public int getColumnNumber() { + return 0; + } + + /** + * This class is only used internally so this method should never + * be called. + */ + public int getLineNumber() { + return 0; + } + + /** + * This class is only used internally so this method should never + * be called. + */ + public String getPublicId() { + return null; + } + /** + * This class is only used internally so this method should never + * be called. + */ + public String getSystemId() { + return null; + } - // private + // Debugging private String getNodeTypeFromCode(short code) { String retval = null; switch (code) { diff --git a/src/org/apache/xalan/xsltc/trax/SAX2DOM.java b/src/org/apache/xalan/xsltc/trax/SAX2DOM.java index 82177b7..de6da38 100644 --- a/src/org/apache/xalan/xsltc/trax/SAX2DOM.java +++ b/src/org/apache/xalan/xsltc/trax/SAX2DOM.java @@ -57,12 +57,14 @@ * <http://www.apache.org/>. * * @author G. Todd Miller - * */ package org.apache.xalan.xsltc.trax; +import java.util.Stack; +import java.util.Vector; + import org.xml.sax.ContentHandler; import org.xml.sax.Locator; import org.xml.sax.Attributes; @@ -75,164 +77,135 @@ import org.w3c.dom.DOMException; import org.w3c.dom.Element; import org.w3c.dom.Text; import org.w3c.dom.Attr; -import java.util.Stack; +import org.apache.xalan.xsltc.runtime.Constants; -class SAX2DOM implements ContentHandler { +class SAX2DOM implements ContentHandler, Constants { + + private Document _root = null; + private Stack _nodeStk = new Stack(); + private Vector _namespaceDecls = null; - private Document _document = null; - private DocumentBuilder _builder = null; - private Stack _nodeStk = null; - public SAX2DOM() throws ParserConfigurationException { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - _builder = factory.newDocumentBuilder(); - _nodeStk = new Stack(); + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + _root = factory.newDocumentBuilder().newDocument(); + } + + public SAX2DOM(Node root) throws ParserConfigurationException { + if (root != null) { + _root = (Document) root; // TODO: add support for frags and elems + } + else { + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + _root = factory.newDocumentBuilder().newDocument(); + } } public Node getDOM() { - return _document; + return _root; } public void characters(char[] ch, int start, int length) { - Text text = _document.createTextNode(new String(ch, start, length)); - Node last = (Node)_nodeStk.peek(); - last.appendChild(text); + final Node last = (Node)_nodeStk.peek(); + + // No text nodes can be children of root (DOM006 exception) + if (last != _root) { + final String text = new String(ch, start, length); + last.appendChild(_root.createTextNode(text)); + } } public void startDocument() { - _document = _builder.newDocument(); - Element root = (Element)_document.createElement("root"); - _document.appendChild(root); - _nodeStk.push(root); + _nodeStk.push(_root); } public void endDocument() { - //printDOM(); } public void startElement(String namespace, String localName, String qName, - Attributes attrs ) + Attributes attrs) { - // create new element - Element tmp = (Element)_document.createElementNS(namespace, qName); - int nattrs = attrs.getLength(); - for (int i=0; i<nattrs; i++ ) { - String namespaceuri = attrs.getURI(i); - String value = attrs.getValue(i); - String qname = attrs.getQName(i); - if ((namespaceuri == null) || (namespaceuri.equals(""))) - tmp.setAttribute(qname, value); - else - tmp.setAttributeNS(namespaceuri, qname, value); + final Element tmp = (Element)_root.createElementNS(namespace, qName); + + // Add namespace declarations first + if (_namespaceDecls != null) { + final int nDecls = _namespaceDecls.size(); + for (int i = 0; i < nDecls; i++) { + final String prefix = (String) _namespaceDecls.elementAt(i++); + + if (prefix == null || prefix.equals(EMPTYSTRING)) { + tmp.setAttributeNS(XMLNS_URI, XMLNS_PREFIX, + (String) _namespaceDecls.elementAt(i)); + } + else { + tmp.setAttributeNS(XMLNS_URI, XMLNS_STRING + prefix, + (String) _namespaceDecls.elementAt(i)); + } + } + _namespaceDecls.clear(); } - // append this new node onto current stack node + + // Add attributes to element + final int nattrs = attrs.getLength(); + for (int i = 0; i < nattrs; i++) { + if (attrs.getLocalName(i) == null) { + tmp.setAttribute(attrs.getQName(i), attrs.getValue(i)); + } + else { + tmp.setAttributeNS(attrs.getURI(i), attrs.getQName(i), + attrs.getValue(i)); + } + } + + // Append this new node onto current stack node Node last = (Node)_nodeStk.peek(); last.appendChild(tmp); - // push this node onto stack + + // Push this node onto stack _nodeStk.push(tmp); } public void endElement(String namespace, String localName, String qName) { - Node lastActive = (Node)_nodeStk.pop(); + _nodeStk.pop(); } + public void startPrefixMapping(String prefix, String uri) { + if (_namespaceDecls == null) { + _namespaceDecls = new Vector(2); + } + _namespaceDecls.addElement(prefix); + _namespaceDecls.addElement(uri); + } + + public void endPrefixMapping(String prefix) { + // do nothing + } + /** + * This class is only used internally so this method should never + * be called. + */ public void ignorableWhitespace(char[] ch, int start, int length) { } + /** + * This class is only used internally so this method should never + * be called. + */ public void processingInstruction(String target, String data) { } + /** + * This class is only used internally so this method should never + * be called. + */ public void setDocumentLocator(Locator locator) { } + /** + * This class is only used internally so this method should never + * be called. + */ public void skippedEntity(String name) { } - - public void startPrefixMapping(String prefix, String uri) { - } - - public void endPrefixMapping(String prefix) { - } - - - // for debugging - will be removed - private void printDOM() { - System.out.println("SAX2DOM.java:Printing DOM..."); - Node currNode = _document; - while (currNode != null) { - // start of node processing - switch (currNode.getNodeType()) { - case Node.ATTRIBUTE_NODE : - break; - case Node.CDATA_SECTION_NODE : - break; - case Node.COMMENT_NODE : - break; - case Node.DOCUMENT_FRAGMENT_NODE : - break; - case Node.DOCUMENT_NODE : - break; - case Node.DOCUMENT_TYPE_NODE : - break; - case Node.ELEMENT_NODE : - System.out.println("ELEMT NODE " + currNode.getLocalName() +":"); - org.w3c.dom.NamedNodeMap map = currNode.getAttributes(); - int length = map.getLength(); - for (int i=0; i<length; i++ ){ - Node attrNode = map.item(i); - short code = attrNode.getNodeType(); - System.out.println("\tattr:"+attrNode.getNamespaceURI()+ - "," + attrNode.getLocalName() + - "," + attrNode.getNodeName() + - "=" + attrNode.getNodeValue()); - } - break; - case Node.ENTITY_NODE : - org.w3c.dom.Entity edecl = (org.w3c.dom.Entity)currNode; - String name = edecl.getNotationName(); - if ( name != null ) { - System.out.println("ENT NODE: "+currNode.getNodeName()+ - ", "+ edecl.getSystemId()+ "," + name); - } - break; - case Node.ENTITY_REFERENCE_NODE : - break; - case Node.NOTATION_NODE : - break; - case Node.PROCESSING_INSTRUCTION_NODE : - break; - case Node.TEXT_NODE : - String data = currNode.getNodeValue(); - System.out.println("TEXT NODE:" + data); - break; - } - - // move to first child - Node next = currNode.getFirstChild(); - if (next != null) { - currNode = next; - continue; - } - - // no child nodes, walk the tree - while (currNode != null) { - switch (currNode.getNodeType()) { - case Node.DOCUMENT_NODE: - break; - case Node.ELEMENT_NODE: - break; - } - next = currNode.getNextSibling(); - if (next != null ) { - currNode = next; - break; - } - // move up a level - currNode = currNode.getParentNode(); - } - } - } - } diff --git a/src/org/apache/xalan/xsltc/trax/TemplatesHandlerImpl.java b/src/org/apache/xalan/xsltc/trax/TemplatesHandlerImpl.java index 3c8f8f0..0252cc3 100644 --- a/src/org/apache/xalan/xsltc/trax/TemplatesHandlerImpl.java +++ b/src/org/apache/xalan/xsltc/trax/TemplatesHandlerImpl.java @@ -91,8 +91,9 @@ public class TemplatesHandlerImpl extends Parser implements TemplatesHandler { // Create and initialize a stylesheet compiler final XSLTC xsltc = new XSLTC(); super.setXSLTC(xsltc); - xsltc.setParser(this); xsltc.init(); + super.init(); + xsltc.setParser(this); xsltc.setOutputType(XSLTC.BYTEARRAY_OUTPUT); } @@ -126,10 +127,7 @@ public class TemplatesHandlerImpl extends Parser implements TemplatesHandler { * process, or null if no Templates object has been created. */ public Templates getTemplates() { - try { - // Create a placeholder for the translet bytecodes - byte[][] bytecodes = null; final XSLTC xsltc = getXSLTC(); @@ -161,6 +159,7 @@ public class TemplatesHandlerImpl extends Parser implements TemplatesHandler { xsltc.printWarnings(); // Check that the transformation went well before returning + final byte[][] bytecodes = xsltc.getBytecodes(); if (bytecodes == null) { xsltc.printErrors(); return null; diff --git a/src/org/apache/xalan/xsltc/trax/TemplatesImpl.java b/src/org/apache/xalan/xsltc/trax/TemplatesImpl.java index e1c099c..26cde36 100644 --- a/src/org/apache/xalan/xsltc/trax/TemplatesImpl.java +++ b/src/org/apache/xalan/xsltc/trax/TemplatesImpl.java @@ -59,6 +59,7 @@ * @author Morten Jorgensen * @author G. Todd Millerj * @author Jochen Cordes <[email protected]> + * @author Santiago Pericas-Geertsen * */ @@ -176,8 +177,13 @@ public final class TemplatesImpl implements Templates, Serializable { (TransletClassLoader) AccessController.doPrivileged( new PrivilegedAction() { public Object run() { - ClassLoader current = getClass().getClassLoader(); - return new TransletClassLoader(current); + /* + * Get the loader from the current thread instead of + * the class. This is important for translets that load + * external Java classes and run in multi-threaded envs. + */ + return new TransletClassLoader( + Thread.currentThread().getContextClassLoader()); } } ); diff --git a/src/org/apache/xalan/xsltc/trax/TransformerFactoryImpl.java b/src/org/apache/xalan/xsltc/trax/TransformerFactoryImpl.java index 2f2cc9b..a652020 100644 --- a/src/org/apache/xalan/xsltc/trax/TransformerFactoryImpl.java +++ b/src/org/apache/xalan/xsltc/trax/TransformerFactoryImpl.java @@ -527,7 +527,9 @@ public class TransformerFactoryImpl */ public TemplatesHandler newTemplatesHandler() throws TransformerConfigurationException { - return(new TemplatesHandlerImpl()); + final TemplatesHandlerImpl handler = new TemplatesHandlerImpl(); + handler.init(); + return handler; } /** diff --git a/src/org/apache/xalan/xsltc/trax/TransformerImpl.java b/src/org/apache/xalan/xsltc/trax/TransformerImpl.java index 24e66cf..e6eb0ce 100644 --- a/src/org/apache/xalan/xsltc/trax/TransformerImpl.java +++ b/src/org/apache/xalan/xsltc/trax/TransformerImpl.java @@ -211,7 +211,7 @@ public final class TransformerImpl extends Transformer if (handler != null) return handler; } else if (result instanceof DOMResult) { - return (new SAX2DOM()); + return new SAX2DOM(((DOMResult) result).getNode()); } else if (result instanceof StreamResult) { // Get StreamResult @@ -409,8 +409,14 @@ public final class TransformerImpl extends Transformer // Handle DOMSource input else if (source instanceof DOMSource) { final DOMSource domsrc = (DOMSource)source; - final Document tree = (Document)domsrc.getNode(); - final DOM2SAX dom2sax = new DOM2SAX(tree); + final org.w3c.dom.Node node = domsrc.getNode(); + + boolean isComplete = true; + if (node.getNodeType() != org.w3c.dom.Node.DOCUMENT_NODE) { + isComplete = false; + } + + final DOM2SAX dom2sax = new DOM2SAX(node); final InputSource input = null; final String systemId = domsrc.getSystemId(); @@ -425,7 +431,13 @@ public final class TransformerImpl extends Transformer dom2sax.setContentHandler(builder); // Parse the input and build the internal DOM + if (!isComplete) { + builder.startDocument(); + } dom2sax.parse(input); // need this parameter? + if (!isComplete) { + builder.endDocument(); + } dom.setDocumentURI(systemId); } // Handle StreamSource input @@ -708,7 +720,8 @@ public final class TransformerImpl extends Transformer while (names.hasMoreElements()) { // Get the next property name and value String name = (String)names.nextElement(); - String value = (String)properties.get(name); + // bug fix # 6636- contributed by Tim Elcott + String value = (String)properties.getProperty(name); // Pass property value to translet - override previous setting if (name.equals(OutputKeys.ENCODING)) @@ -756,13 +769,14 @@ public final class TransformerImpl extends Transformer private Properties createOutputProperties() { // Level3: Return the default property value + // bug # 6751 fixed by removing setProperty lines for + // OutputKeys.(DOCTYPE_PUBLIC|DOCTYPE_SYSTEM|CDATA_SECTION_ELEMENTS) + // instead of setting them to "" (EMPTY_STRING). Fix contributed + // by Derek Sayeau. Properties third = new Properties(); third.setProperty(OutputKeys.ENCODING, "UTF-8"); third.setProperty(OutputKeys.METHOD, XML_STRING); third.setProperty(OutputKeys.INDENT, NO_STRING); - third.setProperty(OutputKeys.DOCTYPE_PUBLIC, EMPTY_STRING); - third.setProperty(OutputKeys.DOCTYPE_SYSTEM, EMPTY_STRING); - third.setProperty(OutputKeys.CDATA_SECTION_ELEMENTS, EMPTY_STRING); third.setProperty(OutputKeys.MEDIA_TYPE, "text/xml"); third.setProperty(OutputKeys.OMIT_XML_DECLARATION, NO_STRING); third.setProperty(OutputKeys.STANDALONE, NO_STRING); diff --git a/src/trax/trax.properties b/src/trax/trax.properties deleted file mode 100644 index e593c39..0000000 --- a/src/trax/trax.properties +++ /dev/null @@ -1,11 +0,0 @@ -# $Revision$ $Date$ -# -# Note: This properties file is provided for illustrative purposes -# only and is not part of the interface definition. -# This properties file is located in the implementation JAR -# and different implementations will specify different -# implementation classes and output methods. -# - -# The TRaX Stylesheet processor -trax.processor.xslt=org.apache.xalan.processor.StylesheetProcessor --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
