This commit was manufactured by cvs2svn to create tag
'jaxp-ri-1_2_0-fcs-07'.
git-svn-id: https://svn.apache.org/repos/asf/xalan/java/tags/jaxp-ri-1_2_0-fcs-07@336566 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/build.xml b/build.xml
index 0e09c0f..0378c20 100644
--- a/build.xml
+++ b/build.xml
@@ -361,7 +361,19 @@
</javac>
</target>
- <target name="xsltc.jar" depends="xsltc.compile"
+ <target name="xsltc.fcompile"
+ description="Compile just the XSLTC classes w/o JLex, JCUP" >
+ <echo message="Compiling remaining XSLTC classes"/>
+ <javac srcdir="${src.dir}"
+ destdir="${build.classes}"
+ includes="${xsltc.reldir}/**/*.java"
+ debug="${build.debug}">
+ <classpath refid="xsltc.class.path" />
+ <bootclasspath refid="xslt.boot.class.path" />
+ </javac>
+ </target>
+
+ <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 +386,7 @@
</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 +461,14 @@
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/serialize/SerializerToXML.java b/src/org/apache/xalan/serialize/SerializerToXML.java
index f9705d8..5d38068 100644
--- a/src/org/apache/xalan/serialize/SerializerToXML.java
+++ b/src/org/apache/xalan/serialize/SerializerToXML.java
@@ -323,6 +323,9 @@
/** Indicate whether running in Debug mode */
private static final boolean DEBUG = false;
+ /** This flag is set while receiving events from the external DTD */
+ private boolean m_inExternalDTD = false;
+
/**
* Default constructor.
*/
@@ -1864,6 +1867,8 @@
*/
public void startEntity(String name) throws org.xml.sax.SAXException
{
+ if (name.equals("[dtd]"))
+ m_inExternalDTD = true;
m_inEntityRef = true;
}
@@ -1876,7 +1881,9 @@
*/
public void endEntity(String name) throws org.xml.sax.SAXException
{
- m_inEntityRef = false;
+ if (name.equals("[dtd]"))
+ m_inExternalDTD = false;
+ m_inEntityRef = false;
}
/**
@@ -1925,7 +1932,10 @@
*/
public void elementDecl(String name, String model) throws SAXException
{
- try
+ // Do not inline external DTD
+ if (m_inExternalDTD) return;
+
+ try
{
final Writer writer = m_writer;
if (m_inDoctype)
@@ -1975,6 +1985,8 @@
String eName, String aName, String type, String valueDefault, String value)
throws SAXException
{
+ // Do not inline external DTD
+ if (m_inExternalDTD) return;
try
{
@@ -1987,26 +1999,19 @@
m_inDoctype = false;
}
- if (!eName.equals(m_elemName))
- {
- writer.write("<!ATTLIST ");
- writer.write(eName);
- writer.write(" ");
+ writer.write("<!ATTLIST ");
+ writer.write(eName);
+ writer.write(" ");
- m_elemName = eName;
- }
- else
- {
- m_pos -= 3;
-
- writer.write(m_lineSep, 0, m_lineSepLen);
- }
writer.write(aName);
writer.write(" ");
writer.write(type);
- writer.write(" ");
- writer.write(valueDefault);
+ if (valueDefault != null)
+ {
+ writer.write(" ");
+ writer.write(valueDefault);
+ }
//m_writer.write(" ");
//m_writer.write(value);
@@ -2035,6 +2040,8 @@
public void internalEntityDecl(String name, String value)
throws SAXException
{
+ // Do not inline external DTD
+ if (m_inExternalDTD) return;
try
{
diff --git a/src/org/apache/xalan/xsltc/DOM.java b/src/org/apache/xalan/xsltc/DOM.java
index 040e74e..97e1d47 100644
--- a/src/org/apache/xalan/xsltc/DOM.java
+++ b/src/org/apache/xalan/xsltc/DOM.java
@@ -132,4 +132,6 @@
public void setupMapping(String[] names, String[] namespaces);
public boolean isElement(final int node);
public boolean isAttribute(final int node);
+ public String lookupNamespace(int node, String prefix)
+ throws TransletException;
}
diff --git a/src/org/apache/xalan/xsltc/TransletOutputHandler.java b/src/org/apache/xalan/xsltc/TransletOutputHandler.java
index f53fa11..59a5150 100644
--- a/src/org/apache/xalan/xsltc/TransletOutputHandler.java
+++ b/src/org/apache/xalan/xsltc/TransletOutputHandler.java
@@ -73,6 +73,7 @@
public void endDocument() throws TransletException;
public void startElement(String elementName) throws TransletException;
public void endElement(String elementName) throws TransletException;
+ public void characters(String characters) throws TransletException;
public void characters(char[] characters, int offset, int length)
throws TransletException;
public void attribute(String attributeName, String attributeValue)
@@ -86,5 +87,10 @@
public void omitHeader(boolean value);
public boolean setEscaping(boolean escape) throws TransletException;
public void setCdataElements(Hashtable elements);
+ public void setDoctype(String system, String pub);
+ public void setMediaType(String mediaType);
+ public void setStandalone(String standalone);
+ public void setVersion(String version);
public void close();
+
}
diff --git a/src/org/apache/xalan/xsltc/cmdline/Compile.java b/src/org/apache/xalan/xsltc/cmdline/Compile.java
index c7598a2..89d317e 100644
--- a/src/org/apache/xalan/xsltc/cmdline/Compile.java
+++ b/src/org/apache/xalan/xsltc/cmdline/Compile.java
@@ -80,6 +80,12 @@
public final class Compile {
+ // Versioning numbers for the compiler -v option output
+ private static int VERSION_MAJOR = 1;
+ private static int VERSION_MINOR = 1;
+ private static int VERSION_DELTA = 0;
+
+
// This variable should be set to false to prevent any methods in this
// class from calling System.exit(). As this is a command-line tool,
// calling System.exit() is normally OK, but we also want to allow for
@@ -87,7 +93,11 @@
private static boolean _allowExit = true;
public static void printUsage() {
- System.err.println(new ErrorMsg(ErrorMsg.COMPILE_USAGE_STR));
+ StringBuffer vers = new StringBuffer("XSLTC version " +
+ VERSION_MAJOR + "." + VERSION_MINOR +
+ ((VERSION_DELTA > 0) ? ("."+VERSION_DELTA) : ("")));
+ System.err.println(vers + "\n" +
+ new ErrorMsg(ErrorMsg.COMPILE_USAGE_STR));
if (_allowExit) System.exit(-1);
}
@@ -103,8 +113,7 @@
boolean inputIsURL = false;
boolean useStdIn = false;
boolean classNameSet = false;
-
- final GetOpt getopt = new GetOpt(args, "o:d:j:p:uxhsi");
+ final GetOpt getopt = new GetOpt(args, "o:d:j:p:uxhsinv");
if (args.length < 1) printUsage();
final XSLTC xsltc = new XSLTC();
@@ -138,6 +147,11 @@
case 's':
_allowExit = false;
break;
+ case 'n':
+ xsltc.setTemplateInlining(false);
+ break;
+ case 'v':
+ // fall through to case h
case 'h':
default:
printUsage();
diff --git a/src/org/apache/xalan/xsltc/cmdline/Transform.java b/src/org/apache/xalan/xsltc/cmdline/Transform.java
index 55ac4e2..57b6430 100644
--- a/src/org/apache/xalan/xsltc/cmdline/Transform.java
+++ b/src/org/apache/xalan/xsltc/cmdline/Transform.java
@@ -92,8 +92,13 @@
import org.apache.xalan.xsltc.dom.DTDMonitor;
import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
+import org.apache.xalan.xsltc.runtime.output.*;
+
final public class Transform {
+ // Temporary
+ static private boolean _useOldOutputSystem = false;
+
private TransletOutputHandler _handler;
private String _fileName;
@@ -102,15 +107,17 @@
private boolean _isJarFileSpecified = false;
private Vector _params = null;
private boolean _uri, _debug;
+ private int _iterations;
private static boolean _allowExit = true;
public Transform(String className, String fileName,
- boolean uri, boolean debug) {
+ boolean uri, boolean debug, int iterations) {
_fileName = fileName;
_className = className;
_uri = uri;
_debug = debug;
+ _iterations = iterations;
}
public void setParameters(Vector params) {
@@ -196,18 +203,31 @@
}
// Transform the document
- String encoding = _translet._encoding;
+ TransletOutputHandlerFactory tohFactory =
+ TransletOutputHandlerFactory.newInstance();
+ tohFactory.setOutputType(TransletOutputHandlerFactory.STREAM);
+ tohFactory.setEncoding(_translet._encoding);
+ tohFactory.setOutputMethod(_translet._method);
- // Create our default SAX/DTD handler
- DefaultSAXOutputHandler saxHandler =
- new DefaultSAXOutputHandler(System.out, encoding);
- // Create a translet output handler and plug in the SAX/DTD handler
- TextOutput textOutput =
- new TextOutput((ContentHandler)saxHandler,
- (LexicalHandler)saxHandler, encoding);
+ if (_iterations == -1) {
+ translet.transform(dom, _useOldOutputSystem ?
+ tohFactory.getOldTransletOutputHandler() :
+ tohFactory.getTransletOutputHandler());
+ }
+ else if (_iterations > 0) {
+ long mm = System.currentTimeMillis();
+ for (int i = 0; i < _iterations; i++) {
+ translet.transform(dom, _useOldOutputSystem ?
+ tohFactory.getOldTransletOutputHandler() :
+ tohFactory.getTransletOutputHandler());
+ }
+ mm = System.currentTimeMillis() - mm;
- // Transform and pass output to the translet output handler
- translet.transform(dom, textOutput);
+ System.err.println("\n<!--");
+ System.err.println(" transform = " + (mm / _iterations) + " ms");
+ System.err.println(" throughput = " + (1000.0 / (mm / _iterations)) + " tps");
+ System.err.println("-->");
+ }
}
catch (TransletException e) {
if (_debug) e.printStackTrace();
@@ -279,6 +299,7 @@
try {
if (args.length > 0) {
int i;
+ int iterations = -1;
boolean uri = false, debug = false;
boolean isJarFileSpecified = false;
String jarFile = null;
@@ -298,6 +319,17 @@
isJarFileSpecified = true;
jarFile = args[++i];
}
+ else if (args[i].equals("-e")) {
+ _useOldOutputSystem = true;
+ }
+ else if (args[i].equals("-n")) {
+ try {
+ iterations = Integer.parseInt(args[++i]);
+ }
+ catch (NumberFormatException e) {
+ // ignore
+ }
+ }
else {
printUsage();
}
@@ -307,7 +339,8 @@
if (args.length - i < 2) printUsage();
// Get document file and class name
- Transform handler = new Transform(args[i+1],args[i],uri,debug);
+ Transform handler = new Transform(args[i+1], args[i], uri,
+ debug, iterations);
handler.setJarFileInputSrc(isJarFileSpecified, jarFile);
// Parse stylesheet parameters
diff --git a/src/org/apache/xalan/xsltc/compiler/AbsolutePathPattern.java b/src/org/apache/xalan/xsltc/compiler/AbsolutePathPattern.java
index 665b0ad..cf03c43 100644
--- a/src/org/apache/xalan/xsltc/compiler/AbsolutePathPattern.java
+++ b/src/org/apache/xalan/xsltc/compiler/AbsolutePathPattern.java
@@ -123,31 +123,44 @@
else {
_left.translate(classGen, methodGen);
}
- _trueList.append(_left._trueList);
- _falseList.append(_left._falseList);
}
+
final int getParent = cpg.addInterfaceMethodref(DOM_INTF,
GET_PARENT,
GET_PARENT_SIG);
final int getType = cpg.addInterfaceMethodref(DOM_INTF,
"getType", "(I)I");
- il.append(methodGen.loadDOM());
+
+ InstructionHandle begin = il.append(methodGen.loadDOM());
il.append(SWAP);
il.append(new INVOKEINTERFACE(getParent, 2));
- if (_left instanceof AncestorPattern) {
+ if (_left instanceof AncestorPattern) {
il.append(methodGen.loadDOM());
il.append(SWAP);
}
il.append(new INVOKEINTERFACE(getType, 2));
il.append(new PUSH(cpg, DOM.ROOT));
- // long jump: _falseList.add(il.append(new IF_ICMPNE(null)));
final BranchHandle skip = il.append(new IF_ICMPEQ(null));
_falseList.add(il.append(new GOTO_W(null)));
skip.setTarget(il.append(NOP));
+
+ if (_left != null) {
+ _left.backPatchTrueList(begin);
+
+ /*
+ * If _left is an ancestor pattern, backpatch this pattern's false
+ * list to the loop that searches for more ancestors.
+ */
+ if (_left instanceof AncestorPattern) {
+ final AncestorPattern ancestor = (AncestorPattern) _left;
+ _falseList.backPatch(ancestor.getLoopHandle()); // clears list
+ }
+ _falseList.append(_left._falseList);
+ }
}
public String toString() {
- return "absolutePathPattern(" + (_left!=null ? _left.toString() : ")");
+ return "absolutePathPattern(" + (_left != null ? _left.toString() : ")");
}
}
diff --git a/src/org/apache/xalan/xsltc/compiler/AncestorPattern.java b/src/org/apache/xalan/xsltc/compiler/AncestorPattern.java
index f99b678..9fe38ae 100644
--- a/src/org/apache/xalan/xsltc/compiler/AncestorPattern.java
+++ b/src/org/apache/xalan/xsltc/compiler/AncestorPattern.java
@@ -69,8 +69,10 @@
import org.apache.xalan.xsltc.compiler.util.*;
final class AncestorPattern extends RelativePathPattern {
+
private final Pattern _left; // may be null
private final RelativePathPattern _right;
+ private InstructionHandle _loop;
public AncestorPattern(RelativePathPattern right) {
this(null, right);
@@ -84,6 +86,10 @@
}
}
+ public InstructionHandle getLoopHandle() {
+ return _loop;
+ }
+
public void setParser(Parser parser) {
super.setParser(parser);
if (_left != null) {
@@ -106,17 +112,23 @@
}
public Type typeCheck(SymbolTable stable) throws TypeCheckError {
- if (_left != null) _left.typeCheck(stable);
+ if (_left != null) {
+ _left.typeCheck(stable);
+ }
return _right.typeCheck(stable);
}
public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
- InstructionHandle loop, eloop;
+ InstructionHandle parent;
final ConstantPoolGen cpg = classGen.getConstantPool();
final InstructionList il = methodGen.getInstructionList();
+
+ /*
+ * The scope of this local var must be the entire method since
+ * a another pattern may decide to jump back into the loop
+ */
final LocalVariableGen local =
- methodGen.addLocalVariable2("app",
- Util.getJCRefType(NODE_SIG),
+ methodGen.addLocalVariable2("app", Util.getJCRefType(NODE_SIG),
il.getEnd());
final org.apache.bcel.generic.Instruction loadLocal =
@@ -133,13 +145,18 @@
}
else {
_right.translate(classGen, methodGen);
+
+ if (_right instanceof AncestorPattern) {
+ il.append(methodGen.loadDOM());
+ il.append(SWAP);
+ }
}
if (_left != null) {
final int getParent = cpg.addInterfaceMethodref(DOM_INTF,
GET_PARENT,
GET_PARENT_SIG);
- loop = il.append(new INVOKEINTERFACE(getParent, 2));
+ parent = il.append(new INVOKEINTERFACE(getParent, 2));
il.append(DUP);
il.append(storeLocal);
@@ -148,11 +165,10 @@
_left.translate(classGen, methodGen);
-
final SyntaxTreeNode p = getParent();
- if ((p == null) ||
- (p instanceof Instruction) ||
- (p instanceof TopLevelElement)) {
+ if (p == null || p instanceof Instruction ||
+ p instanceof TopLevelElement)
+ {
// do nothing
}
else {
@@ -160,19 +176,27 @@
}
final BranchHandle exit = il.append(new GOTO(null));
- eloop = il.append(methodGen.loadDOM());
+ _loop = il.append(methodGen.loadDOM());
il.append(loadLocal);
- local.setEnd(eloop);
- il.append(new GOTO(loop));
+ local.setEnd(_loop);
+ il.append(new GOTO(parent));
exit.setTarget(il.append(NOP));
- _left.backPatchFalseList(eloop);
+ _left.backPatchFalseList(_loop);
_trueList.append(_left._trueList);
}
else {
il.append(POP2);
}
- methodGen.removeLocalVariable(local);
+
+ /*
+ * If _right is an ancestor pattern, backpatch this pattern's false
+ * list to the loop that searches for more ancestors.
+ */
+ if (_right instanceof AncestorPattern) {
+ final AncestorPattern ancestor = (AncestorPattern) _right;
+ _falseList.backPatch(ancestor.getLoopHandle()); // clears list
+ }
_trueList.append(_right._trueList);
_falseList.append(_right._falseList);
diff --git a/src/org/apache/xalan/xsltc/compiler/ApplyImports.java b/src/org/apache/xalan/xsltc/compiler/ApplyImports.java
index 852b0bc..5d41236 100644
--- a/src/org/apache/xalan/xsltc/compiler/ApplyImports.java
+++ b/src/org/apache/xalan/xsltc/compiler/ApplyImports.java
@@ -136,7 +136,7 @@
// Indicate to the top-level stylesheet that all templates must be
// compiled into separate methods.
Stylesheet stylesheet = getStylesheet();
- stylesheet.compileTemplatesAsMethods();
+ stylesheet.setTemplateInlining(false);
// Get the mode we are currently in (might not be any)
Template template = getTemplate();
diff --git a/src/org/apache/xalan/xsltc/compiler/ApplyTemplates.java b/src/org/apache/xalan/xsltc/compiler/ApplyTemplates.java
index b0143cb..746f0cd 100644
--- a/src/org/apache/xalan/xsltc/compiler/ApplyTemplates.java
+++ b/src/org/apache/xalan/xsltc/compiler/ApplyTemplates.java
@@ -106,7 +106,7 @@
}
if (mode.length() > 0) {
- _modeName = parser.getQName(mode);
+ _modeName = parser.getQNameIgnoreDefaultNs(mode);
}
// instantiate Mode if needed, cache (apply temp) function name
@@ -139,6 +139,7 @@
* 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 @@
translateContents(classGen, methodGen);
}
+
il.append(classGen.loadTranslet());
// The 'select' expression is a result-tree
@@ -192,6 +194,7 @@
NODE_ITERATOR_SIG);
il.append(methodGen.loadCurrentNode());
il.append(new INVOKEINTERFACE(setStartNode,2));
+ setStartNodeCalled = true;
}
else {
if (_select == null)
@@ -201,7 +204,7 @@
}
}
- if (_select != null) {
+ if (_select != null && !setStartNodeCalled) {
_select.startResetIterator(classGen, methodGen);
}
diff --git a/src/org/apache/xalan/xsltc/compiler/AttributeSet.java b/src/org/apache/xalan/xsltc/compiler/AttributeSet.java
index b484604..6bbba08 100644
--- a/src/org/apache/xalan/xsltc/compiler/AttributeSet.java
+++ b/src/org/apache/xalan/xsltc/compiler/AttributeSet.java
@@ -84,6 +84,7 @@
// Element contents
private QName _name;
private UseAttributeSets _useSets;
+ private AttributeSet _mergeSet;
private String _method;
private boolean _ignore = false;
@@ -119,7 +120,7 @@
public void parseContents(Parser parser) {
// Get this attribute set's name
- _name = parser.getQName(getAttribute("name"));
+ _name = parser.getQNameIgnoreDefaultNs(getAttribute("name"));
if ((_name == null) || (_name.equals(EMPTYSTRING))) {
ErrorMsg msg = new ErrorMsg(ErrorMsg.UNNAMED_ATTRIBSET_ERR, this);
parser.reportError(Constants.ERROR, msg);
@@ -161,15 +162,10 @@
if (_ignore) return (Type.Void);
- final AttributeSet other = stable.addAttributeSet(this);
- if (other != null) {
- _method = other.getMethodName();
- merge(other);
- other.ignore();
- }
- else {
- _method = AttributeSetPrefix + getXSLTC().nextAttributeSetSerial();
- }
+ // _mergeSet Point to any previous definition of this attribute set
+ _mergeSet = stable.addAttributeSet(this);
+
+ _method = AttributeSetPrefix + getXSLTC().nextAttributeSetSerial();
if (_useSets != null) _useSets.typeCheck(stable);
typeCheckContents(stable);
@@ -177,26 +173,6 @@
}
/**
- * Merge this attribute set with some other one
- */
- private void merge(AttributeSet other) {
- // Both attribute sets may inherit from other sets...
- if (_useSets == null)
- _useSets = other._useSets;
- else
- _useSets.addAttributeSets(other.getAttribute("use-attribute-sets"));
-
- // Merge the contents of the two attribute sets...
- final Enumeration attributes = other.elements();
- while (attributes.hasMoreElements()) {
- SyntaxTreeNode element = (SyntaxTreeNode)attributes.nextElement();
- if (element instanceof XslAttribute) {
- setFirstElement((XslAttribute)element);
- }
- }
- }
-
- /**
* Compile a method that outputs the attributes in this set
*/
public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
@@ -206,6 +182,21 @@
// Create a new method generator for an attribute set method
methodGen = new AttributeSetMethodGenerator(_method, classGen);
+ // Generate a reference to previous attribute-set definitions with the
+ // same name first. Those later in the stylesheet take precedence.
+ if (_mergeSet != null) {
+ final ConstantPoolGen cpg = classGen.getConstantPool();
+ final InstructionList il = methodGen.getInstructionList();
+ final String methodName = _mergeSet.getMethodName();
+
+ il.append(classGen.loadTranslet());
+ il.append(methodGen.loadHandler());
+ il.append(methodGen.loadIterator());
+ final int method = cpg.addMethodref(classGen.getClassName(),
+ methodName, ATTR_SET_SIG);
+ il.append(new INVOKESPECIAL(method));
+ }
+
// Translate other used attribute sets first, as local attributes
// take precedence (last attributes overrides first)
if (_useSets != null) _useSets.translate(classGen, methodGen);
diff --git a/src/org/apache/xalan/xsltc/compiler/AttributeValue.java b/src/org/apache/xalan/xsltc/compiler/AttributeValue.java
index 64c0340..8f33670 100644
--- a/src/org/apache/xalan/xsltc/compiler/AttributeValue.java
+++ b/src/org/apache/xalan/xsltc/compiler/AttributeValue.java
@@ -71,16 +71,16 @@
AttributeValue result;
if (text.indexOf('{') != -1) {
- result = new AttributeValueTemplate(text, parser);
+ result = new AttributeValueTemplate(text, parser, parent);
}
else if (text.indexOf('}') != -1) {
- result = new AttributeValueTemplate(text, parser);
+ result = new AttributeValueTemplate(text, parser, parent);
}
else {
result = new SimpleAttributeValue(text);
result.setParser(parser);
+ result.setParent(parent);
}
- result.setParent(parent);
return result;
}
}
diff --git a/src/org/apache/xalan/xsltc/compiler/AttributeValueTemplate.java b/src/org/apache/xalan/xsltc/compiler/AttributeValueTemplate.java
index 49f2e20..00d981d 100644
--- a/src/org/apache/xalan/xsltc/compiler/AttributeValueTemplate.java
+++ b/src/org/apache/xalan/xsltc/compiler/AttributeValueTemplate.java
@@ -72,10 +72,14 @@
final class AttributeValueTemplate extends AttributeValue {
- public AttributeValueTemplate(String value, Parser parser) {
+ public AttributeValueTemplate(String value, Parser parser,
+ SyntaxTreeNode parent)
+ {
+ setParent(parent);
setParser(parser);
- if (check(value, parser))
+ if (check(value, parser)) {
parseAVTemplate(0, value, parser);
+ }
}
private void parseAVTemplate(final int start, String text, Parser parser) {
diff --git a/src/org/apache/xalan/xsltc/compiler/CallTemplate.java b/src/org/apache/xalan/xsltc/compiler/CallTemplate.java
index 84b1e4d..00ff83e 100644
--- a/src/org/apache/xalan/xsltc/compiler/CallTemplate.java
+++ b/src/org/apache/xalan/xsltc/compiler/CallTemplate.java
@@ -87,7 +87,7 @@
}
public void parseContents(Parser parser) {
- _name = parser.getQName(getAttribute("name"));
+ _name = parser.getQNameIgnoreDefaultNs(getAttribute("name"));
parseChildren(parser);
}
diff --git a/src/org/apache/xalan/xsltc/compiler/CastExpr.java b/src/org/apache/xalan/xsltc/compiler/CastExpr.java
index cec15f5..8063340 100644
--- a/src/org/apache/xalan/xsltc/compiler/CastExpr.java
+++ b/src/org/apache/xalan/xsltc/compiler/CastExpr.java
@@ -88,25 +88,16 @@
InternalTypeMap.put(Type.Real, Type.Real);
InternalTypeMap.put(Type.Real, Type.Int);
- InternalTypeMap.put(Type.Real, Type.Lng);
InternalTypeMap.put(Type.Real, Type.Boolean);
InternalTypeMap.put(Type.Real, Type.String);
InternalTypeMap.put(Type.Real, Type.Reference);
InternalTypeMap.put(Type.Int, Type.Int);
InternalTypeMap.put(Type.Int, Type.Real);
- InternalTypeMap.put(Type.Int, Type.Lng);
InternalTypeMap.put(Type.Int, Type.Boolean);
InternalTypeMap.put(Type.Int, Type.String);
InternalTypeMap.put(Type.Int, Type.Reference);
- // GTM, bug 3592 fix.
- InternalTypeMap.put(Type.Lng, Type.Int);
- InternalTypeMap.put(Type.Lng, Type.Real);
- InternalTypeMap.put(Type.Lng, Type.Boolean);
- InternalTypeMap.put(Type.Lng, Type.String);
- InternalTypeMap.put(Type.Lng, Type.Reference);
-
InternalTypeMap.put(Type.String, Type.String);
InternalTypeMap.put(Type.String, Type.Boolean);
InternalTypeMap.put(Type.String, Type.Real);
@@ -140,6 +131,7 @@
InternalTypeMap.put(Type.Reference, Type.String);
InternalTypeMap.put(Type.Reference, Type.Node);
InternalTypeMap.put(Type.Reference, Type.NodeSet);
+ InternalTypeMap.put(Type.Reference, Type.ResultTree);
InternalTypeMap.put(Type.Void, Type.String);
}
diff --git a/src/org/apache/xalan/xsltc/compiler/Constants.java b/src/org/apache/xalan/xsltc/compiler/Constants.java
index 6772185..12258b1 100644
--- a/src/org/apache/xalan/xsltc/compiler/Constants.java
+++ b/src/org/apache/xalan/xsltc/compiler/Constants.java
@@ -127,6 +127,8 @@
= org.apache.bcel.Constants.ACC_PRIVATE;
public static final int ACC_PROTECTED
= org.apache.bcel.Constants.ACC_PROTECTED;
+ public static final int ACC_STATIC
+ = org.apache.bcel.Constants.ACC_STATIC;
public static final String STRING_SIG
= "Ljava/lang/String;";
@@ -147,6 +149,8 @@
= "int";
public static final String NODE_ITERATOR
= "org.apache.xalan.xsltc.NodeIterator";
+ public static final String NODE_ITERATOR_BASE
+ = "org.apache.xalan.xsltc.dom.NodeIteratorBase";
public static final String SORT_ITERATOR
= "org.apache.xalan.xsltc.dom.SortingIterator";
public static final String SORT_ITERATOR_SIG
@@ -169,10 +173,6 @@
= "org/apache/xalan/xsltc/TransletOutputHandler";
public static final String OUTPUT_HANDLER_SIG
= "Lorg/apache/xalan/xsltc/TransletOutputHandler;";
- public static final String TEXT_OUTPUT
- = "org/apache/xalan/xsltc/runtime/TextOutput";
- public static final String TEXT_OUTPUT_SIG
- = "Lorg/apache/xalan/xsltc/runtime/TextOutput;";
public static final String FILTER_INTERFACE
= "org.apache.xalan.xsltc.dom.Filter";
public static final String FILTER_INTERFACE_SIG
@@ -286,8 +286,6 @@
= "java.lang.Double";
public static final String INTEGER_CLASS
= "java.lang.Integer";
- public static final String LONG_CLASS
- = "java.lang.Long";
public static final String RUNTIME_NODE_CLASS
= "org.apache.xalan.xsltc.runtime.Node";
public static final String MATH_CLASS
@@ -301,10 +299,6 @@
= "intValue";
public static final String INT_VALUE_SIG
= "()I";
- public static final String LONG_VALUE
- = "longValue";
- public static final String LONG_VALUE_SIG
- = "()J";
public static final String DOUBLE_VALUE
= "doubleValue";
public static final String DOUBLE_VALUE_SIG
@@ -486,6 +480,10 @@
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/DecimalFormatting.java b/src/org/apache/xalan/xsltc/compiler/DecimalFormatting.java
index 874e031..c4fa876 100644
--- a/src/org/apache/xalan/xsltc/compiler/DecimalFormatting.java
+++ b/src/org/apache/xalan/xsltc/compiler/DecimalFormatting.java
@@ -84,7 +84,7 @@
private static final String DFS_CLASS = "java.text.DecimalFormatSymbols";
private static final String DFS_SIG = "Ljava/text/DecimalFormatSymbols;";
- private String _name = null;
+ private QName _name = null;
/**
* No type check needed for the <xsl:decimal-formatting/> element
@@ -98,14 +98,20 @@
*/
public void parseContents(Parser parser) {
// Get the name of these decimal formatting symbols
- if ((_name = getAttribute("name")) == null) _name = EMPTYSTRING;
+ _name = parser.getQNameIgnoreDefaultNs(getAttribute("name"));
+ if (_name == null) {
+ _name = parser.getQNameIgnoreDefaultNs(EMPTYSTRING);
+ }
// Check if a set of symbols has already been registered under this name
SymbolTable stable = parser.getSymbolTable();
- if (stable.getDecimalFormatting(_name) != null)
- reportWarning(this, parser, ErrorMsg.SYMBOLS_REDEF_ERR,_name.toString());
- else
+ if (stable.getDecimalFormatting(_name) != null) {
+ reportWarning(this, parser, ErrorMsg.SYMBOLS_REDEF_ERR,
+ _name.toString());
+ }
+ else {
stable.addDecimalFormatting(_name, this);
+ }
}
/**
@@ -122,7 +128,7 @@
// Push the format name on the stack for call to addDecimalFormat()
il.append(classGen.loadTranslet());
- il.append(new PUSH(cpg, _name));
+ il.append(new PUSH(cpg, _name.toString()));
// Manufacture a DecimalFormatSymbols on the stack
// for call to addDecimalFormat()
diff --git a/src/org/apache/xalan/xsltc/compiler/DocumentCall.java b/src/org/apache/xalan/xsltc/compiler/DocumentCall.java
index 0817a06..8ff7f49 100644
--- a/src/org/apache/xalan/xsltc/compiler/DocumentCall.java
+++ b/src/org/apache/xalan/xsltc/compiler/DocumentCall.java
@@ -120,7 +120,15 @@
// Parse the second argument - the document URI base
if (ac == 2) {
_base = argument(1);
- if (!_base.typeCheck(stable).identicalTo(Type.NodeSet)) {
+ final Type baseType = _base.typeCheck(stable);
+
+ if (baseType.identicalTo(Type.Node)) {
+ _base = new CastExpr(_base, Type.NodeSet);
+ }
+ else if (baseType.identicalTo(Type.NodeSet)) {
+ // falls through
+ }
+ else {
ErrorMsg msg = new ErrorMsg(ErrorMsg.DOCUMENT_ARG_ERR, this);
throw new TypeCheckError(msg);
}
diff --git a/src/org/apache/xalan/xsltc/compiler/ElementAvailableCall.java b/src/org/apache/xalan/xsltc/compiler/ElementAvailableCall.java
index 97e3f3c..55d0e73 100644
--- a/src/org/apache/xalan/xsltc/compiler/ElementAvailableCall.java
+++ b/src/org/apache/xalan/xsltc/compiler/ElementAvailableCall.java
@@ -88,13 +88,30 @@
}
/**
+ * Returns an object representing the compile-time evaluation
+ * of an expression. We are only using this for function-available
+ * and element-available at this time.
+ */
+ public Object evaluateAtCompileTime() {
+ return getResult() ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ /**
* Returns the result that this function will return
*/
public boolean getResult() {
- final Parser parser = getParser();
- final LiteralExpr arg = (LiteralExpr)argument();
- final QName qname = parser.getQName(arg.getValue());
- return(parser.elementSupported(qname));
+ try {
+ final LiteralExpr arg = (LiteralExpr) argument();
+ final String qname = arg.getValue();
+ final int index = qname.indexOf(':');
+ final String localName = (index > 0) ?
+ qname.substring(index + 1) : qname;
+ return getParser().elementSupported(arg.getNamespace(),
+ localName);
+ }
+ catch (ClassCastException e) {
+ return false;
+ }
}
/**
diff --git a/src/org/apache/xalan/xsltc/compiler/EqualityExpr.java b/src/org/apache/xalan/xsltc/compiler/EqualityExpr.java
index 4b8bb9b..6af9494 100644
--- a/src/org/apache/xalan/xsltc/compiler/EqualityExpr.java
+++ b/src/org/apache/xalan/xsltc/compiler/EqualityExpr.java
@@ -101,10 +101,7 @@
}
public boolean getOp() {
- if (_op == Operators.NE)
- return false;
- else
- return true;
+ return (_op != Operators.NE);
}
/**
diff --git a/src/org/apache/xalan/xsltc/compiler/Expression.java b/src/org/apache/xalan/xsltc/compiler/Expression.java
index 3da80c6..6b58c8f 100644
--- a/src/org/apache/xalan/xsltc/compiler/Expression.java
+++ b/src/org/apache/xalan/xsltc/compiler/Expression.java
@@ -103,7 +103,7 @@
public abstract String toString();
public boolean hasPositionCall() {
- return true;
+ return false; // default should be 'false' for StepPattern
}
public boolean hasLastCall() {
@@ -111,6 +111,15 @@
}
/**
+ * Returns an object representing the compile-time evaluation
+ * of an expression. We are only using this for function-available
+ * and element-available at this time.
+ */
+ public Object evaluateAtCompileTime() {
+ return null;
+ }
+
+ /**
* Type check all the children of this node.
*/
public Type typeCheck(SymbolTable stable) throws TypeCheckError {
diff --git a/src/org/apache/xalan/xsltc/compiler/FilterParentPath.java b/src/org/apache/xalan/xsltc/compiler/FilterParentPath.java
index 1562c60..4f320b7 100644
--- a/src/org/apache/xalan/xsltc/compiler/FilterParentPath.java
+++ b/src/org/apache/xalan/xsltc/compiler/FilterParentPath.java
@@ -149,9 +149,9 @@
// This is a special case for the //* path with or without predicates
if (_hasDescendantAxis) {
- final int incl = cpg.addMethodref(STEP_ITERATOR_CLASS,
+ final int incl = cpg.addMethodref(NODE_ITERATOR_BASE,
"includeSelf",
- "()"+NODE_ITERATOR_SIG);
+ "()" + NODE_ITERATOR_SIG);
il.append(new INVOKEVIRTUAL(incl));
}
diff --git a/src/org/apache/xalan/xsltc/compiler/FormatNumberCall.java b/src/org/apache/xalan/xsltc/compiler/FormatNumberCall.java
index 9558f1a..b4ee8e2 100644
--- a/src/org/apache/xalan/xsltc/compiler/FormatNumberCall.java
+++ b/src/org/apache/xalan/xsltc/compiler/FormatNumberCall.java
@@ -74,6 +74,7 @@
private Expression _value;
private Expression _format;
private Expression _name;
+ private QName _resolvedQName = null;
public FormatNumberCall(QName fname, Vector arguments) {
super(fname, arguments);
@@ -83,9 +84,8 @@
}
public Type typeCheck(SymbolTable stable) throws TypeCheckError {
- // The stylesheet element only adds code to instanciate the
- // default DecimalFormat object if at least one format-number()
- // call exists in the stylesheet. We must signal this call...
+
+ // Inform stylesheet to instantiate a DecimalFormat object
getStylesheet().numberFormattingUsed();
final Type tvalue = _value.typeCheck(stable);
@@ -97,8 +97,14 @@
_format = new CastExpr(_format, Type.String);
}
if (argumentCount() == 3) {
- final Type tname = _format.typeCheck(stable);
- if (tname instanceof StringType == false) {
+ final Type tname = _name.typeCheck(stable);
+
+ if (_name instanceof LiteralExpr) {
+ final LiteralExpr literal = (LiteralExpr) _name;
+ _resolvedQName =
+ getParser().getQNameIgnoreDefaultNs(literal.getValue());
+ }
+ else if (tname instanceof StringType == false) {
_name = new CastExpr(_name, Type.String);
}
}
@@ -126,6 +132,9 @@
if (_name == null) {
il.append(new PUSH(cpg, EMPTYSTRING));
}
+ else if (_resolvedQName != null) {
+ il.append(new PUSH(cpg, _resolvedQName.toString()));
+ }
else {
_name.translate(classGen, methodGen);
}
diff --git a/src/org/apache/xalan/xsltc/compiler/FunctionAvailableCall.java b/src/org/apache/xalan/xsltc/compiler/FunctionAvailableCall.java
index 1e6aafc..35e0501 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,36 +64,190 @@
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 Expression _arg;
+ private String _nameOfFunct = null;
+ private String _namespaceOfFunct = null;
+ private boolean _isFunctionAvailable = false;
+
+ /**
+ * 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.
+ */
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.startsWith(JAVA_EXT_XSLTC) ||
+ _namespaceOfFunct.startsWith(JAVA_EXT_XALAN)))
+ {
+ _isFunctionAvailable = hasMethods();
+ }
+ }
}
/**
- * 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) {
+ if (_type != null) {
+ return _type;
+ }
+ if (_arg instanceof LiteralExpr) {
return _type = 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
+ * Returns an object representing the compile-time evaluation
+ * of an expression. We are only using this for function-available
+ * and element-available at this time.
+ */
+ public Object evaluateAtCompileTime() {
+ return getResult() ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ /**
+ * (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);
+
+ 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 (_nameOfFunct == null) {
+ return false;
+ }
+
+ if (_namespaceOfFunct == null ||
+ _namespaceOfFunct.equals(EMPTYSTRING) ||
+ _namespaceOfFunct.equals(TRANSLET_URI))
+ {
+ final Parser parser = getParser();
+ _isFunctionAvailable =
+ parser.functionSupported(Util.getLocalName(_nameOfFunct));
+ }
+ return _isFunctionAvailable;
}
/**
@@ -103,7 +257,7 @@
*/
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..50f341b 100644
--- a/src/org/apache/xalan/xsltc/compiler/FunctionCall.java
+++ b/src/org/apache/xalan/xsltc/compiler/FunctionCall.java
@@ -86,10 +86,19 @@
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 EXT_XSLTC =
+ TRANSLET_URI;
+
+ protected final static String JAVA_EXT_XSLTC =
+ EXT_XSLTC + "/java";
+
+ protected final static String EXT_XALAN =
+ "http://xml.apache.org/xalan";
+
+ protected final static String JAVA_EXT_XALAN =
"http://xml.apache.org/xslt/java";
+
// External Java function's class/method/signature
private String _className;
private Method _chosenMethod;
@@ -112,6 +121,7 @@
*/
static {
try {
+ final Class objectClass = Class.forName("java.lang.Object");
final Class stringClass = Class.forName("java.lang.String");
final Class nodeClass = Class.forName("org.w3c.dom.Node");
final Class nodeListClass = Class.forName("org.w3c.dom.NodeList");
@@ -147,6 +157,8 @@
_internal2Java.put(Type.ResultTree, nodeClass);
_internal2Java.put(Type.ResultTree, nodeListClass);
+ _internal2Java.put(Type.Reference, objectClass);
+
// Possible conversions between Java and internal types
_java2Internal.put(Boolean.TYPE, Type.Boolean);
@@ -160,6 +172,8 @@
_java2Internal.put(stringClass, Type.String);
+ _java2Internal.put(objectClass, Type.Reference);
+
// Conversions from org.w3c.dom.Node/NodeList are not supported
}
catch (ClassNotFoundException e) {
@@ -170,6 +184,7 @@
public FunctionCall(QName fname, Vector arguments) {
_fname = fname;
_arguments = arguments;
+ _type = null;
}
public FunctionCall(QName fname) {
@@ -192,48 +207,71 @@
}
}
+ public String getClassNameFromUri(String uri)
+ throws TypeCheckError
+ {
+ final int length =
+ uri.startsWith(JAVA_EXT_XSLTC) ? JAVA_EXT_XSLTC.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();
- // XPath functions have no namespace
- if (isStandard()) {
+ if (isExtension()) {
+ _fname = new QName(null, null, local);
+ return typeCheckStandard(stable);
+ }
+ else if (isStandard()) {
return typeCheckStandard(stable);
}
// 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));
}
- unresolvedExternal = true;
- return _type = Type.Void;
+ else {
+ _fname = new QName(namespace, null, local);
+ }
+ if (_className.length() > 0) {
+ return typeCheckExternal(stable);
+ }
+ } catch (TypeCheckError e) {
+ // Falls through
}
- return typeCheckExternal(stable);
+
+ /*
+ * 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());
+ }
+ unresolvedExternal = true;
+ return _type = Type.Void;
}
}
@@ -243,8 +281,7 @@
* thrown, then catch it and re-throw it with a new "this".
*/
public Type typeCheckStandard(SymbolTable stable) throws TypeCheckError {
-
- _fname.clearNamespace(); // HACK!!!
+ _fname.clearNamespace(); // HACK!!!
final int n = _arguments.size();
final Vector argsType = typeCheckArgs(stable);
@@ -367,8 +404,8 @@
* Update true/false-lists.
*/
public void translateDesynthesized(ClassGenerator classGen,
- MethodGenerator methodGen) {
-
+ MethodGenerator methodGen)
+ {
Type type = Type.Boolean;
if (_chosenMethodType != null)
type = _chosenMethodType.resultType();
@@ -393,7 +430,7 @@
int index;
// Translate calls to methods in the BasisLibrary
- if (isStandard()) {
+ if (isStandard() || isExtension()) {
for (int i = 0; i < n; i++) {
final Expression exp = argument(i);
exp.translate(classGen, methodGen);
@@ -442,7 +479,7 @@
exp.translate(classGen, methodGen);
// Convert the argument to its Java type
exp.startResetIterator(classGen, methodGen);
- exp._type.translateTo(classGen, methodGen, paramTypes[i]);
+ exp.getType().translateTo(classGen, methodGen, paramTypes[i]);
}
final StringBuffer buffer = new StringBuffer();
@@ -470,10 +507,13 @@
public boolean isStandard() {
final String namespace = _fname.getNamespace();
- if ((namespace == null) || (namespace.equals(Constants.EMPTYSTRING)))
- return true;
- else
- return false;
+ return (namespace == null) || (namespace.equals(Constants.EMPTYSTRING));
+ }
+
+ public boolean isExtension() {
+ final String namespace = _fname.getNamespace();
+ return (namespace != null) && (namespace.equals(EXT_XSLTC)
+ || namespace.equals(EXT_XALAN));
}
/**
@@ -485,7 +525,7 @@
Vector result = null;
final String namespace = _fname.getNamespace();
- if (namespace.startsWith(JAVA_EXT_PREFIX) ||
+ if (namespace.startsWith(JAVA_EXT_XSLTC) ||
namespace.startsWith(JAVA_EXT_XALAN)) {
final int nArgs = _arguments.size();
try {
diff --git a/src/org/apache/xalan/xsltc/compiler/If.java b/src/org/apache/xalan/xsltc/compiler/If.java
index cc115b0..b51d795 100644
--- a/src/org/apache/xalan/xsltc/compiler/If.java
+++ b/src/org/apache/xalan/xsltc/compiler/If.java
@@ -102,17 +102,11 @@
return;
}
- // We will ignore the contents of this <xsl:if> if we know that the
- // test will always return 'false'.
- if (_test instanceof ElementAvailableCall) {
- ElementAvailableCall call = (ElementAvailableCall)_test;
- _ignore = !call.getResult();
- return;
- }
- if (_test instanceof FunctionAvailableCall) {
- FunctionAvailableCall call = (FunctionAvailableCall)_test;
- _ignore = !call.getResult();
- return;
+ // Ignore xsl:if when test is false (function-available() and
+ // element-available())
+ Object result = _test.evaluateAtCompileTime();
+ if (result != null && result instanceof Boolean) {
+ _ignore = !((Boolean) result).booleanValue();
}
parseChildren(parser);
diff --git a/src/org/apache/xalan/xsltc/compiler/Include.java b/src/org/apache/xalan/xsltc/compiler/Include.java
index 9f50727..e2f6728 100644
--- a/src/org/apache/xalan/xsltc/compiler/Include.java
+++ b/src/org/apache/xalan/xsltc/compiler/Include.java
@@ -65,6 +65,7 @@
package org.apache.xalan.xsltc.compiler;
import java.io.File;
+import java.io.FileNotFoundException;
import java.net.URL;
import java.net.MalformedURLException;
import java.util.Enumeration;
@@ -88,8 +89,8 @@
public void parseContents(final Parser parser) {
final Stylesheet context = parser.getCurrentStylesheet();
+ String docToLoad = getAttribute("href");
try {
- String docToLoad = getAttribute("href");
if (context.checkForLoop(docToLoad)) {
final int errno = ErrorMsg.CIRCULAR_INCLUDE_ERR;
final ErrorMsg msg = new ErrorMsg(errno, docToLoad, this);
@@ -106,11 +107,28 @@
input = loader.loadSource(docToLoad, currLoadedDoc, xsltc);
}
else {
- File file = new File(currLoadedDoc);
- if (file.exists()) currLoadedDoc = "file:"+currLoadedDoc;
- final URL url = new URL(new URL(currLoadedDoc), docToLoad);
- docToLoad = url.toString();
- input = new InputSource(docToLoad);
+ // bug 7835, patch by Stefan Kost (s.kost@webmacher.de)
+ if ((currLoadedDoc != null) && (currLoadedDoc.length() > 0)) {
+ File file = new File(currLoadedDoc);
+ if (file.exists()) {
+ currLoadedDoc = "file:" + file.getCanonicalPath();
+ }
+ final URL url = new URL(new URL(currLoadedDoc), docToLoad);
+ docToLoad = url.toString();
+ input = new InputSource(docToLoad);
+ }
+ else {
+ File file = new File(System.getProperty("user.dir"),
+ docToLoad);
+ if (file.exists()) {
+ docToLoad = "file:" + file.getCanonicalPath();
+ }
+ else {
+ throw new FileNotFoundException(
+ "Could not load file " + docToLoad);
+ }
+ input = new InputSource(docToLoad);
+ }
}
final SyntaxTreeNode root = parser.parse(input);
@@ -122,6 +140,7 @@
_included.setSystemId(docToLoad);
_included.setParentStylesheet(context);
_included.setIncludingStylesheet(context);
+ _included.setTemplateInlining(context.getTemplateInlining());
// An included stylesheet gets the same import precedence
// as the stylesheet that included it.
@@ -145,6 +164,22 @@
}
}
}
+ catch (FileNotFoundException e) {
+ // Update systemId in parent stylesheet for error reporting
+ context.setSystemId(getAttribute("href"));
+
+ final ErrorMsg msg =
+ new ErrorMsg(ErrorMsg.FILE_NOT_FOUND_ERR, docToLoad, this);
+ parser.reportError(Constants.FATAL, msg);
+ }
+ catch (MalformedURLException e) {
+ // Update systemId in parent stylesheet for error reporting
+ context.setSystemId(getAttribute("href"));
+
+ final ErrorMsg msg =
+ new ErrorMsg(ErrorMsg.FILE_NOT_FOUND_ERR, docToLoad, this);
+ parser.reportError(Constants.FATAL, msg);
+ }
catch (Exception e) {
e.printStackTrace();
}
diff --git a/src/org/apache/xalan/xsltc/compiler/Key.java b/src/org/apache/xalan/xsltc/compiler/Key.java
index e4e9d5e..adc8b66 100644
--- a/src/org/apache/xalan/xsltc/compiler/Key.java
+++ b/src/org/apache/xalan/xsltc/compiler/Key.java
@@ -87,7 +87,7 @@
public void parseContents(Parser parser) {
// Get the required attributes and parser XPath expressions
- _name = parser.getQName(getAttribute("name"));
+ _name = parser.getQNameIgnoreDefaultNs(getAttribute("name"));
_match = parser.parsePattern(this, "match", null);
_use = parser.parseExpression(this, "use", null);
@@ -111,12 +111,7 @@
* @return The key's name (from the <xsl:key> elements 'name' attribute).
*/
public String getName() {
- String name;
- if (_name.getPrefix() == null)
- name = _name.getLocalPart();
- else
- name = _name.getPrefix()+":"+_name.getLocalPart();
- return(name);
+ return _name.toString();
}
/**
@@ -191,7 +186,8 @@
// Prepare to call buildKeyIndex(String name, int node, String value);
il.append(classGen.loadTranslet());
- il.append(new PUSH(cpg, getName()));
+ // il.append(new PUSH(cpg, getName()));
+ il.append(new PUSH(cpg, _name.toString()));
il.append(new ILOAD(parentNode.getIndex()));
// Now get the node value and feck it on the parameter stack
diff --git a/src/org/apache/xalan/xsltc/compiler/KeyCall.java b/src/org/apache/xalan/xsltc/compiler/KeyCall.java
index a7f93c1..00e878f 100644
--- a/src/org/apache/xalan/xsltc/compiler/KeyCall.java
+++ b/src/org/apache/xalan/xsltc/compiler/KeyCall.java
@@ -73,6 +73,7 @@
private Expression _name; // The name of this key
private Expression _value; // The value to look up in the key/index
private Type _valueType; // The value's data type
+ private QName _resolvedQName = null;
/**
* Get the parameters passed to function:
@@ -117,7 +118,13 @@
// and if it is not it must be converted to one using string() rules.
if (_name != null) {
final Type nameType = _name.typeCheck(stable);
- if (!(nameType instanceof StringType)) {
+
+ if (_name instanceof LiteralExpr) {
+ final LiteralExpr literal = (LiteralExpr) _name;
+ _resolvedQName =
+ getParser().getQNameIgnoreDefaultNs(literal.getValue());
+ }
+ else if (nameType instanceof StringType == false) {
_name = new CastExpr(_name, Type.String);
}
}
@@ -241,10 +248,15 @@
// Initialise the index specified in the first parameter of key()
il.append(classGen.loadTranslet());
- if (_name == null)
+ if (_name == null) {
il.append(new PUSH(cpg,"##id"));
- else
+ }
+ else if (_resolvedQName != null) {
+ il.append(new PUSH(cpg, _resolvedQName.toString()));
+ }
+ else {
_name.translate(classGen, methodGen);
+ }
il.append(new INVOKEVIRTUAL(getKeyIndex));
il.append(new ASTORE(searchIndex.getIndex()));
@@ -265,10 +277,12 @@
il.append(methodGen.loadDOM());
il.append(methodGen.loadCurrentNode());
il.append(new INVOKEINTERFACE(getNodeValue, 2));
- if (_name == null)
+ if (_name == null) {
il.append(new INVOKEVIRTUAL(lookupId));
- else
+ }
+ else {
il.append(new INVOKEVIRTUAL(lookupKey));
+ }
// Call to returnIndex.merge(searchIndex);
il.append(new INVOKEVIRTUAL(merge));
@@ -295,10 +309,15 @@
// Call getKeyIndex in AbstractTranslet with the name of the key
// to get the index for this key (which is also a node iterator).
il.append(classGen.loadTranslet());
- if (_name == null)
+ if (_name == null) {
il.append(new PUSH(cpg,"##id"));
- else
+ }
+ else if (_resolvedQName != null) {
+ il.append(new PUSH(cpg, _resolvedQName.toString()));
+ }
+ else {
_name.translate(classGen, methodGen);
+ }
il.append(new INVOKEVIRTUAL(getKeyIndex));
// Now use the value in the second argument to determine what nodes
@@ -318,10 +337,12 @@
_value.translate(classGen, methodGen);
}
- if (_name == null)
+ if (_name == null) {
il.append(new INVOKEVIRTUAL(lookupId));
- else
+ }
+ else {
il.append(new INVOKEVIRTUAL(lookupKey));
+ }
}
}
}
diff --git a/src/org/apache/xalan/xsltc/compiler/LiteralElement.java b/src/org/apache/xalan/xsltc/compiler/LiteralElement.java
index fffa79b..e04db84 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.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 @@
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 @@
if (old != null) {
if (old.equals(uri))
return;
- else
+ else
prefix = stable.generateNamespacePrefix();
}
}
@@ -207,7 +208,6 @@
_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 @@
* 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,17 @@
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 (e.g. xmlns:prefix and xmlns)
+ final String prefix = qname.getPrefix();
+ if (prefix != null && prefix.equals(XMLNS_PREFIX) ||
+ prefix == null && qname.getLocalPart().equals("xmlns") ||
+ uri != null && uri.equals(XSLT_URI))
+ {
+ continue;
+ }
+
+ // Handle all other literal attributes
final String name = translateQName(qname, stable);
LiteralAttribute attr = new LiteralAttribute(name, val, parser);
addAttribute(attr);
@@ -311,9 +317,8 @@
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 +327,6 @@
// 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 +348,9 @@
/**
* 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 +360,52 @@
// 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/LiteralExpr.java b/src/org/apache/xalan/xsltc/compiler/LiteralExpr.java
index 93623a9..b169eff 100644
--- a/src/org/apache/xalan/xsltc/compiler/LiteralExpr.java
+++ b/src/org/apache/xalan/xsltc/compiler/LiteralExpr.java
@@ -88,10 +88,7 @@
*/
public LiteralExpr(String value, String namespace) {
_value = value;
- if (namespace.equals(Constants.EMPTYSTRING))
- _namespace = null;
- else
- _namespace = namespace;
+ _namespace = namespace.equals(Constants.EMPTYSTRING) ? null : namespace;
}
public Type typeCheck(SymbolTable stable) throws TypeCheckError {
diff --git a/src/org/apache/xalan/xsltc/compiler/LogicalExpr.java b/src/org/apache/xalan/xsltc/compiler/LogicalExpr.java
index ff727d0..a0d86a3 100644
--- a/src/org/apache/xalan/xsltc/compiler/LogicalExpr.java
+++ b/src/org/apache/xalan/xsltc/compiler/LogicalExpr.java
@@ -96,9 +96,31 @@
* needed for context changes in node steps containing multiple predicates.
*/
public boolean hasPositionCall() {
- if (_left.hasPositionCall()) return true;
- if (_right.hasPositionCall()) return true;
- return false;
+ return (_left.hasPositionCall() || _right.hasPositionCall());
+ }
+
+ /**
+ * Returns an object representing the compile-time evaluation
+ * of an expression. We are only using this for function-available
+ * and element-available at this time.
+ */
+ public Object evaluateAtCompileTime() {
+ final Object leftb = _left.evaluateAtCompileTime();
+ final Object rightb = _right.evaluateAtCompileTime();
+
+ // Return null if we can't evaluate at compile time
+ if (leftb == null || rightb == null) {
+ return null;
+ }
+
+ if (_op == AND) {
+ return (leftb == Boolean.TRUE && rightb == Boolean.TRUE) ?
+ Boolean.TRUE : Boolean.FALSE;
+ }
+ else {
+ return (leftb == Boolean.TRUE || rightb == Boolean.TRUE) ?
+ Boolean.TRUE : Boolean.FALSE;
+ }
}
/**
diff --git a/src/org/apache/xalan/xsltc/compiler/Mode.java b/src/org/apache/xalan/xsltc/compiler/Mode.java
index febab4f..c869a79 100644
--- a/src/org/apache/xalan/xsltc/compiler/Mode.java
+++ b/src/org/apache/xalan/xsltc/compiler/Mode.java
@@ -82,21 +82,54 @@
*/
final class Mode implements Constants {
- private final QName _name; // The QName of this mode
- private final Stylesheet _stylesheet; // The owning stylesheet
- private final String _methodName; // The method name for this mode
- private Vector _templates; // All templates in this mode
+ /**
+ * The name of this mode as defined in the stylesheet.
+ */
+ private final QName _name;
- // Pattern/test sequence for pattern with node()-type kernel
- private Vector _nodeGroup = null;
- private TestSeq _nodeTestSeq = null;
+ /**
+ * A reference to the stylesheet object that owns this mode.
+ */
+ private final Stylesheet _stylesheet;
- // Pattern/test sequence for pattern with id() or key()-type kernel
- private Vector _idxGroup = null;
- private TestSeq _idxTestSeq = null;
+ /**
+ * The name of the method in which this mode is compiled.
+ */
+ private final String _methodName;
- // Pattern/test sequence for patterns with any other kernel type
+ /**
+ * A vector of all the templates in this mode.
+ */
+ private Vector _templates;
+
+ /**
+ * Group for patterns with node()-type kernel.
+ */
+ private Vector _nodeGroup = null;
+
+ /**
+ * Test sequence for patterns with node()-type kernel.
+ */
+ private TestSeq _nodeTestSeq = null;
+
+ /**
+ * Group for patterns with id() or key()-type kernel.
+ */
+ private Vector _idxGroup = null;
+
+ /**
+ * Test sequence for patterns with id() or key()-type kernel.
+ */
+ private TestSeq _idxTestSeq = null;
+
+ /**
+ * Group for patterns with any other kernel type.
+ */
private Vector[] _patternGroups;
+
+ /**
+ * Test sequence for patterns with any other kernel type.
+ */
private TestSeq[] _testSeq;
private Hashtable _neededTemplates = new Hashtable();
@@ -114,7 +147,8 @@
/**
- * Creates a new Mode
+ * Creates a new Mode.
+ *
* @param name A textual representation of the mode's QName
* @param stylesheet The Stylesheet in which the mode occured
* @param suffix A suffix to append to the method name for this mode
@@ -161,30 +195,30 @@
_templates.addElement(template);
}
- /*
private Vector quicksort(Vector templates, int p, int r) {
- while (p < r) {
+ if (p < r) {
final int q = partition(templates, p, r);
quicksort(templates, p, q);
- p = q + 1;
+ quicksort(templates, q + 1, r);
}
return templates;
}
private int partition(Vector templates, int p, int r) {
- final Template x = (Template)templates.elementAt((p + r) >>> 1);
+ final Template x = (Template)templates.elementAt(p);
int i = p - 1;
int j = r + 1;
while (true) {
- while (x.compareTo((Template)templates.elementAt(--j)) < 0);
- while (x.compareTo((Template)templates.elementAt(++i)) > 0);
- if (i < j)
+ while (x.compareTo((Template)templates.elementAt(--j)) > 0);
+ while (x.compareTo((Template)templates.elementAt(++i)) < 0);
+ if (i < j) {
templates.set(j, templates.set(i, templates.elementAt(j)));
- else
- return(j);
+ }
+ else {
+ return j;
+ }
}
}
- */
/**
* Process all the test patterns in this mode
@@ -192,7 +226,27 @@
public void processPatterns(Hashtable keys) {
_keys = keys;
- //_templates = quicksort(_templates, 0, _templates.size() - 1);
+/*
+System.out.println("Before Sort " + _name);
+for (int i = 0; i < _templates.size(); i++) {
+ System.out.println("name = " + ((Template)_templates.elementAt(i)).getName());
+ System.out.println("pattern = " + ((Template)_templates.elementAt(i)).getPattern());
+ System.out.println("priority = " + ((Template)_templates.elementAt(i)).getPriority());
+ System.out.println("position = " + ((Template)_templates.elementAt(i)).getPosition());
+}
+*/
+
+ _templates = quicksort(_templates, 0, _templates.size() - 1);
+
+/*
+System.out.println("\n After Sort " + _name);
+for (int i = 0; i < _templates.size(); i++) {
+ System.out.println("name = " + ((Template)_templates.elementAt(i)).getName());
+ System.out.println("pattern = " + ((Template)_templates.elementAt(i)).getPattern());
+ System.out.println("priority = " + ((Template)_templates.elementAt(i)).getPriority());
+ System.out.println("position = " + ((Template)_templates.elementAt(i)).getPosition());
+}
+*/
// Traverse all templates
final Enumeration templates = _templates.elements();
@@ -200,15 +254,20 @@
// Get the next template
final Template template = (Template)templates.nextElement();
- // Add this template to a table of named templates if it has a name.
- // If there are multiple templates with the same name, all but one
- // (the one with highest priority) will be disabled.
- if (template.isNamed() && !template.disabled())
+ /*
+ * Add this template to a table of named templates if it has a name.
+ * If there are multiple templates with the same name, all but one
+ * (the one with highest priority) will be disabled.
+ */
+ if (template.isNamed() && !template.disabled()) {
_namedTemplates.put(template, this);
+ }
// Add this template to a test sequence if it has a pattern
final Pattern pattern = template.getPattern();
- if (pattern != null) flattenAlternative(pattern, template, keys);
+ if (pattern != null) {
+ flattenAlternative(pattern, template, keys);
+ }
}
prepareTestSequences();
}
@@ -261,10 +320,7 @@
Vector patterns;
// Use the vector for id()/key()/node() patterns if no kernel type
- if (kernelType == -1)
- patterns = _nodeGroup;
- else
- patterns = _patternGroups[kernelType];
+ patterns = (kernelType == -1) ? _nodeGroup : _patternGroups[kernelType];
// Create a new vector if needed and insert the very first pattern
if (patterns == null) {
@@ -389,7 +445,8 @@
private void compileTemplates(ClassGenerator classGen,
MethodGenerator methodGen,
- InstructionHandle next) {
+ InstructionHandle next)
+ {
Enumeration templates = _namedTemplates.keys();
while (templates.hasMoreElements()) {
final Template template = (Template)templates.nextElement();
@@ -563,22 +620,16 @@
}
/**
- * Auxillary method to determine if a qname describes an attribute/element
+ * Auxiliary method to determine if a qname describes an attribute/element
*/
private static boolean isAttributeName(String qname) {
final int col = qname.lastIndexOf(':') + 1;
- if (qname.charAt(col) == '@')
- return(true);
- else
- return(false);
+ return (qname.charAt(col) == '@');
}
private static boolean isNamespaceName(String qname) {
final int col = qname.lastIndexOf(':');
- if ((col > -1) && (qname.charAt(qname.length()-1) == '*'))
- return(true);
- else
- return(false);
+ return (col > -1 && qname.charAt(qname.length()-1) == '*');
}
/**
@@ -588,9 +639,9 @@
public void compileApplyTemplates(ClassGenerator classGen) {
final XSLTC xsltc = classGen.getParser().getXSLTC();
final ConstantPoolGen cpg = classGen.getConstantPool();
- final Vector names = xsltc.getNamesIndex();
+ final Vector names = xsltc.getNamesIndex();
- // (*) Create the applyTemplates() method
+ // Create the applyTemplates() method
final org.apache.bcel.generic.Type[] argTypes =
new org.apache.bcel.generic.Type[3];
argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
@@ -611,20 +662,20 @@
classGen.getConstantPool());
methodGen.addException("org.apache.xalan.xsltc.TransletException");
- // (*) Create the local variablea
+ // Create a local variable to hold the current node
final LocalVariableGen current;
current = methodGen.addLocalVariable2("current",
org.apache.bcel.generic.Type.INT,
mainIL.getEnd());
_currentIndex = current.getIndex();
- // (*) Create the "body" instruction list that will eventually hold the
- // code for the entire method (other ILs will be appended).
+ // Create the "body" instruction list that will eventually hold the
+ // code for the entire method (other ILs will be appended).
final InstructionList body = new InstructionList();
body.append(NOP);
- // (*) Create an instruction list that contains the default next-node
- // iteration
+ // Create an instruction list that contains the default next-node
+ // iteration
final InstructionList ilLoop = new InstructionList();
ilLoop.append(methodGen.loadIterator());
ilLoop.append(methodGen.nextNode());
@@ -635,41 +686,44 @@
// by a single IFNE(body.getStart()) instruction - need workaround:
final BranchHandle ifeq = ilLoop.append(new IFEQ(null));
final BranchHandle loop = ilLoop.append(new GOTO_W(null));
- ifeq.setTarget(ilLoop.append(RETURN)); // applyTemplates() ends here!
+ ifeq.setTarget(ilLoop.append(RETURN)); // applyTemplates() ends here!
final InstructionHandle ihLoop = ilLoop.getStart();
- // (*) Compile default handling of elements (traverse children)
+ // Compile default handling of elements (traverse children)
InstructionList ilRecurse =
compileDefaultRecursion(classGen, methodGen, ihLoop);
InstructionHandle ihRecurse = ilRecurse.getStart();
- // (*) Compile default handling of text/attribute nodes (output text)
+ // Compile default handling of text/attribute nodes (output text)
InstructionList ilText =
compileDefaultText(classGen, methodGen, ihLoop);
InstructionHandle ihText = ilText.getStart();
// Distinguish attribute/element/namespace tests for further processing
final int[] types = new int[DOM.NTYPES + names.size()];
- for (int i = 0; i < types.length; i++) types[i] = i;
+ for (int i = 0; i < types.length; i++) {
+ types[i] = i;
+ }
+ // Initialize isAttribute[] and isNamespace[] arrays
final boolean[] isAttribute = new boolean[types.length];
final boolean[] isNamespace = new boolean[types.length];
for (int i = 0; i < names.size(); i++) {
final String name = (String)names.elementAt(i);
- isAttribute[i+DOM.NTYPES] = isAttributeName(name);
- isNamespace[i+DOM.NTYPES] = isNamespaceName(name);
+ isAttribute[i + DOM.NTYPES] = isAttributeName(name);
+ isNamespace[i + DOM.NTYPES] = isNamespaceName(name);
}
- // (*) Compile all templates - regardless of pattern type
+ // Compile all templates - regardless of pattern type
compileTemplates(classGen, methodGen, ihLoop);
- // (*) Handle template with explicit "*" pattern
+ // Handle template with explicit "*" pattern
final TestSeq elemTest = _testSeq[DOM.ELEMENT];
InstructionHandle ihElem = ihRecurse;
if (elemTest != null)
ihElem = elemTest.compile(classGen, methodGen, ihRecurse);
- // (*) Handle template with explicit "@*" pattern
+ // Handle template with explicit "@*" pattern
final TestSeq attrTest = _testSeq[DOM.ATTRIBUTE];
InstructionHandle ihAttr = ihText;
if (attrTest != null)
@@ -685,39 +739,58 @@
loop.setTarget(body.getStart());
}
- // (*) If there is a match on node() we need to replace ihElem
- // and ihText (default behaviour for elements & text).
+ // If there is a match on node() we need to replace ihElem
+ // and ihText if the priority of node() is higher
if (_nodeTestSeq != null) {
- double nodePrio = -0.5; //_nodeTestSeq.getPriority();
+
+ // Compare priorities of node() and "*"
+ double nodePrio = _nodeTestSeq.getPriority();
int nodePos = _nodeTestSeq.getPosition();
double elemPrio = (0 - Double.MAX_VALUE);
int elemPos = Integer.MIN_VALUE;
+
if (elemTest != null) {
elemPrio = elemTest.getPriority();
elemPos = elemTest.getPosition();
}
- if ((elemPrio == Double.NaN) || (elemPrio < nodePrio) ||
- ((elemPrio == nodePrio) && (elemPos < nodePos))) {
+ if (elemPrio == Double.NaN || elemPrio < nodePrio ||
+ (elemPrio == nodePrio && elemPos < nodePos))
+ {
ihElem = _nodeTestSeq.compile(classGen, methodGen, ihLoop);
- ihText = ihElem;
+ }
+
+ // Compare priorities of node() and text()
+ final TestSeq textTest = _testSeq[DOM.TEXT];
+ double textPrio = (0 - Double.MAX_VALUE);
+ int textPos = Integer.MIN_VALUE;
+
+ if (textTest != null) {
+ textPrio = textTest.getPriority();
+ textPos = textTest.getPosition();
+ }
+ if (textPrio == Double.NaN || textPrio < nodePrio ||
+ (textPrio == nodePrio && textPos < nodePos))
+ {
+ ihText = _nodeTestSeq.compile(classGen, methodGen, ihLoop);
+ _testSeq[DOM.TEXT] = _nodeTestSeq;
}
}
- // (*) Handle templates with "ns:*" pattern
+ // Handle templates with "ns:*" pattern
InstructionHandle elemNamespaceHandle = ihElem;
InstructionList nsElem = compileNamespaces(classGen, methodGen,
isNamespace, isAttribute,
false, ihElem);
if (nsElem != null) elemNamespaceHandle = nsElem.getStart();
- // (*) Handle templates with "ns:@*" pattern
+ // Handle templates with "ns:@*" pattern
InstructionHandle attrNamespaceHandle = ihAttr;
InstructionList nsAttr = compileNamespaces(classGen, methodGen,
isNamespace, isAttribute,
true, ihAttr);
if (nsAttr != null) attrNamespaceHandle = nsAttr.getStart();
- // (*) Handle templates with "ns:elem" or "ns:@attr" pattern
+ // Handle templates with "ns:elem" or "ns:@attr" pattern
final InstructionHandle[] targets = new InstructionHandle[types.length];
for (int i = DOM.NTYPES; i < targets.length; i++) {
final TestSeq testSeq = _testSeq[i];
@@ -902,7 +975,7 @@
// Process all patterns from those templates
processPatterns(_keys);
- // (*) Create the applyTemplates() method
+ // Create the applyTemplates() method
final org.apache.bcel.generic.Type[] argTypes =
new org.apache.bcel.generic.Type[3];
argTypes[0] = Util.getJCRefType(DOM_INTF_SIG);
@@ -936,20 +1009,20 @@
return;
}
- // (*) Create the local variablea
+ // Create the local variablea
final LocalVariableGen current;
current = methodGen.addLocalVariable2("current",
org.apache.bcel.generic.Type.INT,
mainIL.getEnd());
_currentIndex = current.getIndex();
- // (*) Create the "body" instruction list that will eventually hold the
- // code for the entire method (other ILs will be appended).
+ // Create the "body" instruction list that will eventually hold the
+ // code for the entire method (other ILs will be appended).
final InstructionList body = new InstructionList();
body.append(NOP);
- // (*) Create an instruction list that contains the default next-node
- // iteration
+ // Create an instruction list that contains the default next-node
+ // iteration
final InstructionList ilLoop = new InstructionList();
ilLoop.append(methodGen.loadIterator());
ilLoop.append(methodGen.nextNode());
@@ -965,7 +1038,9 @@
// Distinguish attribute/element/namespace tests for further processing
final int[] types = new int[DOM.NTYPES + names.size()];
- for (int i = 0; i < types.length; i++) types[i] = i;
+ for (int i = 0; i < types.length; i++) {
+ types[i] = i;
+ }
final boolean[] isAttribute = new boolean[types.length];
final boolean[] isNamespace = new boolean[types.length];
@@ -975,20 +1050,22 @@
isNamespace[i+DOM.NTYPES] = isNamespaceName(name);
}
- // (*) Compile all templates - regardless of pattern type
+ // Compile all templates - regardless of pattern type
compileTemplateCalls(classGen, methodGen, ihLoop, min, max);
- // (*) Handle template with explicit "*" pattern
+ // Handle template with explicit "*" pattern
final TestSeq elemTest = _testSeq[DOM.ELEMENT];
InstructionHandle ihElem = ihLoop;
- if (elemTest != null)
+ if (elemTest != null) {
ihElem = elemTest.compile(classGen, methodGen, ihLoop);
+ }
- // (*) Handle template with explicit "@*" pattern
+ // Handle template with explicit "@*" pattern
final TestSeq attrTest = _testSeq[DOM.ATTRIBUTE];
InstructionHandle ihAttr = ihLoop;
- if (attrTest != null)
+ if (attrTest != null) {
ihAttr = attrTest.compile(classGen, methodGen, ihAttr);
+ }
// Do tests for id() and key() patterns first
InstructionList ilKey = null;
@@ -1000,40 +1077,61 @@
loop.setTarget(body.getStart());
}
- // (*) If there is a match on node() we need to replace ihElem
- // and ihText (default behaviour for elements & text).
+ // If there is a match on node() we need to replace ihElem
+ // and ihText if the priority of node() is higher
InstructionHandle ihText = ihLoop;
if (_nodeTestSeq != null) {
- double nodePrio = -0.5; //_nodeTestSeq.getPriority();
+
+ // Compare priorities of node() and "*"
+ double nodePrio = _nodeTestSeq.getPriority();
int nodePos = _nodeTestSeq.getPosition();
double elemPrio = (0 - Double.MAX_VALUE);
int elemPos = Integer.MIN_VALUE;
+
if (elemTest != null) {
elemPrio = elemTest.getPriority();
elemPos = elemTest.getPosition();
}
- if ((elemPrio == Double.NaN) || (elemPrio < nodePrio) ||
- ((elemPrio == nodePrio) && (elemPos < nodePos))) {
+
+ if (elemPrio == Double.NaN || elemPrio < nodePrio ||
+ (elemPrio == nodePrio && elemPos < nodePos))
+ {
ihElem = _nodeTestSeq.compile(classGen, methodGen, ihLoop);
- ihText = ihElem;
+ }
+
+ // Compare priorities of node() and text()
+ final TestSeq textTest = _testSeq[DOM.TEXT];
+ double textPrio = (0 - Double.MAX_VALUE);
+ int textPos = Integer.MIN_VALUE;
+
+ if (textTest != null) {
+ textPrio = textTest.getPriority();
+ textPos = textTest.getPosition();
+ }
+
+ if (textPrio == Double.NaN || textPrio < nodePrio ||
+ (textPrio == nodePrio && textPos < nodePos))
+ {
+ ihText = _nodeTestSeq.compile(classGen, methodGen, ihLoop);
+ _testSeq[DOM.TEXT] = _nodeTestSeq;
}
}
- // (*) Handle templates with "ns:*" pattern
+ // Handle templates with "ns:*" pattern
InstructionHandle elemNamespaceHandle = ihElem;
InstructionList nsElem = compileNamespaces(classGen, methodGen,
isNamespace, isAttribute,
false, ihElem);
if (nsElem != null) elemNamespaceHandle = nsElem.getStart();
- // (*) Handle templates with "ns:@*" pattern
+ // Handle templates with "ns:@*" pattern
InstructionList nsAttr = compileNamespaces(classGen, methodGen,
isNamespace, isAttribute,
true, ihAttr);
InstructionHandle attrNamespaceHandle = ihAttr;
if (nsAttr != null) attrNamespaceHandle = nsAttr.getStart();
- // (*) Handle templates with "ns:elem" or "ns:@attr" pattern
+ // Handle templates with "ns:elem" or "ns:@attr" pattern
final InstructionHandle[] targets = new InstructionHandle[types.length];
for (int i = DOM.NTYPES; i < targets.length; i++) {
final TestSeq testSeq = _testSeq[i];
@@ -1080,12 +1178,14 @@
// Match on processing instruction - default: loop
InstructionHandle ihPI = ihLoop;
if (_nodeTestSeq != null) ihPI = ihElem;
- if (_testSeq[DOM.PROCESSING_INSTRUCTION] != null)
+ if (_testSeq[DOM.PROCESSING_INSTRUCTION] != null) {
targets[DOM.PROCESSING_INSTRUCTION] =
_testSeq[DOM.PROCESSING_INSTRUCTION].
compile(classGen, methodGen, ihPI);
- else
+ }
+ else {
targets[DOM.PROCESSING_INSTRUCTION] = ihPI;
+ }
// Match on comments - default: process next node
InstructionHandle ihComment = ihLoop;
diff --git a/src/org/apache/xalan/xsltc/compiler/NameBase.java b/src/org/apache/xalan/xsltc/compiler/NameBase.java
index a15f49f..2b5c4d5 100644
--- a/src/org/apache/xalan/xsltc/compiler/NameBase.java
+++ b/src/org/apache/xalan/xsltc/compiler/NameBase.java
@@ -72,7 +72,7 @@
class NameBase extends FunctionCall {
private Expression _param = null;
- private Type _type = Type.Node;
+ private Type _paramType = Type.Node;
/**
* Handles calls with no parameter (current node is implicit parameter).
@@ -99,30 +99,29 @@
// Check the argument type (if any)
switch(argumentCount()) {
case 0:
- _type = Type.Node;
+ _paramType = Type.Node;
break;
case 1:
- _type = _param.typeCheck(stable);
+ _paramType = _param.typeCheck(stable);
break;
default:
throw new TypeCheckError(this);
}
// The argument has to be a node, a node-set or a node reference
- if ((_type != Type.NodeSet) &&
- (_type != Type.Node) &&
- (_type != Type.Reference)) {
+ if ((_paramType != Type.NodeSet) &&
+ (_paramType != Type.Node) &&
+ (_paramType != Type.Reference)) {
throw new TypeCheckError(this);
}
- return Type.String;
+ return (_type = Type.String);
}
public Type getType() {
- return Type.String;
+ return _type;
}
-
/**
* Translate the code required for getting the node for which the
* QName, local-name or namespace URI should be extracted.
@@ -139,10 +138,10 @@
il.append(methodGen.loadContextNode());
}
// Function was called with node parameter
- else if (_type == Type.Node) {
+ else if (_paramType == Type.Node) {
_param.translate(classGen, methodGen);
}
- else if (_type == Type.Reference) {
+ else if (_paramType == Type.Reference) {
_param.translate(classGen, methodGen);
il.append(new INVOKESTATIC(cpg.addMethodref
(BASIS_LIBRARY_CLASS,
diff --git a/src/org/apache/xalan/xsltc/compiler/Number.java b/src/org/apache/xalan/xsltc/compiler/Number.java
index af99fe4..5435f27 100644
--- a/src/org/apache/xalan/xsltc/compiler/Number.java
+++ b/src/org/apache/xalan/xsltc/compiler/Number.java
@@ -129,23 +129,23 @@
}
}
else if (name.equals("format")) {
- _format = new AttributeValueTemplate(value, parser);
+ _format = new AttributeValueTemplate(value, parser, this);
_formatNeeded = true;
}
else if (name.equals("lang")) {
- _lang = new AttributeValueTemplate(value, parser);
+ _lang = new AttributeValueTemplate(value, parser, this);
_formatNeeded = true;
}
else if (name.equals("letter-value")) {
- _letterValue = new AttributeValueTemplate(value, parser);
+ _letterValue = new AttributeValueTemplate(value, parser, this);
_formatNeeded = true;
}
else if (name.equals("grouping-separator")) {
- _groupingSeparator = new AttributeValueTemplate(value, parser);
+ _groupingSeparator = new AttributeValueTemplate(value, parser, this);
_formatNeeded = true;
}
else if (name.equals("grouping-size")) {
- _groupingSize = new AttributeValueTemplate(value, parser);
+ _groupingSize = new AttributeValueTemplate(value, parser, this);
_formatNeeded = true;
}
}
diff --git a/src/org/apache/xalan/xsltc/compiler/Output.java b/src/org/apache/xalan/xsltc/compiler/Output.java
index 907b793..0fa71df 100644
--- a/src/org/apache/xalan/xsltc/compiler/Output.java
+++ b/src/org/apache/xalan/xsltc/compiler/Output.java
@@ -65,15 +65,16 @@
package org.apache.xalan.xsltc.compiler;
import java.util.Vector;
+import java.util.Properties;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.io.OutputStreamWriter;
+import javax.xml.transform.OutputKeys;
import org.apache.bcel.generic.*;
import org.apache.bcel.classfile.JavaClass;
import org.apache.xalan.xsltc.compiler.util.*;
-import org.apache.xalan.xsltc.runtime.TextOutput;
final class Output extends TopLevelElement {
@@ -97,7 +98,8 @@
// Some global constants
private final static String STRING_SIG = "Ljava/lang/String;";
- private final static String ONE_DOT_ZERO_STRING = "1.0";
+ private final static String XML_VERSION = "1.0";
+ private final static String HTML_VERSION = "4.0";
/**
* Displays the contents of this element (for debugging)
@@ -124,6 +126,7 @@
* Scans the attribute list for the xsl:output instruction
*/
public void parseContents(Parser parser) {
+ final Properties outputProperties = new Properties();
// Ask the parser if it wants this <xsl:output> element
parser.setOutput(this);
@@ -133,25 +136,30 @@
String attrib = null;
- // Get the output XML version - only version "1.0" should be used
+ // Get the output version
_version = getAttribute("version");
- if ((_version == null) || (_version.equals(Constants.EMPTYSTRING))) {
- _version = ONE_DOT_ZERO_STRING;
+ if (_version == null || _version.equals(Constants.EMPTYSTRING)) {
+ _version = null;
}
- if (!_version.equals(ONE_DOT_ZERO_STRING)) {
- ErrorMsg msg = new ErrorMsg(ErrorMsg.OUTPUT_VERSION_ERR, this);
- parser.reportError(Constants.WARNING, msg);
+ else {
+ outputProperties.setProperty(OutputKeys.VERSION, _version);
}
// Get the output method - "xml", "html", "text" or <qname>
_method = getAttribute("method");
- if (_method.equals(Constants.EMPTYSTRING)) _method = null;
- if (_method != null) _method = _method.toLowerCase();
+ if (_method.equals(Constants.EMPTYSTRING)) {
+ _method = null;
+ }
+ if (_method != null) {
+ _method = _method.toLowerCase();
+ outputProperties.setProperty(OutputKeys.METHOD, _method);
+ }
// Get the output encoding - any value accepted here
_encoding = getAttribute("encoding");
- if (_encoding.equals(Constants.EMPTYSTRING))
+ if (_encoding.equals(Constants.EMPTYSTRING)) {
_encoding = null;
+ }
else {
try {
OutputStreamWriter writer =
@@ -162,42 +170,104 @@
_encoding, this);
parser.reportError(Constants.WARNING, msg);
}
+ outputProperties.setProperty(OutputKeys.ENCODING, _encoding);
}
// Should the XML header be omitted - translate to true/false
attrib = getAttribute("omit-xml-declaration");
- if ((attrib != null) && (attrib.equals("yes"))) _omitHeader = true;
+ if (attrib != null && !attrib.equals(Constants.EMPTYSTRING)) {
+ if (attrib.equals("yes")) {
+ _omitHeader = true;
+ }
+ outputProperties.setProperty(OutputKeys.OMIT_XML_DECLARATION, attrib);
+ }
// Add 'standalone' decaration to output - use text as is
_standalone = getAttribute("standalone");
- if (_standalone.equals(Constants.EMPTYSTRING)) _standalone = null;
+ if (_standalone.equals(Constants.EMPTYSTRING)) {
+ _standalone = null;
+ }
+ else {
+ outputProperties.setProperty(OutputKeys.STANDALONE, _standalone);
+ }
// Get system/public identifiers for output DOCTYPE declaration
_doctypeSystem = getAttribute("doctype-system");
- if (_doctypeSystem.equals(Constants.EMPTYSTRING)) _doctypeSystem = null;
+ if (_doctypeSystem.equals(Constants.EMPTYSTRING)) {
+ _doctypeSystem = null;
+ }
+ else {
+ outputProperties.setProperty(OutputKeys.DOCTYPE_SYSTEM, _doctypeSystem);
+ }
+
+
_doctypePublic = getAttribute("doctype-public");
- if (_doctypePublic.equals(Constants.EMPTYSTRING)) _doctypePublic = null;
+ if (_doctypePublic.equals(Constants.EMPTYSTRING)) {
+ _doctypePublic = null;
+ }
+ else {
+ outputProperties.setProperty(OutputKeys.DOCTYPE_PUBLIC, _doctypePublic);
+ }
// Names the elements of whose text contents should be output as CDATA
_cdata = getAttribute("cdata-section-elements");
- if ((_cdata != null) && (_cdata.equals(Constants.EMPTYSTRING)))
+ if (_cdata != null && _cdata.equals(Constants.EMPTYSTRING)) {
_cdata = null;
+ }
+ else {
+ StringBuffer expandedNames = new StringBuffer();
+ StringTokenizer tokens = new StringTokenizer(_cdata);
+
+ // Make sure to store names in expanded form
+ while (tokens.hasMoreTokens()) {
+ expandedNames.append(parser.getQName(tokens.nextToken()).toString())
+ .append(' ');
+ }
+ _cdata = expandedNames.toString();
+
+ outputProperties.setProperty(OutputKeys.CDATA_SECTION_ELEMENTS, _cdata);
+ }
// Get the indent setting - only has effect for xml and html output
attrib = getAttribute("indent");
- if ((attrib != null) && (!attrib.equals(EMPTYSTRING))) {
- if (attrib.equals("yes")) _indent = true;
+ if (attrib != null && !attrib.equals(EMPTYSTRING)) {
+ if (attrib.equals("yes")) {
+ _indent = true;
+ }
+ outputProperties.setProperty(OutputKeys.INDENT, attrib);
}
- else if ((_method != null) && (_method.equals("html"))) {
+ else if (_method != null && _method.equals("html")) {
_indent = true;
}
- // Get the MIME type for the output file - we don't do anythign with it,
- // but our client may use it to specify a data transport type, etc.
+ // Get the MIME type for the output file
_mediaType = getAttribute("media-type");
- if (_mediaType.equals(Constants.EMPTYSTRING)) _mediaType = null;
+ if (_mediaType.equals(Constants.EMPTYSTRING)) {
+ _mediaType = null;
+ }
+ else {
+ outputProperties.setProperty(OutputKeys.MEDIA_TYPE, _mediaType);
+ }
- // parseChildren(parser); - the element is always empty
+ // Implied properties
+ if (_method != null) {
+ if (_method.equals("html")) {
+ if (_version == null) {
+ _version = HTML_VERSION;
+ }
+ if (_mediaType == null) {
+ _mediaType = "text/html";
+ }
+ }
+ else if (_method.equals("text")) {
+ if (_mediaType == null) {
+ _mediaType = "text/plain";
+ }
+ }
+ }
+
+ // Set output properties in current stylesheet
+ parser.getCurrentStylesheet().setOutputProperties(outputProperties);
}
/**
@@ -216,7 +286,7 @@
il.append(classGen.loadTranslet());
// Only update _version field if set and different from default
- if ((_version != null) && (!_version.equals(ONE_DOT_ZERO_STRING))) {
+ if ((_version != null) && (!_version.equals(XML_VERSION))) {
field = cpg.addFieldref(TRANSLET_CLASS, "_version", STRING_SIG);
il.append(DUP);
il.append(new PUSH(cpg, _version));
@@ -274,7 +344,7 @@
}
// Compile code to set output indentation on/off
- if (_indent ) {
+ if (_indent) {
field = cpg.addFieldref(TRANSLET_CLASS, "_indent", "Z");
il.append(DUP);
il.append(new PUSH(cpg, _indent));
@@ -286,6 +356,7 @@
int index = cpg.addMethodref(TRANSLET_CLASS,
"addCdataElement",
"(Ljava/lang/String;)V");
+
StringTokenizer tokens = new StringTokenizer(_cdata);
while (tokens.hasMoreTokens()) {
il.append(DUP);
diff --git a/src/org/apache/xalan/xsltc/compiler/ParentLocationPath.java b/src/org/apache/xalan/xsltc/compiler/ParentLocationPath.java
index adca196..cb52df0 100644
--- a/src/org/apache/xalan/xsltc/compiler/ParentLocationPath.java
+++ b/src/org/apache/xalan/xsltc/compiler/ParentLocationPath.java
@@ -216,14 +216,15 @@
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.PRECEDING && step == Axis.PARENT)) {
- final int incl = cpg.addMethodref(STEP_ITERATOR_CLASS,
+ final int incl = cpg.addMethodref(NODE_ITERATOR_BASE,
"includeSelf",
- "()"+NODE_ITERATOR_SIG);
+ "()" + NODE_ITERATOR_SIG);
il.append(new INVOKEVIRTUAL(incl));
}
}
diff --git a/src/org/apache/xalan/xsltc/compiler/ParentPattern.java b/src/org/apache/xalan/xsltc/compiler/ParentPattern.java
index 78f2053..4d92fbc 100644
--- a/src/org/apache/xalan/xsltc/compiler/ParentPattern.java
+++ b/src/org/apache/xalan/xsltc/compiler/ParentPattern.java
@@ -117,8 +117,6 @@
il.append(SWAP);
}
else if (_right instanceof StepPattern) {
- //!!! check this
-
il.append(DUP);
il.append(storeLocal);
@@ -129,6 +127,11 @@
}
else {
_right.translate(classGen, methodGen);
+
+ if (_right instanceof AncestorPattern) {
+ il.append(methodGen.loadDOM());
+ il.append(SWAP);
+ }
}
final int getParent = cpg.addInterfaceMethodref(DOM_INTF,
@@ -137,9 +140,9 @@
il.append(new INVOKEINTERFACE(getParent, 2));
final SyntaxTreeNode p = getParent();
- if ((p == null) ||
- (p instanceof Instruction) ||
- (p instanceof TopLevelElement)) {
+ if (p == null || p instanceof Instruction ||
+ p instanceof TopLevelElement)
+ {
_left.translate(classGen, methodGen);
}
else {
@@ -154,6 +157,15 @@
methodGen.removeLocalVariable(local);
+ /*
+ * If _right is an ancestor pattern, backpatch _left false
+ * list to the loop that searches for more ancestors.
+ */
+ if (_right instanceof AncestorPattern) {
+ final AncestorPattern ancestor = (AncestorPattern) _right;
+ _left.backPatchFalseList(ancestor.getLoopHandle()); // clears list
+ }
+
_trueList.append(_right._trueList.append(_left._trueList));
_falseList.append(_right._falseList.append(_left._falseList));
}
diff --git a/src/org/apache/xalan/xsltc/compiler/Parser.java b/src/org/apache/xalan/xsltc/compiler/Parser.java
index c4b2fd6..e6412d9 100644
--- a/src/org/apache/xalan/xsltc/compiler/Parser.java
+++ b/src/org/apache/xalan/xsltc/compiler/Parser.java
@@ -70,6 +70,7 @@
import java.net.URL;
import java.util.Vector;
import java.util.Hashtable;
+import java.util.Properties;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.StringTokenizer;
@@ -99,6 +100,7 @@
private Vector _warnings; // Contains all compilation errors
private Hashtable _instructionClasses; // Maps instructions to classes
+ private Hashtable _instructionAttrs;; // reqd and opt attrs
private Hashtable _qNames;
private Hashtable _namespaces;
private QName _useAttributeSets;
@@ -126,6 +128,7 @@
_qNames = new Hashtable(512);
_namespaces = new Hashtable();
_instructionClasses = new Hashtable();
+ _instructionAttrs = new Hashtable();
_variableScope = new Hashtable();
_template = null;
_errors = new Vector();
@@ -136,6 +139,7 @@
_currentImportPrecedence = 1;
initStdClasses();
+ initInstructionAttrs();
initExtClasses();
initSymbolTable();
@@ -166,6 +170,10 @@
return _output;
}
+ public Properties getOutputProperties() {
+ return getTopLevelStylesheet().getOutputProperties();
+ }
+
public void addVariable(Variable var) {
addVariableOrParam(var);
}
@@ -252,19 +260,34 @@
String namespace = null;
// Get the namespace uri from the symbol table
- if (prefix.equals("xmlns") == false) {
+ if (prefix.equals(XMLNS_PREFIX) == false) {
namespace = _symbolTable.lookupNamespace(prefix);
if (namespace == null) namespace = EMPTYSTRING;
}
return getQName(namespace, prefix, localname);
}
else {
- final String uri = _symbolTable.lookupNamespace(EMPTYSTRING);
+ final String uri = stringRep.equals(XMLNS_PREFIX) ? null
+ : _symbolTable.lookupNamespace(EMPTYSTRING);
return getQName(uri, null, stringRep);
}
}
public QName getQName(final String stringRep) {
+ return getQName(stringRep, true, false);
+ }
+
+ public QName getQNameIgnoreDefaultNs(final String stringRep) {
+ return getQName(stringRep, true, true);
+ }
+
+ public QName getQName(final String stringRep, boolean reportError) {
+ return getQName(stringRep, reportError, false);
+ }
+
+ private QName getQName(final String stringRep, boolean reportError,
+ boolean ignoreDefaultNs)
+ {
// parse and retrieve namespace
final int colon = stringRep.lastIndexOf(':');
if (colon != -1) {
@@ -273,9 +296,9 @@
String namespace = null;
// Get the namespace uri from the symbol table
- if (prefix.equals("xmlns") == false) {
+ if (prefix.equals(XMLNS_PREFIX) == 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);
@@ -285,13 +308,17 @@
return getQName(namespace, prefix, localname);
}
else {
- final String defURI = _symbolTable.lookupNamespace(EMPTYSTRING);
+ if (stringRep.equals(XMLNS_PREFIX)) {
+ ignoreDefaultNs = true;
+ }
+ final String defURI = ignoreDefaultNs ? null
+ : _symbolTable.lookupNamespace(EMPTYSTRING);
return getQName(defURI, null, stringRep);
}
}
public QName getQName(String namespace, String prefix, String localname) {
- if (namespace == null) {
+ if (namespace == null || namespace.equals(EMPTYSTRING)) {
QName name = (QName)_qNames.get(localname);
if (name == null) {
name = new QName(null, prefix, localname);
@@ -356,7 +383,11 @@
stylesheet.setSimplified();
stylesheet.addElement(element);
stylesheet.setAttributes(element.getAttributes());
- element.addPrefixMapping(EMPTYSTRING, EMPTYSTRING);
+
+ // Map the default NS if not already defined
+ if (element.lookupNamespace(EMPTYSTRING) == null) {
+ element.addPrefixMapping(EMPTYSTRING, EMPTYSTRING);
+ }
}
stylesheet.setParser(this);
return stylesheet;
@@ -567,6 +598,70 @@
return(external);
}
+ private void initAttrTable(String elementName, String[] attrs) {
+ _instructionAttrs.put(getQName(XSLT_URI, XSL, elementName),
+ attrs);
+ }
+
+ private void initInstructionAttrs() {
+ initAttrTable("template",
+ new String[] {"match", "name", "priority", "mode"});
+ initAttrTable("stylesheet",
+ new String[] {"id", "version", "extension-element-prefixes",
+ "exclude-result-prefixes"});
+ initAttrTable("transform",
+ new String[] {"id", "version", "extension-element-prefixes",
+ "exclude-result-prefixes"});
+ initAttrTable("text", new String[] {"disable-output-escaping"});
+ initAttrTable("if", new String[] {"test"});
+ initAttrTable("choose", new String[] {});
+ initAttrTable("when", new String[] {"test"});
+ initAttrTable("otherwise", new String[] {});
+ initAttrTable("for-each", new String[] {"select"});
+ initAttrTable("message", new String[] {"terminate"});
+ initAttrTable("number",
+ new String[] {"level", "count", "from", "value", "format", "lang",
+ "letter-value", "grouping-separator", "grouping-size"});
+ initAttrTable("comment", new String[] {});
+ initAttrTable("copy", new String[] {"use-attribute-sets"});
+ initAttrTable("copy-of", new String[] {"select"});
+ initAttrTable("param", new String[] {"name", "select"});
+ initAttrTable("with-param", new String[] {"name", "select"});
+ initAttrTable("variable", new String[] {"name", "select"});
+ initAttrTable("output",
+ new String[] {"method", "version", "encoding",
+ "omit-xml-declaration", "standalone", "doctype-public",
+ "doctype-system", "cdata-section-elements", "indent",
+ "media-type"});
+ initAttrTable("sort",
+ new String[] {"select", "order", "case-order", "lang", "data-type"});
+ initAttrTable("key", new String[] {"name", "match", "use"});
+ initAttrTable("fallback", new String[] {});
+ initAttrTable("attribute", new String[] {"name", "namespace"});
+ initAttrTable("attribute-set",
+ new String[] {"name", "use-attribute-sets"});
+ initAttrTable("value-of",
+ new String[] {"select", "disable-output-escaping"});
+ initAttrTable("element",
+ new String[] {"name", "namespace", "use-attribute-sets"});
+ initAttrTable("call-template", new String[] {"name"});
+ initAttrTable("apply-templates", new String[] {"select", "mode"});
+ initAttrTable("apply-imports", new String[] {});
+ initAttrTable("decimal-format",
+ new String[] {"name", "decimal-separator", "grouping-separator",
+ "infinity", "minus-sign", "NaN", "percent", "per-mille",
+ "zero-digit", "digit", "pattern-separator"});
+ initAttrTable("import", new String[] {"href"});
+ initAttrTable("include", new String[] {"href"});
+ initAttrTable("strip-space", new String[] {"elements"});
+ initAttrTable("preserve-space", new String[] {"elements"});
+ initAttrTable("processing-instruction", new String[] {"name"});
+ initAttrTable("namespace-alias",
+ new String[] {"stylesheet-prefix", "result-prefix"});
+ }
+
+
+
/**
* Initialize the _instructionClasses Hashtable, which maps XSL element
* names to Java classes in this package.
@@ -614,8 +709,8 @@
COMPILER_PACKAGE + '.' + className);
}
- public boolean elementSupported(QName qname) {
- return(_instructionClasses.get(qname) != null);
+ public boolean elementSupported(String namespace, String localName) {
+ return(_instructionClasses.get(getQName(namespace, XSL, localName)) != null);
}
public boolean functionSupported(String fname) {
@@ -645,7 +740,6 @@
MethodType R_D = new MethodType(Type.Real, Type.NodeSet);
MethodType R_O = new MethodType(Type.Real, Type.Reference);
MethodType I_I = new MethodType(Type.Int, Type.Int);
- MethodType J_J = new MethodType(Type.Lng, Type.Lng); //GTM,bug 3592
MethodType D_O = new MethodType(Type.NodeSet, Type.Reference);
MethodType D_V = new MethodType(Type.NodeSet, Type.Void);
MethodType D_S = new MethodType(Type.NodeSet, Type.String);
@@ -660,6 +754,7 @@
MethodType B_V = new MethodType(Type.Boolean, Type.Void);
MethodType B_B = new MethodType(Type.Boolean, Type.Boolean);
MethodType B_S = new MethodType(Type.Boolean, Type.String);
+ MethodType D_T = new MethodType(Type.NodeSet, Type.ResultTree);
MethodType R_RR = new MethodType(Type.Real, Type.Real, Type.Real);
MethodType I_II = new MethodType(Type.Int, Type.Int, Type.Int);
MethodType B_RR = new MethodType(Type.Boolean, Type.Real, Type.Real);
@@ -744,6 +839,9 @@
_symbolTable.addPrimop("normalize-space", S_S);
_symbolTable.addPrimop("system-property", S_S);
+ // Extensions
+ _symbolTable.addPrimop("nodeset", D_T);
+
// Operators +, -, *, /, % defined on real types.
_symbolTable.addPrimop("+", R_RR);
_symbolTable.addPrimop("-", R_RR);
@@ -782,7 +880,6 @@
// Unary minus.
_symbolTable.addPrimop("u-", R_R);
_symbolTable.addPrimop("u-", I_I);
- _symbolTable.addPrimop("u-", J_J); // GTM,bug 3592
}
public SymbolTable getSymbolTable() {
@@ -814,10 +911,15 @@
* until we have received all child elements of an unsupported element to
* see if any <xsl:fallback> elements exist.
*/
- public SyntaxTreeNode makeInstance(String uri, String prefix, String local){
+
+ private boolean versionIsOne = true;
+
+ public SyntaxTreeNode makeInstance(String uri, String prefix,
+ String local, Attributes attributes)
+ {
+ SyntaxTreeNode node = null;
QName qname = getQName(uri, prefix, local);
String className = (String)_instructionClasses.get(qname);
- SyntaxTreeNode node = null;
if (className != null) {
try {
@@ -825,11 +927,13 @@
node = (SyntaxTreeNode)clazz.newInstance();
node.setQName(qname);
node.setParser(this);
- if (_locator != null)
+ if (_locator != null) {
node.setLineNumber(_locator.getLineNumber());
+ }
if (node instanceof Stylesheet) {
_xsltc.setStylesheet((Stylesheet)node);
}
+ checkForSuperfluousAttributes(node, attributes);
}
catch (ClassNotFoundException e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.CLASS_NOT_FOUND_ERR, node);
@@ -884,6 +988,46 @@
}
/**
+ * checks the list of attributes against a list of allowed attributes
+ * for a particular element node.
+ */
+ private void checkForSuperfluousAttributes(SyntaxTreeNode node,
+ Attributes attrs)
+ {
+ QName qname = node.getQName();
+ boolean isStylesheet = (node instanceof Stylesheet);
+ String[] legal = (String[]) _instructionAttrs.get(qname);
+ if (versionIsOne && legal != null) {
+ int j;
+ final int n = attrs.getLength();
+
+ for (int i = 0; i < n; i++) {
+ final String attrQName = attrs.getQName(i);
+
+ if (isStylesheet && attrQName.equals("version")) {
+ versionIsOne = attrs.getValue(i).equals("1.0");
+ }
+
+ if (attrQName.startsWith("xml") ||
+ attrQName.indexOf(':') > 0) continue;
+
+ for (j = 0; j < legal.length; j++) {
+ if (attrQName.equalsIgnoreCase(legal[j])) {
+ break;
+ }
+ }
+ if (j == legal.length) {
+ final ErrorMsg err =
+ new ErrorMsg(ErrorMsg.ILLEGAL_ATTRIBUTE_ERR,
+ attrQName, node);
+ reportError(WARNING, err);
+ }
+ }
+ }
+ }
+
+
+ /**
* Parse an XPath expression:
* @parent - XSL element where the expression occured
* @exp - textual representation of the expression
@@ -944,7 +1088,7 @@
try {
_xpathParser.setScanner(new XPathLexer(new StringReader(text)));
- Symbol result = _xpathParser.parse(line);
+ Symbol result = _xpathParser.parse(expression, line);
if (result != null) {
final SyntaxTreeNode node = (SyntaxTreeNode)result.value;
if (node != null) {
@@ -957,14 +1101,12 @@
reportError(ERROR, new ErrorMsg(ErrorMsg.XPATH_PARSER_ERR,
expression, parent));
}
- catch (ClassCastException e) {
+ catch (Exception e) {
+ if (_xsltc.debug()) e.printStackTrace();
reportError(ERROR, new ErrorMsg(ErrorMsg.XPATH_PARSER_ERR,
expression, parent));
}
- catch (Exception e) {
- if (_xsltc.debug()) e.printStackTrace();
- // Intentional fall through
- }
+
// Return a dummy pattern (which is an expression)
SyntaxTreeNode.Dummy.setParser(this);
return SyntaxTreeNode.Dummy;
@@ -1072,7 +1214,9 @@
* 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);
}
@@ -1091,13 +1235,10 @@
String qname, Attributes attributes)
throws SAXException {
final int col = qname.lastIndexOf(':');
- final String prefix;
- if (col == -1)
- prefix = null;
- else
- prefix = qname.substring(0, col);
+ final String prefix = (col == -1) ? null : qname.substring(0, col);
- SyntaxTreeNode element = makeInstance(uri, prefix, localname);
+ SyntaxTreeNode element = makeInstance(uri, prefix,
+ localname, attributes);
if (element == null) {
ErrorMsg err = new ErrorMsg(ErrorMsg.ELEMENT_PARSE_ERR,
prefix+':'+localname);
diff --git a/src/org/apache/xalan/xsltc/compiler/Predicate.java b/src/org/apache/xalan/xsltc/compiler/Predicate.java
index 0d6c217..f57b23c 100644
--- a/src/org/apache/xalan/xsltc/compiler/Predicate.java
+++ b/src/org/apache/xalan/xsltc/compiler/Predicate.java
@@ -208,8 +208,8 @@
if (fexp instanceof KeyCall)
_canOptimize = false;
- //else if (fexp instanceof VariableRefBase)
- // _canOptimize = false;
+ else if (fexp instanceof VariableRefBase)
+ _canOptimize = false;
else if (fexp instanceof ParentLocationPath)
_canOptimize = false;
else if (fexp instanceof UnionPathExpr)
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 @@
// 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/QName.java b/src/org/apache/xalan/xsltc/compiler/QName.java
index 6eace10..1c1b1b0 100644
--- a/src/org/apache/xalan/xsltc/compiler/QName.java
+++ b/src/org/apache/xalan/xsltc/compiler/QName.java
@@ -75,24 +75,14 @@
_namespace = namespace;
_prefix = prefix;
_localname = localname;
- if ((namespace != null) && (!namespace.equals(Constants.EMPTYSTRING))) {
- _stringRep = namespace+':'+localname;
- }
- else {
- _stringRep = localname;
- }
+
+ _stringRep =
+ (namespace != null && !namespace.equals(Constants.EMPTYSTRING)) ?
+ (namespace + ':' + localname) : localname;
_hashCode = _stringRep.hashCode() + 19; // cached for speed
}
- public void clearDefaultNamespace() {
- if ((_prefix == null) || (_prefix.equals(Constants.EMPTYSTRING))) {
- _namespace = null;
- _stringRep = _localname;
- _hashCode = _stringRep.hashCode() + 19; // cached for speed
- }
- }
-
public void clearNamespace() {
_namespace = Constants.EMPTYSTRING;
}
@@ -106,7 +96,7 @@
}
public boolean equals(Object other) {
- return this == other;
+ return (this == other);
}
public String getLocalPart() {
@@ -126,6 +116,7 @@
}
public String dump() {
- return(new String("QName: "+_namespace+"("+_prefix+"):"+_localname));
+ return new String("QName: " + _namespace + "(" + _prefix + "):"
+ + _localname);
}
}
diff --git a/src/org/apache/xalan/xsltc/compiler/Sort.java b/src/org/apache/xalan/xsltc/compiler/Sort.java
index 383b1df..4269f8a 100644
--- a/src/org/apache/xalan/xsltc/compiler/Sort.java
+++ b/src/org/apache/xalan/xsltc/compiler/Sort.java
@@ -349,7 +349,7 @@
// Class initializer - void NodeSortRecord.<clinit>();
final InstructionList il = new InstructionList();
final CompareGenerator classInit =
- new CompareGenerator(ACC_PUBLIC | ACC_FINAL,
+ new CompareGenerator(ACC_PUBLIC | ACC_STATIC,
org.apache.bcel.generic.Type.VOID,
new org.apache.bcel.generic.Type[] { },
new String[] { },
diff --git a/src/org/apache/xalan/xsltc/compiler/Step.java b/src/org/apache/xalan/xsltc/compiler/Step.java
index 4d54224..265fe42 100644
--- a/src/org/apache/xalan/xsltc/compiler/Step.java
+++ b/src/org/apache/xalan/xsltc/compiler/Step.java
@@ -74,23 +74,28 @@
final class Step extends RelativeLocationPath {
- // This step's axis as defined in class Axis.
+ /**
+ * This step's axis as defined in class Axis.
+ */
private int _axis;
- // A vector of predicates (filters) defined on this step - may be null
+ /**
+ * A vector of predicates (filters) defined on this step - may be null
+ */
private Vector _predicates;
- // Some simple predicates can be handled by this class (and not by the
- // Predicate class) and will be removed from the above vector as they are
- // handled. We use this boolean to remember if we did have any predicates.
+ /**
+ * Some simple predicates can be handled by this class (and not by the
+ * Predicate class) and will be removed from the above vector as they are
+ * handled. We use this boolean to remember if we did have any predicates.
+ */
private boolean _hadPredicates = false;
- // Type of the node test.
+ /**
+ * Type of the node test.
+ */
private int _nodeType;
- /**
- * Constructor
- */
public Step(int axis, int nodeType, Vector predicates) {
_axis = axis;
_nodeType = nodeType;
@@ -156,16 +161,12 @@
* an element like <xsl:for-each> or <xsl:apply-templates>.
*/
private boolean hasParentPattern() {
- SyntaxTreeNode parent = getParent();
- if ((parent instanceof ParentPattern) ||
- (parent instanceof ParentLocationPath) ||
- (parent instanceof UnionPathExpr) ||
- (parent instanceof FilterParentPath))
- return(true);
- else
- return(false);
+ final SyntaxTreeNode parent = getParent();
+ return (parent instanceof ParentPattern ||
+ parent instanceof ParentLocationPath ||
+ parent instanceof UnionPathExpr ||
+ parent instanceof FilterParentPath);
}
-
/**
* Returns 'true' if this step has any predicates
@@ -214,24 +215,10 @@
// Special case for '.'
if (isAbbreviatedDot()) {
- if (hasParentPattern())
- _type = Type.NodeSet;
- else
- _type = Type.Node;
- }
- // Special case for '..'
- else if (isAbbreviatedDDot()) {
- _type = Type.NodeSet;
+ _type = (hasParentPattern()) ? Type.NodeSet : Type.Node;
}
else {
- // Special case for '@attr' with no parent or predicates
- if ((_axis == Axis.ATTRIBUTE) && (_nodeType!=NodeTest.ATTRIBUTE) &&
- (!hasParentPattern()) && (!_hadPredicates) && (!isPredicate())) {
- _type = Type.Node;
- }
- else {
- _type = Type.NodeSet;
- }
+ _type = Type.NodeSet;
}
// Type check all predicates (expressions applied to the step)
@@ -259,11 +246,8 @@
if ((_axis == Axis.ANCESTOR) || (_axis == Axis.ANCESTORORSELF) ||
(_axis == Axis.PRECEDING) || (_axis == Axis.PRECEDINGSIBLING)) {
- // Do not reverse nodes if we have a parent step that will reverse
- // the nodes for us.
- if (hasParentPattern()) return false;
- if (hasPredicates()) return false;
- if (_hadPredicates) return false;
+ // Do not reverse nodes if we had predicates
+ // if (_hadPredicates) return false;
// Check if this step occured under an <xsl:apply-templates> element
SyntaxTreeNode parent = this;
@@ -276,11 +260,11 @@
if (parent instanceof ApplyTemplates) return true;
if (parent instanceof ForEach) return true;
if (parent instanceof FilterParentPath) return true;
+ if (parent instanceof FilterExpr) return true;
+ if (parent instanceof WithParam) return true;
+ if (parent instanceof ValueOf) return true;
- // No not order node set if descendant of these elements:
- if (parent instanceof ValueOf) return false;
-
- } while (parent != null);
+ } while (parent != null && parent instanceof Instruction == false);
}
return false;
}
@@ -298,30 +282,23 @@
if (hasPredicates()) {
translatePredicates(classGen, methodGen);
+
+ // If needed, create a reverse iterator after compiling preds
+ if (_predicates.size() == 0) {
+ orderIterator(classGen, methodGen);
+ }
}
else {
// If it is an attribute but not '@*' or '@attr' with a parent
if ((_axis == Axis.ATTRIBUTE) &&
(_nodeType != NodeTest.ATTRIBUTE) && (!hasParentPattern())) {
- int node = cpg.addInterfaceMethodref(DOM_INTF,
- "getAttributeNode",
- "(II)I");
int iter = cpg.addInterfaceMethodref(DOM_INTF,
"getTypedAxisIterator",
"(II)"+NODE_ITERATOR_SIG);
- if (_type instanceof NodeType) {
- il.append(methodGen.loadDOM());
- il.append(new PUSH(cpg, _nodeType));
- il.append(methodGen.loadContextNode());
- il.append(new INVOKEINTERFACE(node, 3));
- }
- // If it is the case '@attr[P_1]...[P_k]'
- else if (_type instanceof NodeSetType) {
- il.append(methodGen.loadDOM());
- il.append(new PUSH(cpg, Axis.ATTRIBUTE));
- il.append(new PUSH(cpg, _nodeType));
- il.append(new INVOKEINTERFACE(iter, 3));
- }
+ il.append(methodGen.loadDOM());
+ il.append(new PUSH(cpg, Axis.ATTRIBUTE));
+ il.append(new PUSH(cpg, _nodeType));
+ il.append(new INVOKEINTERFACE(iter, 3));
return;
}
@@ -403,9 +380,14 @@
il.append(new PUSH(cpg, _axis));
il.append(new PUSH(cpg, _nodeType));
il.append(new INVOKEINTERFACE(ty, 3));
- orderIterator(classGen, methodGen);
+
break;
}
+
+ // If needed, create a reverse iterator
+ if (!_hadPredicates) {
+ orderIterator(classGen, methodGen);
+ }
}
}
@@ -508,22 +490,6 @@
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..5078287 100644
--- a/src/org/apache/xalan/xsltc/compiler/StepPattern.java
+++ b/src/org/apache/xalan/xsltc/compiler/StepPattern.java
@@ -133,14 +133,11 @@
else {
switch(_nodeType) {
case -1:
- return(-0.25);
+ return -0.5; // node()
case 0:
- return(0.0);
+ return 0.0;
default:
- if (_nodeType >= NodeTest.GTYPE)
- return(0.0);
- else
- return(-0.5);
+ return (_nodeType >= NodeTest.GTYPE) ? 0.0 : -0.5;
}
}
}
@@ -162,10 +159,12 @@
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..4d79fe4 100644
--- a/src/org/apache/xalan/xsltc/compiler/Stylesheet.java
+++ b/src/org/apache/xalan/xsltc/compiler/Stylesheet.java
@@ -66,6 +66,7 @@
import java.util.Vector;
import java.util.Hashtable;
+import java.util.Properties;
import java.util.Enumeration;
import java.util.StringTokenizer;
import java.util.Iterator;
@@ -117,6 +118,7 @@
private int _importPrecedence = 1;
private Mode _defaultMode;
private boolean _multiDocument = false;
+ private boolean _callsNodeset = false;
// All named key elements (needed by Key/IdPattern)
private Hashtable _keys = new Hashtable();
@@ -127,16 +129,22 @@
private SourceLoader _loader = null;
- private boolean _compileTemplatesAsMethods;
+ private boolean _templateInlining = true;
private boolean _forwardReference = false;
+ private Properties _outputProperties = null;
+
public void setForwardReference() {
_forwardReference = true;
}
- public void compileTemplatesAsMethods() {
- _compileTemplatesAsMethods = true;
+ public boolean getTemplateInlining() {
+ return _templateInlining;
+ }
+
+ public void setTemplateInlining(boolean flag) {
+ _templateInlining = flag;
}
public boolean isSimplified() {
@@ -147,6 +155,21 @@
_simplified = true;
}
+ public void setOutputProperty(String key, String value) {
+ if (_outputProperties == null) {
+ _outputProperties = new Properties();
+ }
+ _outputProperties.setProperty(key, value);
+ }
+
+ public void setOutputProperties(Properties props) {
+ _outputProperties = props;
+ }
+
+ public Properties getOutputProperties() {
+ return _outputProperties;
+ }
+
public void setMultiDocument(boolean flag) {
_multiDocument = flag;
}
@@ -155,6 +178,15 @@
return _multiDocument;
}
+ public void setCallsNodeset(boolean flag) {
+ if (flag) setMultiDocument(flag);
+ _callsNodeset = flag;
+ }
+
+ public boolean callsNodeset() {
+ return _callsNodeset;
+ }
+
public void numberFormattingUsed() {
_numberFormattingUsed = true;
}
@@ -194,8 +226,9 @@
public boolean checkForLoop(String systemId) {
// Return true if this stylesheet includes/imports itself
- if (_systemId.equals(systemId))
+ if (_systemId != null && _systemId.equals(systemId)) {
return true;
+ }
// Then check with any stylesheets that included/imported this one
if (_parentStylesheet != null)
return _parentStylesheet.checkForLoop(systemId);
@@ -284,7 +317,6 @@
super.addPrefixMapping(prefix, uri);
}
-
/**
* Store extension URIs
*/
@@ -308,8 +340,10 @@
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);
@@ -399,9 +433,10 @@
parser.getSymbolTable().setCurrentNode(child);
child.parseContents(parser);
}
+
// All template code should be compiled as methods if the
// <xsl:apply-imports/> element was ever used in this stylesheet
- if (_compileTemplatesAsMethods && (child instanceof Template)) {
+ if (!_templateInlining && (child instanceof Template)) {
Template template = (Template)child;
String name = "template$dot$"+template.getPosition();
template.setName(parser.getQName(name));
@@ -692,23 +727,45 @@
return("("+DOM_INTF_SIG+NODE_ITERATOR_SIG+TRANSLET_OUTPUT_SIG+")V");
}
-
+ /**
+ * This method returns a vector with variables in the order in
+ * which they are to be compiled. The order is determined by the
+ * dependencies between them and the order in which they were defined
+ * in the stylesheet. The first step is to close the input vector under
+ * the dependence relation (this is usually needed when variables are
+ * defined inside other variables in a RTF).
+ */
private Vector resolveReferences(Vector input) {
+
+ // Make sure that the vector 'input' is closed
+ for (int i = 0; i < input.size(); i++) {
+ final VariableBase var = (VariableBase) input.elementAt(i);
+ final Vector dep = var.getDependencies();
+ final int depSize = (dep != null) ? dep.size() : 0;
+
+ for (int j = 0; j < depSize; j++) {
+ final VariableBase depVar = (VariableBase) dep.elementAt(j);
+ if (!input.contains(depVar)) {
+ input.addElement(depVar);
+ }
+ }
+ }
+
+ /* DEBUG CODE - INGORE
+ for (int i = 0; i < input.size(); i++) {
+ final VariableBase var = (VariableBase) input.elementAt(i);
+ System.out.println("var = " + var);
+ }
+ System.out.println("=================================");
+ */
+
Vector result = new Vector();
-
- int zeroDep = 0;
-
while (input.size() > 0) {
boolean changed = false;
for (int i = 0; i < input.size(); ) {
final VariableBase var = (VariableBase)input.elementAt(i);
final Vector dep = var.getDependencies();
- if (dep == null) {
- result.insertElementAt(var, zeroDep++);
- input.remove(i);
- changed = true;
- }
- else if (result.containsAll(dep)) {
+ if (dep == null || result.containsAll(dep)) {
result.addElement(var);
input.remove(i);
changed = true;
@@ -717,6 +774,7 @@
i++;
}
}
+
// If nothing was changed in this pass then we have a circular ref
if (!changed) {
ErrorMsg err = new ErrorMsg(ErrorMsg.CIRCULAR_VARIABLE_ERR,
@@ -725,7 +783,16 @@
return(result);
}
}
- return(result);
+
+ /* DEBUG CODE - INGORE
+ System.out.println("=================================");
+ for (int i = 0; i < result.size(); i++) {
+ final VariableBase var = (VariableBase) result.elementAt(i);
+ System.out.println("var = " + var);
+ }
+ */
+
+ return result;
}
/**
@@ -878,6 +945,18 @@
"("+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 +975,6 @@
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..4575744 100644
--- a/src/org/apache/xalan/xsltc/compiler/SymbolTable.java
+++ b/src/org/apache/xalan/xsltc/compiler/SymbolTable.java
@@ -85,12 +85,12 @@
private Hashtable _excludedURI = null;
private Hashtable _decimalFormats = null;
- public DecimalFormatting getDecimalFormatting(String name) {
+ public DecimalFormatting getDecimalFormatting(QName name) {
if (_decimalFormats == null) return null;
return((DecimalFormatting)_decimalFormats.get(name));
}
- public void addDecimalFormatting(String name, DecimalFormatting symbols) {
+ public void addDecimalFormatting(QName name, DecimalFormatting symbols) {
if (_decimalFormats == null) _decimalFormats = new Hashtable();
_decimalFormats.put(name, symbols);
}
@@ -105,14 +105,12 @@
public Template addTemplate(Template template) {
final QName name = template.getName();
- name.clearDefaultNamespace();
if (_templates == null) _templates = new Hashtable();
return (Template)_templates.put(name, template);
}
public Template lookupTemplate(QName name) {
if (_templates == null) return null;
- name.clearDefaultNamespace();
return (Template)_templates.get(name);
}
@@ -262,11 +260,10 @@
* 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..322781c 100644
--- a/src/org/apache/xalan/xsltc/compiler/SyntaxTreeNode.java
+++ b/src/org/apache/xalan/xsltc/compiler/SyntaxTreeNode.java
@@ -193,18 +193,16 @@
* @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);
}
/**
@@ -554,10 +552,11 @@
* @param methodGen BCEL Java method generator
*/
protected void compileResultTree(ClassGenerator classGen,
- MethodGenerator methodGen) {
-
+ MethodGenerator methodGen)
+ {
final ConstantPoolGen cpg = classGen.getConstantPool();
final InstructionList il = methodGen.getInstructionList();
+ final Stylesheet stylesheet = classGen.getStylesheet();
// Save the current handler base on the stack
il.append(methodGen.loadHandler());
@@ -602,13 +601,42 @@
il.append(new NEW(cpg.addClass(DOM_ADAPTER_CLASS)));
il.append(new DUP_X1());
il.append(SWAP);
- // Give the DOM adapter an empty type mapping to start with.
- // Type mapping is expensive and will only be done when casting
- // a result tree fragment to a node-set.
- il.append(new ICONST(0));
- il.append(new ANEWARRAY(cpg.addClass(STRING)));
- il.append(DUP);
- il.append(new INVOKESPECIAL(index)); // leave DOMAdapter on stack
+
+ /*
+ * Give the DOM adapter an empty type mapping if the nodeset
+ * extension function is never called.
+ */
+ if (!stylesheet.callsNodeset()) {
+ il.append(new ICONST(0));
+ il.append(new ANEWARRAY(cpg.addClass(STRING)));
+ il.append(DUP);
+ il.append(new INVOKESPECIAL(index));
+ }
+ else {
+ // Push name arrays on the stack
+ il.append(ALOAD_0);
+ il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
+ NAMES_INDEX,
+ NAMES_INDEX_SIG)));
+ il.append(ALOAD_0);
+ il.append(new GETFIELD(cpg.addFieldref(TRANSLET_CLASS,
+ NAMESPACE_INDEX,
+ NAMESPACE_INDEX_SIG)));
+
+ // Initialized DOM adapter
+ il.append(new INVOKESPECIAL(index));
+
+ // Add DOM adapter to MultiDOM class by calling addDOMAdapter()
+ il.append(DUP);
+ il.append(methodGen.loadDOM());
+ il.append(new CHECKCAST(cpg.addClass(classGen.getDOMClass())));
+ il.append(SWAP);
+ index = cpg.addMethodref(MULTI_DOM_CLASS,
+ "addDOMAdapter",
+ "(" + DOM_ADAPTER_SIG + ")I");
+ il.append(new INVOKEVIRTUAL(index));
+ il.append(POP); // ignore mask returned by addDOMAdapter
+ }
}
// Restore old handler base from stack
diff --git a/src/org/apache/xalan/xsltc/compiler/Template.java b/src/org/apache/xalan/xsltc/compiler/Template.java
index 6191e9e..07b6186 100644
--- a/src/org/apache/xalan/xsltc/compiler/Template.java
+++ b/src/org/apache/xalan/xsltc/compiler/Template.java
@@ -245,11 +245,11 @@
_stylesheet = super.getStylesheet();
if (name.length() > 0) {
- _name = parser.getQName(name);
+ _name = parser.getQNameIgnoreDefaultNs(name);
}
if (mode.length() > 0) {
- _mode = parser.getQName(mode);
+ _mode = parser.getQNameIgnoreDefaultNs(mode);
}
if (match.length() > 0) {
diff --git a/src/org/apache/xalan/xsltc/compiler/TestSeq.java b/src/org/apache/xalan/xsltc/compiler/TestSeq.java
index 2f4b644..0ea54cb 100644
--- a/src/org/apache/xalan/xsltc/compiler/TestSeq.java
+++ b/src/org/apache/xalan/xsltc/compiler/TestSeq.java
@@ -73,18 +73,18 @@
import org.apache.bcel.generic.*;
import org.apache.xalan.xsltc.compiler.util.*;
+/**
+ * A test sequence is a sequence of patterns that
+ *
+ * (1) occured in templates in the same mode
+ * (2) share the same kernel node type (such as A/B and C/C/B).
+ *
+ * A test sequence may have a default template, which will be run if
+ * none of the patterns do not match. This template is always a template
+ * that matches solely on the shared kernel node type.
+ */
final class TestSeq {
- /*
- * A test sequence is a sequence of patterns that
- *
- * (1) occured in templates in the same mode
- * (2) share the same kernel node type (such as A/B and C/C/B).
- *
- * A test sequence may have a default template, which will be run if
- * none of the patterns do not match. This template is always a template
- * that matches solely on the shared kernel node type.
- */
private Vector _patterns = null; // all patterns
private Mode _mode = null; // the shared mode
private Template _default = null; // the default template
@@ -107,6 +107,7 @@
public double getPriority() {
double prio = (0 - Double.MAX_VALUE);
final int count = _patterns.size();
+
for (int i = 0; i < count; i++) {
final Pattern pattern = (Pattern)_patterns.elementAt(i);
final Template template = pattern.getTemplate();
@@ -127,6 +128,7 @@
public int getPosition() {
int pos = Integer.MIN_VALUE;
final int count = _patterns.size();
+
for (int i = 0; i < count; i++) {
final Pattern pattern = (Pattern)_patterns.elementAt(i);
final Template template = pattern.getTemplate();
@@ -144,7 +146,7 @@
* Reduce the patterns in this test sequence to exclude the shared
* kernel node type. After the switch() in the translet's applyTemplates()
* we already know that we have a hit for the kernel node type, we only
- * have the check the rest of the pattens.
+ * have the check the rest of the pattern.
*/
public void reduce() {
final Vector newPatterns = new Vector();
diff --git a/src/org/apache/xalan/xsltc/compiler/Text.java b/src/org/apache/xalan/xsltc/compiler/Text.java
index aa07fe9..93b1689 100644
--- a/src/org/apache/xalan/xsltc/compiler/Text.java
+++ b/src/org/apache/xalan/xsltc/compiler/Text.java
@@ -126,7 +126,12 @@
parseChildren(parser);
if (_text == null) {
- _ignore = true;
+ if (_textElement) {
+ _text = EMPTYSTRING;
+ }
+ else {
+ _ignore = true;
+ }
}
else if (_textElement) {
if (_text.length() == 0) _ignore = true;
@@ -162,35 +167,27 @@
// Turn off character escaping if so is wanted.
final int esc = cpg.addInterfaceMethodref(OUTPUT_HANDLER,
"setEscaping", "(Z)Z");
- // set escaping value in output handler
- if (_escaping) {
- il.append(methodGen.loadHandler());
- il.append(new PUSH(cpg,true));
- il.append(new INVOKEINTERFACE(esc, 2));
- } else {
+ if (!_escaping) {
il.append(methodGen.loadHandler());
il.append(new PUSH(cpg, false));
il.append(new INVOKEINTERFACE(esc, 2));
}
- final int toCharArr = cpg.addMethodref("java/lang/String",
- "toCharArray", "()[C");
final int characters = cpg.addInterfaceMethodref(OUTPUT_HANDLER,
"characters",
- "([CII)V");
+ "(" + STRING_SIG + ")V");
il.append(methodGen.loadHandler());
il.append(new PUSH(cpg, _text));
- il.append(new INVOKEVIRTUAL(toCharArr));
- il.append(new ICONST(0));
- il.append(new PUSH(cpg, _text.length()));
- il.append(new INVOKEINTERFACE(characters, 4));
+ il.append(new INVOKEINTERFACE(characters, 2));
// Restore character escaping setting to whatever it was.
// Note: setEscaping(bool) returns the original (old) value
- il.append(methodGen.loadHandler());
- il.append(SWAP);
- il.append(new INVOKEINTERFACE(esc, 2));
- il.append(POP);
+ if (!_escaping) {
+ il.append(methodGen.loadHandler());
+ il.append(SWAP);
+ il.append(new INVOKEINTERFACE(esc, 2));
+ il.append(POP);
+ }
}
translateContents(classGen, methodGen);
}
diff --git a/src/org/apache/xalan/xsltc/compiler/UnresolvedRef.java b/src/org/apache/xalan/xsltc/compiler/UnresolvedRef.java
index 276a87b..baa8cc6 100644
--- a/src/org/apache/xalan/xsltc/compiler/UnresolvedRef.java
+++ b/src/org/apache/xalan/xsltc/compiler/UnresolvedRef.java
@@ -119,10 +119,10 @@
ErrorMsg err = new ErrorMsg(ErrorMsg.CIRCULAR_VARIABLE_ERR,
name, this);
}
- if ((_ref = resolve(getParser(), stable)) != null)
- return(_ref.typeCheck(stable));
- else
- throw new TypeCheckError(reportError());
+ if ((_ref = resolve(getParser(), stable)) != null) {
+ return (_type = _ref.typeCheck(stable));
+ }
+ throw new TypeCheckError(reportError());
}
public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
@@ -131,4 +131,9 @@
else
reportError();
}
+
+ public String toString() {
+ return "unresolved-ref()";
+ }
+
}
diff --git a/src/org/apache/xalan/xsltc/compiler/UseAttributeSets.java b/src/org/apache/xalan/xsltc/compiler/UseAttributeSets.java
index abe1e59..42c1a64 100644
--- a/src/org/apache/xalan/xsltc/compiler/UseAttributeSets.java
+++ b/src/org/apache/xalan/xsltc/compiler/UseAttributeSets.java
@@ -99,7 +99,8 @@
if ((setNames != null) && (!setNames.equals(Constants.EMPTYSTRING))) {
final StringTokenizer tokens = new StringTokenizer(setNames);
while (tokens.hasMoreTokens()) {
- final QName qname = getParser().getQName(tokens.nextToken());
+ final QName qname =
+ getParser().getQNameIgnoreDefaultNs(tokens.nextToken());
_sets.add(qname);
}
}
diff --git a/src/org/apache/xalan/xsltc/compiler/VariableBase.java b/src/org/apache/xalan/xsltc/compiler/VariableBase.java
index 5a8bd04..e10c511 100644
--- a/src/org/apache/xalan/xsltc/compiler/VariableBase.java
+++ b/src/org/apache/xalan/xsltc/compiler/VariableBase.java
@@ -125,8 +125,12 @@
*
*/
public void addDependency(VariableBase other) {
- if (_dependencies == null) _dependencies = new Vector();
- _dependencies.addElement(other);
+ if (_dependencies == null) {
+ _dependencies = new Vector();
+ }
+ if (!_dependencies.contains(other)) {
+ _dependencies.addElement(other);
+ }
}
/**
@@ -227,7 +231,6 @@
*/
public void setName(QName name) {
_name = name;
- _name.clearDefaultNamespace();
_variable = Util.escape(name.getLocalPart());
}
@@ -247,7 +250,7 @@
if (name == null) name = EMPTYSTRING;
if (name.length() > 0)
- setName(parser.getQName(name));
+ setName(parser.getQNameIgnoreDefaultNs(name));
else
reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "name");
@@ -260,6 +263,10 @@
select = getAttribute("select");
if (select.length() > 0) {
_select = getParser().parseExpression(this, "select", null);
+ if (_select.isDummy()) {
+ reportError(this, parser, ErrorMsg.REQUIRED_ATTR_ERR, "select");
+ return;
+ }
}
// Children must be parsed first -> static scoping
diff --git a/src/org/apache/xalan/xsltc/compiler/When.java b/src/org/apache/xalan/xsltc/compiler/When.java
index 825a1e3..d2e4250 100644
--- a/src/org/apache/xalan/xsltc/compiler/When.java
+++ b/src/org/apache/xalan/xsltc/compiler/When.java
@@ -90,13 +90,12 @@
public void parseContents(Parser parser) {
_test = parser.parseExpression(this, "test", null);
- if (_test instanceof ElementAvailableCall) {
- ElementAvailableCall call = (ElementAvailableCall)_test;
- _ignore = !call.getResult();
- }
- if (_test instanceof FunctionAvailableCall) {
- FunctionAvailableCall call = (FunctionAvailableCall)_test;
- _ignore = !call.getResult();
+
+ // Ignore xsl:if when test is false (function-available() and
+ // element-available())
+ Object result = _test.evaluateAtCompileTime();
+ if (result != null && result instanceof Boolean) {
+ _ignore = !((Boolean) result).booleanValue();
}
parseChildren(parser);
diff --git a/src/org/apache/xalan/xsltc/compiler/XSLTC.java b/src/org/apache/xalan/xsltc/compiler/XSLTC.java
index 4baf1ed..988f6c7 100644
--- a/src/org/apache/xalan/xsltc/compiler/XSLTC.java
+++ b/src/org/apache/xalan/xsltc/compiler/XSLTC.java
@@ -67,9 +67,10 @@
package org.apache.xalan.xsltc.compiler;
import java.io.*;
+import java.util.Set;
import java.util.Vector;
import java.util.Hashtable;
-import java.util.Set;
+import java.util.Properties;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Enumeration;
@@ -139,7 +140,9 @@
private int _outputType = FILE_OUTPUT; // by default
private Vector _classes;
+ private boolean _callsNodeset = false;
private boolean _multiDocument = false;
+ private boolean _templateInlining = true;
/**
* XSLTC compiler constructor
@@ -163,6 +166,13 @@
}
/**
+ * Only for user by the internal TrAX implementation.
+ */
+ public Properties getOutputProperties() {
+ return _parser.getOutputProperties();
+ }
+
+ /**
* Initializes the compiler to compile a new stylesheet
*/
public void init() {
@@ -207,6 +217,16 @@
}
/**
+ * Set a flag indicating if templates are to be inlined or not. The
+ * default is to do inlining, but this causes problems when the
+ * stylesheets have a large number of templates (e.g. branch targets
+ * exceeding 64K or a length of a method exceeding 64K).
+ */
+ public void setTemplateInlining(boolean templateInlining) {
+ _templateInlining = templateInlining;
+ }
+
+ /**
* Set the parameters to use to locate the correct <?xml-stylesheet ...?>
* processing instruction in the case where the input document to the
* compiler (and parser) is an XML document.
@@ -311,12 +331,15 @@
_stylesheet.setSourceLoader(_loader);
_stylesheet.setSystemId(systemId);
_stylesheet.setParentStylesheet(null);
+ _stylesheet.setTemplateInlining(_templateInlining);
_parser.setCurrentStylesheet(_stylesheet);
+
// Create AST under the Stylesheet element (parse & type-check)
_parser.createAST(_stylesheet);
}
// Generate the bytecodes and output the translet class(es)
if ((!_parser.errorsFound()) && (_stylesheet != null)) {
+ _stylesheet.setCallsNodeset(_callsNodeset);
_stylesheet.setMultiDocument(_multiDocument);
_stylesheet.translate();
}
@@ -435,7 +458,6 @@
_parser.printWarnings();
}
-
/**
* This method is called by the XPathParser when it encounters a call
* to the document() function. Affects the DOM used by the translet.
@@ -449,6 +471,19 @@
}
/**
+ * This method is called by the XPathParser when it encounters a call
+ * to the nodeset() extension function. Implies multi document.
+ */
+ protected void setCallsNodeset(boolean flag) {
+ if (flag) setMultiDocument(flag);
+ _callsNodeset = flag;
+ }
+
+ public boolean callsNodeset() {
+ return _callsNodeset;
+ }
+
+ /**
* Set the class name for the generated translet. This class name is
* overridden if multiple stylesheets are compiled in one go using the
* compile(Vector urls) method.
@@ -653,7 +688,10 @@
try {
switch (_outputType) {
case FILE_OUTPUT:
- clazz.dump(getOutputFile(clazz.getClassName()));
+ clazz.dump(
+ new BufferedOutputStream(
+ new FileOutputStream(
+ getOutputFile(clazz.getClassName()))));
break;
case JAR_OUTPUT:
_classes.addElement(clazz);
@@ -685,7 +723,7 @@
// create the manifest
final Manifest manifest = new Manifest();
final java.util.jar.Attributes atrs = manifest.getMainAttributes();
- atrs.put(java.util.jar.Attributes.Name.MANIFEST_VERSION,"1.0");
+ atrs.put(java.util.jar.Attributes.Name.MANIFEST_VERSION,"1.1");
final Map map = manifest.getEntries();
// create manifest
diff --git a/src/org/apache/xalan/xsltc/compiler/XslAttribute.java b/src/org/apache/xalan/xsltc/compiler/XslAttribute.java
index f6e8b6e..96f64f9 100644
--- a/src/org/apache/xalan/xsltc/compiler/XslAttribute.java
+++ b/src/org/apache/xalan/xsltc/compiler/XslAttribute.java
@@ -73,10 +73,9 @@
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 @@
* Parses the attribute's contents. Special care taken for namespaces.
*/
public void parseContents(Parser parser) {
-
- final SymbolTable stable = parser.getSymbolTable();
- String namespace = getAttribute("namespace");
- String name = getAttribute("name");
- QName qname = parser.getQName(name);
- final String prefix = qname.getPrefix();
boolean generated = false;
+ final SymbolTable stable = parser.getSymbolTable();
- if ((prefix != null) && (prefix.equals("xmlns"))) {
+ String name = getAttribute("name");
+ String namespace = getAttribute("namespace");
+ QName qname = parser.getQName(name, false);
+ final String prefix = qname.getPrefix();
+
+ if ((prefix != null) && (prefix.equals(XMLNS_PREFIX))) {
reportError(this, parser, ErrorMsg.ILLEGAL_ATTR_NAME_ERR, name);
return;
}
@@ -118,11 +117,13 @@
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 @@
}
// 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);
+ _namespace = new AttributeValueTemplate(namespace, parser, this);
}
// 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)
- _namespace = new AttributeValueTemplate(namespace, parser);
+ if (namespace != null) {
+ _namespace = new AttributeValueTemplate(namespace, parser, this);
+ }
}
// 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 @@
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 @@
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..6f3df54 100644
--- a/src/org/apache/xalan/xsltc/compiler/XslElement.java
+++ b/src/org/apache/xalan/xsltc/compiler/XslElement.java
@@ -74,10 +74,11 @@
final class XslElement extends Instruction {
- private AttributeValue _name; // name treated as AVT (7.1.3)
- private AttributeValueTemplate _namespace = null;
private String _prefix;
private boolean _ignore = false;
+ private boolean _isLiteralName = true;
+ private AttributeValueTemplate _name;
+ private AttributeValueTemplate _namespace;
/**
* Displays the contents of the element
@@ -89,87 +90,124 @@
}
/**
- * Parses the element's contents. Special care taken for namespaces.
- * TODO: The namespace attribute that specifies the namespace to use
- * for the element is an attribute value template and not a string
- * constant. This means that we do not know what namespace is used
- * before runtime. This causes a problem with the way output namespaces
- * are handled at compile-time. We use a shortcut in this method to get
- * around the problem by treating the namaspace attribute as a constant.
- * (Yes, I know this is a hack, bad, bad, bad.)
+ * This method is now deprecated. The new implemation of this class
+ * never declares the default NS.
*/
- public void parseContents(Parser parser) {
+ public boolean declaresDefaultNS() {
+ return false;
+ }
+ /**
+ * Checks if <param>str</param> is a literal (i.e. not an AVT) or not.
+ */
+ private boolean isLiteral(String str) {
+ final int length = str.length();
+ for (int i = 0; i < length; i++) {
+ if (str.charAt(i) == '{' && str.charAt(i + 1) != '{') {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Simple check to determine if qname is legal. If it returns false
+ * then <param>str</param> is illegal; if it returns true then
+ * <param>str</param> may or may not be legal.
+ */
+ private boolean isLegalName(String str) {
+ if (str.indexOf(' ') > -1) {
+ return false;
+ }
+ final int colon = str.indexOf(':');
+ if (colon == 0 || colon == str.length() - 1) {
+ return false;
+ }
+ final char first = str.charAt(0);
+ if (!Character.isLetter(first) && first != '_') {
+ return false;
+ }
+ return true;
+ }
+
+ public void parseContents(Parser parser) {
final SymbolTable stable = parser.getSymbolTable();
- // Get the "name" attribute of the <xsl:element> element
+ // Handle the 'name' attribute
String name = getAttribute("name");
- if ((name == null) || (name.equals(EMPTYSTRING))) {
+ if (name == EMPTYSTRING) {
ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_ELEM_NAME_ERR,
name, this);
parser.reportError(WARNING, msg);
- _ignore = true; // Ignore the element if the QName is invalid
+ parseChildren(parser);
+ _ignore = true; // Ignore the element if the QName is invalid
return;
}
- // Try to construct a QName and then get the prefix and local part
- QName qname = parser.getQNameSafe(name);
- String prefix = qname.getPrefix();
- String local = qname.getLocalPart();
-
- // First try to get the namespace URI from the "namespace" attribute
+ // Get namespace attribute
String namespace = getAttribute("namespace");
- // Then try to get it from the "name" attribute QName prefix
- if (!hasAttribute("namespace")) {
- // We are supposed to use the default namespace URI if the QName
- // from the "name" attribute is not prefixed, so check that first
- if (prefix == null) prefix = EMPTYSTRING;
- // Then look up the URI that is in scope for the prefix
- namespace = lookupNamespace(prefix);
- // Signal error if the prefix does not map to any namespace URI
- if (namespace == null) {
- ErrorMsg err = new ErrorMsg(ErrorMsg.NAMESPACE_UNDEF_ERR,
- prefix, this);
- parser.reportError(WARNING, err);
+ // Optimize compilation when name is known at compile time
+ _isLiteralName = isLiteral(name);
+ if (_isLiteralName) {
+ if (!isLegalName(name)) {
+ ErrorMsg msg = new ErrorMsg(ErrorMsg.ILLEGAL_ELEM_NAME_ERR,
+ name, this);
+ parser.reportError(WARNING, msg);
parseChildren(parser);
- _ignore = true; // Ignore the element if prefix is undeclared
+ _ignore = true; // Ignore the element if the QName is invalid
return;
}
- _namespace = new AttributeValueTemplate(namespace, parser);
- _prefix = prefix;
+
+ final QName qname = parser.getQNameSafe(name);
+ String prefix = qname.getPrefix();
+ String local = qname.getLocalPart();
+
+ if (prefix == null) {
+ prefix = EMPTYSTRING;
+ }
+
+ if (!hasAttribute("namespace")) {
+ namespace = lookupNamespace(prefix);
+ if (namespace == null) {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.NAMESPACE_UNDEF_ERR,
+ prefix, this);
+ parser.reportError(WARNING, err);
+ parseChildren(parser);
+ _ignore = true; // Ignore the element if prefix is undeclared
+ return;
+ }
+ _prefix = prefix;
+ _namespace = (namespace == EMPTYSTRING) ? null :
+ new AttributeValueTemplate(namespace, parser, this);
+ }
+ else {
+ if (prefix == EMPTYSTRING) {
+ if (isLiteral(namespace)) {
+ prefix = lookupPrefix(namespace);
+ if (prefix == null) {
+ prefix = stable.generateNamespacePrefix();
+ }
+ }
+
+ // Prepend prefix to local name
+ final StringBuffer newName = new StringBuffer(prefix);
+ if (prefix != EMPTYSTRING) {
+ newName.append(':');
+ }
+ name = newName.append(local).toString();
+ }
+ _prefix = prefix;
+ _namespace = new AttributeValueTemplate(namespace, parser, this);
+ }
}
- // Check if this element belongs in a specific namespace
else {
- // Get the namespace requested by the xsl:element
- _namespace = new AttributeValueTemplate(namespace, parser);
- // Get the current prefix for that namespace (if any)
- _prefix = lookupPrefix(namespace);
- // Is it the default namespace?
- if ((_prefix = prefix) == null) _prefix = EMPTYSTRING;
-
- // Construct final element QName
- if (_prefix == EMPTYSTRING)
- name = qname.getLocalPart();
- else
- name = _prefix+":"+qname.getLocalPart();
+ _namespace = (namespace == EMPTYSTRING) ? null :
+ new AttributeValueTemplate(namespace, parser, this);
}
- _name = AttributeValue.create(this, name, parser);
+ _name = new AttributeValueTemplate(name, parser, this);
- // Next check that the local part of the QName is legal (no whitespace)
- if (_name instanceof SimpleAttributeValue) {
- if (local.equals(EMPTYSTRING) || (local.indexOf(' ') > -1)) {
- ErrorMsg err = new ErrorMsg(ErrorMsg.ILLEGAL_ELEM_NAME_ERR,
- local, this);
- parser.reportError(WARNING, err);
- parseChildren(parser);
- _ignore = true; // Ignore the element if local part is invalid
- return;
- }
- }
-
- // Handle the 'use-attribute-sets' attribute
final String useSets = getAttribute("use-attribute-sets");
if (useSets.length() > 0) {
setFirstElement(new UseAttributeSets(useSets, parser));
@@ -184,34 +222,30 @@
public Type typeCheck(SymbolTable stable) throws TypeCheckError {
if (!_ignore) {
_name.typeCheck(stable);
- if (_namespace != null)
+ if (_namespace != null) {
_namespace.typeCheck(stable);
+ }
}
typeCheckContents(stable);
return Type.Void;
}
/**
- * Compiles code that emits the element with the necessary namespace
- * definitions. The element itself is ignored if the element definition
- * was in any way erronous, but the child nodes are still processed.
- * See the overriden translateContents() method as well.
+ * This method is called when the name of the element is known at compile time.
+ * In this case, there is no need to inspect the element name at runtime to
+ * determine if a prefix exists, needs to be generated, etc.
*/
- public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
+ public void translateLiteral(ClassGenerator classGen, MethodGenerator methodGen) {
final ConstantPoolGen cpg = classGen.getConstantPool();
final InstructionList il = methodGen.getInstructionList();
- // Ignore this element if not correctly declared
if (!_ignore) {
- // Compile code that emits the element start tag
il.append(methodGen.loadHandler());
_name.translate(classGen, methodGen);
- il.append(DUP2); // duplicate these 2 args for endElement
+ il.append(DUP2);
il.append(methodGen.startElement());
- // Compile code that emits any needed namespace declaration
if (_namespace != null) {
- // public void attribute(final String name, final String value)
il.append(methodGen.loadHandler());
il.append(new PUSH(cpg, _prefix));
_namespace.translate(classGen,methodGen);
@@ -219,12 +253,94 @@
}
}
- // Compile code that emits the element attributes and contents
translateContents(classGen, methodGen);
- // Ignore this element if not correctly declared
if (!_ignore) {
- // Compile code that emits the element end tag
+ il.append(methodGen.endElement());
+ }
+ }
+
+ /**
+ * At runtime the compilation of xsl:element results in code that: (i)
+ * evaluates the avt for the name, (ii) checks for a prefix in the name
+ * (iii) generates a new prefix and create a new qname when necessary
+ * (iv) calls startElement() on the handler (v) looks up a uri in the XML
+ * when the prefix is not known at compile time (vi) calls namespace()
+ * on the handler (vii) evaluates the contents (viii) calls endElement().
+ */
+ public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
+ LocalVariableGen local = null;
+ final ConstantPoolGen cpg = classGen.getConstantPool();
+ final InstructionList il = methodGen.getInstructionList();
+
+ // Optimize translation if element name is a literal
+ if (_isLiteralName) {
+ translateLiteral(classGen, methodGen);
+ return;
+ }
+
+ if (!_ignore) {
+ il.append(methodGen.loadHandler());
+ _name.translate(classGen, methodGen);
+
+ // Call BasisLibrary.getPrefix() and store result in local variable
+ il.append(DUP);
+ final int getPrefix = cpg.addMethodref(BASIS_LIBRARY_CLASS, "getPrefix",
+ "(" + STRING_SIG + ")" + STRING_SIG);
+ il.append(new INVOKESTATIC(getPrefix));
+ il.append(DUP);
+ local = methodGen.addLocalVariable("prefix",
+ org.apache.bcel.generic.Type.STRING,
+ il.getEnd(), null);
+ il.append(new ASTORE(local.getIndex()));
+
+ // If prefix is null then generate a prefix at runtime
+ final BranchHandle ifNotNull = il.append(new IFNONNULL(null));
+ if (_namespace != null) {
+ final int generatePrefix = cpg.addMethodref(BASIS_LIBRARY_CLASS,
+ "generatePrefix",
+ "()" + STRING_SIG);
+ il.append(new INVOKESTATIC(generatePrefix));
+ il.append(DUP);
+ il.append(new ASTORE(local.getIndex()));
+
+ // Prepend newly generated prefix to the name
+ final int makeQName = cpg.addMethodref(BASIS_LIBRARY_CLASS, "makeQName",
+ "(" + STRING_SIG + STRING_SIG + ")" + STRING_SIG);
+ il.append(new INVOKESTATIC(makeQName));
+ }
+ ifNotNull.setTarget(il.append(DUP2));
+ il.append(methodGen.startElement());
+
+ if (_namespace != null) {
+ il.append(methodGen.loadHandler());
+ il.append(new ALOAD(local.getIndex()));
+ _namespace.translate(classGen, methodGen);
+ il.append(methodGen.namespace());
+ }
+ else {
+ // If prefix not known at compile time, call DOM.lookupNamespace()
+ il.append(new ALOAD(local.getIndex()));
+ final BranchHandle ifNull = il.append(new IFNULL(null));
+ il.append(methodGen.loadHandler());
+ il.append(new ALOAD(local.getIndex()));
+
+ il.append(methodGen.loadDOM());
+ il.append(methodGen.loadCurrentNode());
+ il.append(new ALOAD(local.getIndex()));
+
+ final int lookupNamespace = cpg.addInterfaceMethodref(DOM_INTF,
+ "lookupNamespace",
+ "(I" + STRING_SIG + ")" + STRING_SIG);
+ il.append(new INVOKEINTERFACE(lookupNamespace, 3));
+ il.append(methodGen.namespace());
+ ifNull.setTarget(il.append(NOP));
+ }
+ }
+
+ translateContents(classGen, methodGen);
+
+ if (!_ignore) {
il.append(methodGen.endElement());
}
}
@@ -239,7 +355,7 @@
for (int i = 0; i < n; i++) {
final SyntaxTreeNode item =
(SyntaxTreeNode)getContents().elementAt(i);
- if ((_ignore) && (item instanceof XslAttribute)) continue;
+ if (_ignore && item instanceof XslAttribute) continue;
item.translate(classGen, methodGen);
}
}
diff --git a/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages.java b/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages.java
index 5c5b243..455349d 100644
--- a/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages.java
+++ b/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages.java
@@ -218,38 +218,54 @@
// COMPILE_STDIN_ERR
"The -i option must be used with the -o option.",
+
// COMPILE_USAGE_STR
- "Usage:\n" +
- " xsltc [-o <output>] [-d <directory>] [-j <jarfile>]\n"+
- " [-p <package name>] [-x] [-s] [-u] <stylesheet>|-i\n\n"+
- " Where <output> is the name to give the the generated translet.\n"+
- " <stylesheet> is one or more stylesheet file names, or if\n"+
- " the -u options is specified, one or more stylesheet URLs.\n"+
- " <directory> is the output directory.\n"+
- " <jarfile> is the name of a JAR-file to put all classes in.\n"+
- " <package-name> is used to prefix all class names.\n\n"+
- " Notes:\n"+
- " The -i options forces the compiler to read from stdin\n"+
- " The -o option is ignored if compiling multiple stylesheets\n"+
- " The -x option switches on debug messages.\n"+
- " The -s option disables calling System.exit.",
+ "SYNOPSIS\n" +
+ " java org.apache.xalan.xsltc.cmdline.Compile [-o <output>]\n" +
+ " [-d <directory>] [-j <jarfile>] [-p <package>]\n" +
+ " [-n] [-x] [-s] [-u] [-v] [-h] { <stylesheet> | -i }\n\n" +
+ "OPTIONS\n" +
+ " -o <output> assigns the name <output> to the generated\n" +
+ " translet. By default the translet name\n" +
+ " is taken from the <stylesheet> name. This option\n"+
+ " is ignored if compiling multiple stylesheets.\n" +
+ " -d <directory> specifies a destination directory for translet\n" +
+ " -j <jarfile> packages translet classes into a jar file of the\n"+
+ " name specified as <jarfile>\n"+
+ " -p <package> specifies a package name prefix for all generated\n"+
+ " translet classes.\n" +
+ " -n disables template inlining to reduce method\n" +
+ " length.\n"+
+ " -x turns on additional debugging message output\n" +
+ " -s disables calling System.exit\n" +
+ " -u interprets <stylesheet> arguments as URLs\n" +
+ " -i forces compiler to read stylesheet from stdin\n" +
+ " -v prints the version of the compiler\n" +
+ " -h prints this usage statement\n",
+
// TRANSFORM_USAGE_STR
- "Usage: \n" +
- " xslt [-j <jarfile>] {-u <document_url> | <document>} <class>\n"+
- " [<name1>=<value1> ...]\n\n" +
- " Where <document> is the xml document to be transformed, or\n" +
- " <document_url> is a url for the xml document,\n" +
- " <class> is the translet class which is either in\n" +
- " user's CLASSPATH or in the <jarfile> specified \n" +
- " with the -j option.\n" +
- " Notes:\n"+
- " The -x option switches on debug messages.\n"+
- " The -s option disables calling System.exit.",
+ "SYNOPSIS \n" +
+ " java org.apache.xalan.xsltc.cmdline.Transform [-j <jarfile>]\n"+
+ " [-x] [-s] [-n <iterations>] {-u <document_url> | <document>}\n" +
+ " <class> [<param1>=<value1> ...]\n\n" +
+ " uses the translet <class> to transform an XML document \n"+
+ " specified as <document>. The translet <class> is either in\n"+
+ " the user's CLASSPATH or in the optionally specified <jarfile>.\n"+
+ "OPTIONS\n" +
+ " -j <jarfile> specifies a jarfile from which to load translet\n"+
+ " -x turns on additional debugging message output\n" +
+ " -s disables calling System.exit\n" +
+ " -n <iterations> runs the transformation <iterations> times and\n" +
+ " displays profiling information\n" +
+ " -u <document_url> specifies XML input document as a URL\n",
+
// STRAY_SORT_ERR
"<xsl:sort> can only be used within <xsl:for-each> or <xsl:apply-templates>.",
// UNSUPPORTED_ENCODING
- "Output encoding ''{0}'' is not supported on this JVM."
+ "Output encoding ''{0}'' is not supported on this JVM.",
+ // SYNTAX_ERR
+ "Syntax error in ''{0}''."
};
private static Vector _keys;
diff --git a/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages_no.java b/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages_no.java
index 648cd7c..2a481a6 100644
--- a/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages_no.java
+++ b/src/org/apache/xalan/xsltc/compiler/util/ErrorMessages_no.java
@@ -249,7 +249,9 @@
// STRAY_SORT_ERR
"<xsl:sort> kan bare brukes under <xsl:for-each> eller <xsl:apply-templates>.",
// UNSUPPORTED_ENCODING
- "Karaktersett ''{0}'' er ikke st\u00f8ttet av denne JVM."
+ "Karaktersett ''{0}'' er ikke st\u00f8ttet av denne JVM.",
+ // SYNTAX_ERR
+ "Syntax error in ''{0}''." // TODO: How do you say "syntax error" in norwegian?
};
public Object handleGetObject(String key) {
diff --git a/src/org/apache/xalan/xsltc/compiler/util/ErrorMsg.java b/src/org/apache/xalan/xsltc/compiler/util/ErrorMsg.java
index 4351a64..4a97c42 100644
--- a/src/org/apache/xalan/xsltc/compiler/util/ErrorMsg.java
+++ b/src/org/apache/xalan/xsltc/compiler/util/ErrorMsg.java
@@ -165,6 +165,7 @@
// Recently added error messages
public static final int STRAY_SORT_ERR = 74;
public static final int UNSUPPORTED_ENCODING = 75;
+ public static final int SYNTAX_ERR = 76;
// All error messages are localized and are stored in resource bundles.
// This array and the following 4 strings are read from that bundle.
diff --git a/src/org/apache/xalan/xsltc/compiler/util/LongType.java b/src/org/apache/xalan/xsltc/compiler/util/LongType.java
deleted file mode 100644
index cb9435a..0000000
--- a/src/org/apache/xalan/xsltc/compiler/util/LongType.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * @(#)$Id$
- *
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 2001 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Xalan" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation and was
- * originally based on software copyright (c) 2001, Sun
- * Microsystems., http://www.sun.com. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- * @author G. Todd Miller
- *
- */
-
-package org.apache.xalan.xsltc.compiler.util;
-
-import org.apache.xalan.xsltc.compiler.util.Type;
-import org.apache.bcel.generic.*;
-import org.apache.xalan.xsltc.compiler.Parser;
-import org.apache.xalan.xsltc.compiler.FlowList;
-import org.apache.xalan.xsltc.compiler.Constants;
-
-public final class LongType extends NumberType {
- protected LongType() {}
-
- public String toString() {
- return "long";
- }
-
- public boolean identicalTo(Type other) {
- return this == other;
- }
-
- public String toSignature() {
- return "J";
- }
-
- public org.apache.bcel.generic.Type toJCType() {
- return org.apache.bcel.generic.Type.LONG;
- }
-
- /**
- * @see org.apache.xalan.xsltc.compiler.util.Type#distanceTo
- */
- public int distanceTo(Type type) {
- if (type == this) {
- return 0;
- }
- else if (type == Type.Int) {
- return 1;
- }
- else
- return Integer.MAX_VALUE;
- }
-
- /**
- * Translates an long into an object of internal type <code>type</code>.
- *
- * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
- */
- public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
- final Type type) {
- if (type == Type.Real) {
- translateTo(classGen, methodGen, (RealType) type);
- }
- else if (type == Type.Int) {
- translateTo(classGen, methodGen, (IntType) type);
- }
- else if (type == Type.String) {
- translateTo(classGen, methodGen, (StringType) type);
- }
- else if (type == Type.Boolean) {
- translateTo(classGen, methodGen, (BooleanType) type);
- }
- else if (type == Type.Reference) {
- translateTo(classGen, methodGen, (ReferenceType) type);
- }
- else {
- ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
- toString(), type.toString());
- classGen.getParser().reportError(Constants.FATAL, err);
- }
- }
-
-
- /**
- * Expects an long on the stack and pushes a real.
- *
- * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
- */
- public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
- RealType type) {
- methodGen.getInstructionList().append(L2D);
- }
-
- /**
- * Expects an long on the stack and pushes its string value by calling
- * <code>Long.toString(int i)</code>.
- *
- * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
- */
- public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
- StringType type) {
- final ConstantPoolGen cpg = classGen.getConstantPool();
- final InstructionList il = methodGen.getInstructionList();
- il.append(new INVOKESTATIC(cpg.addMethodref(LONG_CLASS,
- "toString",
- "(J)" + STRING_SIG)));
- }
-
- /**
- * Expects an long on the stack and pushes a 0 if its value is 0 and
- * a 1 otherwise.
- *
- * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
- */
- public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
- BooleanType type) {
- final InstructionList il = methodGen.getInstructionList();
- final BranchHandle falsec = il.append(new IFEQ(null));
- il.append(LCONST_1);
- final BranchHandle truec = il.append(new GOTO(null));
- falsec.setTarget(il.append(LCONST_0));
- truec.setTarget(il.append(NOP));
- }
-
- /**
- * Expects an long on the stack and translates it to a non-synthesized
- * boolean. It does not push a 0 or a 1 but instead returns branchhandle
- * list to be appended to the false list.
- *
- * @see org.apache.xalan.xsltc.compiler.util.Type#translateToDesynthesized
- */
- public FlowList translateToDesynthesized(ClassGenerator classGen,
- MethodGenerator methodGen,
- BooleanType type) {
- final InstructionList il = methodGen.getInstructionList();
- return new FlowList(il.append(new IFEQ(null)));
- }
-
- /**
- * Expects an long on the stack and pushes a boxed integer.
- * Boxed integers are represented by an instance of
- * <code>java.lang.Integer</code>.
- *
- * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
- */
- public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
- ReferenceType type) {
- final ConstantPoolGen cpg = classGen.getConstantPool();
- final InstructionList il = methodGen.getInstructionList();
- il.append(new NEW(cpg.addClass(LONG_CLASS)));
- il.append(DUP_X1);
- il.append(SWAP);
- il.append(new INVOKESPECIAL(cpg.addMethodref(LONG_CLASS,
- "<init>", "(J)V")));
- }
-
- /**
- * Translates an long into the Java type denoted by <code>clazz</code>.
- * Expects an long on the stack and pushes a number of the appropriate
- * type after coercion.
- */
- public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
- Class clazz) {
- final InstructionList il = methodGen.getInstructionList();
- if (clazz == Character.TYPE) {
- il.append(L2I);
- il.append(I2C);
- }
- else if (clazz == Byte.TYPE) {
- il.append(L2I);
- il.append(I2B);
- }
- else if (clazz == Short.TYPE) {
- il.append(L2I);
- il.append(I2S);
- }
- else if (clazz == Integer.TYPE) {
- il.append(L2I);
- }
- else if (clazz == Long.TYPE) {
- il.append(NOP);
- }
- else if (clazz == Float.TYPE) {
- il.append(L2F);
- }
- else if (clazz == Double.TYPE) {
- il.append(L2D);
- }
- else {
- ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
- toString(), clazz.getName());
- classGen.getParser().reportError(Constants.FATAL, err);
- }
- }
-
- /**
- * Translates an object of this type to its boxed representation.
- */
- public void translateBox(ClassGenerator classGen,
- MethodGenerator methodGen) {
- translateTo(classGen, methodGen, Type.Reference);
- }
-
- /**
- * Translates an object of this type to its unboxed representation.
- */
- public void translateUnBox(ClassGenerator classGen,
- MethodGenerator methodGen) {
- final ConstantPoolGen cpg = classGen.getConstantPool();
- final InstructionList il = methodGen.getInstructionList();
- il.append(new CHECKCAST(cpg.addClass(LONG_CLASS)));
- final int index = cpg.addMethodref(LONG_CLASS,
- LONG_VALUE,
- LONG_VALUE_SIG);
- il.append(new INVOKEVIRTUAL(index));
- }
-
- public Instruction ADD() {
- return InstructionConstants.LADD;
- }
-
- public Instruction SUB() {
- return InstructionConstants.LSUB;
- }
-
- public Instruction MUL() {
- return InstructionConstants.LMUL;
- }
-
- public Instruction DIV() {
- return InstructionConstants.LDIV;
- }
-
- public Instruction REM() {
- return InstructionConstants.LREM;
- }
-
- public Instruction NEG() {
- return InstructionConstants.LNEG;
- }
-
- public Instruction LOAD(int slot) {
- return new LLOAD(slot);
- }
-
- public Instruction STORE(int slot) {
- return new LSTORE(slot);
- }
-
- public BranchInstruction GT(boolean tozero) {
- // GTM:TBD
- return tozero ? (BranchInstruction) new IFGT(null) :
- (BranchInstruction) new IF_ICMPGT(null);
- }
-
- public BranchInstruction GE(boolean tozero) {
- // GTM:TBD
- return tozero ? (BranchInstruction) new IFGE(null) :
- (BranchInstruction) new IF_ICMPGE(null);
- }
-
- public BranchInstruction LT(boolean tozero) {
- // GTM:TBD
- return tozero ? (BranchInstruction) new IFLT(null) :
- (BranchInstruction) new IF_ICMPLT(null);
- }
-
- public BranchInstruction LE(boolean tozero) {
- // GTM:TBD
- return tozero ? (BranchInstruction) new IFLE(null) :
- (BranchInstruction) new IF_ICMPLE(null);
- }
-}
diff --git a/src/org/apache/xalan/xsltc/compiler/util/MethodGenerator.java b/src/org/apache/xalan/xsltc/compiler/util/MethodGenerator.java
index a0e5fc8..45b42a0 100644
--- a/src/org/apache/xalan/xsltc/compiler/util/MethodGenerator.java
+++ b/src/org/apache/xalan/xsltc/compiler/util/MethodGenerator.java
@@ -103,6 +103,7 @@
private final Instruction _nextNode;
private SlotAllocator _slotAllocator;
+ private boolean _allocatorInit = false;
public MethodGenerator(int access_flags, Type return_type,
Type[] arg_types, String[] arg_names,
@@ -173,17 +174,26 @@
_slotAllocator = new SlotAllocator();
_slotAllocator.initialize(getLocalVariables());
+ _allocatorInit = true;
}
+ /**
+ * Allocates a local variable. If the slot allocator has already been
+ * initialized, then call addLocalVariable2() so that the new variable
+ * is known to the allocator. Failing to do this may cause the allocator
+ * to return a slot that is already in use.
+ */
public LocalVariableGen addLocalVariable(String name, Type type,
InstructionHandle start,
- InstructionHandle end) {
-
- return super.addLocalVariable(name, type, start, end);
+ InstructionHandle end)
+ {
+ return (_allocatorInit) ? addLocalVariable2(name, type, start)
+ : super.addLocalVariable(name, type, start, end);
}
public LocalVariableGen addLocalVariable2(String name, Type type,
- InstructionHandle start) {
+ InstructionHandle start)
+ {
return super.addLocalVariable(name, type,
_slotAllocator.allocateSlot(type),
start, null);
diff --git a/src/org/apache/xalan/xsltc/compiler/util/ReferenceType.java b/src/org/apache/xalan/xsltc/compiler/util/ReferenceType.java
index 8d56714..c7ac287 100644
--- a/src/org/apache/xalan/xsltc/compiler/util/ReferenceType.java
+++ b/src/org/apache/xalan/xsltc/compiler/util/ReferenceType.java
@@ -113,6 +113,9 @@
else if (type == Type.Node) {
translateTo(classGen, methodGen, (NodeType) type);
}
+ else if (type == Type.ResultTree) {
+ translateTo(classGen, methodGen, (ResultTreeType) type);
+ }
else {
ErrorMsg err = new ErrorMsg(ErrorMsg.INTERNAL_ERR, type.toString());
classGen.getParser().reportError(Constants.FATAL, err);
@@ -211,6 +214,52 @@
}
/**
+ * Casts a reference into a ResultTree.
+ *
+ * @see org.apache.xalan.xsltc.compiler.util.Type#translateTo
+ */
+ public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
+ ResultTreeType type) {
+ final ConstantPoolGen cpg = classGen.getConstantPool();
+ final InstructionList il = methodGen.getInstructionList();
+ int index = cpg.addMethodref(BASIS_LIBRARY_CLASS, "referenceToResultTree",
+ "(" + OBJECT_SIG + ")" + DOM_INTF_SIG);
+ il.append(new INVOKESTATIC(index));
+ }
+
+ /**
+ * Translates a reference into the Java type denoted by <code>clazz</code>.
+ * Only conversion allowed is to java.lang.Object.
+ */
+ public void translateTo(ClassGenerator classGen, MethodGenerator methodGen,
+ Class clazz) {
+ if (clazz.getName().equals("java.lang.Object")) {
+ methodGen.getInstructionList().append(NOP);
+ }
+ else {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
+ toString(), clazz.getName());
+ classGen.getParser().reportError(Constants.FATAL, err);
+ }
+ }
+
+ /**
+ * Translates an external Java type into a reference. Only conversion
+ * allowed is from java.lang.Object.
+ */
+ public void translateFrom(ClassGenerator classGen, MethodGenerator methodGen,
+ Class clazz) {
+ if (clazz.getName().equals("java.lang.Object")) {
+ methodGen.getInstructionList().append(NOP);
+ }
+ else {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.DATA_CONVERSION_ERR,
+ toString(), clazz.getName());
+ classGen.getParser().reportError(Constants.FATAL, err);
+ }
+ }
+
+ /**
* Expects a reference on the stack and translates it to a non-synthesized
* boolean. It does not push a 0 or a 1 but instead returns branchhandle
* list to be appended to the false list.
diff --git a/src/org/apache/xalan/xsltc/compiler/util/Type.java b/src/org/apache/xalan/xsltc/compiler/util/Type.java
index 5413d96..689b65f 100644
--- a/src/org/apache/xalan/xsltc/compiler/util/Type.java
+++ b/src/org/apache/xalan/xsltc/compiler/util/Type.java
@@ -72,7 +72,6 @@
public abstract class Type implements Constants {
public static final Type Int = new IntType();
- public static final Type Lng = new LongType(); //GTM,bug 3592
public static final Type Real = new RealType();
public static final Type Boolean = new BooleanType();
public static final Type NodeSet = new NodeSetType();
diff --git a/src/org/apache/xalan/xsltc/compiler/util/Util.java b/src/org/apache/xalan/xsltc/compiler/util/Util.java
index 2082fe1..022bac5 100644
--- a/src/org/apache/xalan/xsltc/compiler/util/Util.java
+++ b/src/org/apache/xalan/xsltc/compiler/util/Util.java
@@ -66,6 +66,7 @@
import org.apache.bcel.generic.Type;
import org.apache.bcel.generic.*;
import org.apache.xalan.xsltc.compiler.Parser;
+import org.apache.xalan.xsltc.compiler.Constants;
public final class Util {
static public char filesep;
@@ -108,17 +109,20 @@
* 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 +134,11 @@
}
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() {
@@ -156,35 +156,46 @@
/**
* Replace a certain character in a string with a new substring.
*/
- public 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;
+ public static String replace(String base, char ch, String str) {
+ return (base.indexOf(ch) < 0) ? base :
+ replace(base, String.valueOf(ch), new String[] { str });
+ }
+
+ public static String replace(String base, String delim, String[] str) {
+ final int len = base.length();
+ final StringBuffer result = new StringBuffer();
+
+ for (int i = 0; i < len; i++) {
+ final char ch = base.charAt(i);
+ final int k = delim.indexOf(ch);
+
+ if (k >= 0) {
+ result.append(str[k]);
}
else {
- final String before = base.substring(0, pos);
- final String after = base.substring(pos+1);
- base = before + str + after;
+ result.append(ch);
}
}
- return base;
+ return result.toString();
}
/**
- * Replace occurances of '.' with '$dot$' and '-' with '$dash$'
+ * Replace occurances of '.', '-', '/' and ':'
*/
public static String escape(String input) {
- input = replace(input, '.', "$dot$");
- input = replace(input, '-', "$dash$");
- return input;
+ return replace(input, ".-/:",
+ new String[] { "$dot$", "$dash$", "$slash$", "$colon$" });
}
+ public static String getLocalName(String qname) {
+ final int index = qname.lastIndexOf(":");
+ return (index > 0) ? qname.substring(index + 1) : qname;
+ }
+
+ public static String getPrefix(String qname) {
+ final int index = qname.lastIndexOf(":");
+ return (index > 0) ? qname.substring(0, index) :
+ Constants.EMPTYSTRING;
+ }
}
diff --git a/src/org/apache/xalan/xsltc/compiler/xpath.cup b/src/org/apache/xalan/xsltc/compiler/xpath.cup
index 31a8a68..adce4e3 100644
--- a/src/org/apache/xalan/xsltc/compiler/xpath.cup
+++ b/src/org/apache/xalan/xsltc/compiler/xpath.cup
@@ -92,6 +92,11 @@
private XSLTC _xsltc;
/**
+ * String representation of the expression being parsed.
+ */
+ private String _expression;
+
+ /**
* Line number where this expression/pattern was declared.
*/
private int _lineNumber = 0;
@@ -115,10 +120,18 @@
return _parser.getQName(name);
}
+ public QName getQNameIgnoreDefaultNs(String name) {
+ return _parser.getQNameIgnoreDefaultNs(name);
+ }
+
public void setMultiDocument(boolean flag) {
_xsltc.setMultiDocument(flag);
}
+ public void setCallsNodeset(boolean flag) {
+ _xsltc.setCallsNodeset(flag);
+ }
+
public int findNodeType(int axis, Object test) {
if (test == null) { // *
@@ -174,8 +187,9 @@
* compiled in a separate module.
*
*/
- public Symbol parse(int lineNumber) throws Exception {
+ public Symbol parse(String expression, int lineNumber) throws Exception {
try {
+ _expression = expression;
_lineNumber = lineNumber;
return super.parse();
}
@@ -206,12 +220,29 @@
}
public void report_error(String message, Object info) {
- // empty
+ final ErrorMsg err = new ErrorMsg(ErrorMsg.SYNTAX_ERR, _lineNumber,
+ _expression);
+ _parser.reportError(Constants.FATAL, err);
}
public void report_fatal_error(String message, Object info) {
// empty
}
+
+ public RelativeLocationPath insertStep(Step step, RelativeLocationPath rlp) {
+ if (rlp instanceof Step) {
+ return new ParentLocationPath(step, (Step) rlp);
+ }
+ else if (rlp instanceof ParentLocationPath) {
+ final ParentLocationPath plp = (ParentLocationPath) rlp;
+ final RelativeLocationPath newrlp = insertStep(step, plp.getPath());
+ return new ParentLocationPath(newrlp, plp.getStep());
+ }
+ else {
+ addError(new ErrorMsg(ErrorMsg.INTERNAL_ERR, "XPathParser.insertStep"));
+ return rlp;
+ }
+ }
:}
terminal SLASH, DOT, LBRACK, RBRACK, VBAR, LPAREN, RPAREN, STAR, COMMA;
@@ -290,12 +321,6 @@
| SLASH RelativePathPattern:rpp
{: RESULT = new AbsolutePathPattern(rpp); :}
- | ProcessingInstructionPattern:pip
- {: RESULT = pip; :}
-
- | ProcessingInstructionPattern:pip Predicates:pp
- {: RESULT = (ProcessingInstructionPattern)pip.setPredicates(pp); :}
-
| IdKeyPattern:ikp
{: RESULT = ikp; :}
@@ -341,6 +366,12 @@
pp);
:}
+ | ProcessingInstructionPattern:pip
+ {: RESULT = pip; :}
+
+ | ProcessingInstructionPattern:pip Predicates:pp
+ {: RESULT = (ProcessingInstructionPattern)pip.setPredicates(pp); :}
+
| ChildOrAttributeAxisSpecifier:axis NodeTestPattern:nt
{: RESULT=new StepPattern(axis.intValue(),
parser.findNodeType(axis.intValue(), nt),
@@ -352,7 +383,19 @@
{: RESULT = new StepPattern(axis.intValue(),
parser.findNodeType(axis.intValue(),nt),
pp);
- :};
+ :}
+
+ | ChildOrAttributeAxisSpecifier:axis ProcessingInstructionPattern:pip
+ {:
+ RESULT = pip; // TODO: report error if axis is attribute
+ :}
+
+ | ChildOrAttributeAxisSpecifier:axis ProcessingInstructionPattern:pip
+ Predicates:pp
+ {:
+ // TODO: report error if axis is attribute
+ RESULT = (ProcessingInstructionPattern)pip.setPredicates(pp);
+ :};
NodeTestPattern ::= NameTestPattern:nt
{: RESULT = nt; :}
@@ -582,30 +625,13 @@
AbbreviatedAbsoluteLocationPath ::= DSLASH RelativeLocationPath:rlp
{:
+ final Step step = new Step(Axis.DESCENDANTORSELF, -1, null);
- AbsoluteLocationPath alp = null;
-
- Step left = new Step(Axis.DESCENDANTORSELF, -1, null);
-
- if (rlp instanceof ParentLocationPath) {
- ParentLocationPath plp = new ParentLocationPath(left, rlp);
- alp = new AbsoluteLocationPath(plp);
- }
- else if (rlp instanceof Step) {
- Step right = (Step)rlp;
- alp = new AbsoluteLocationPath(new ParentLocationPath(left, right));
- }
- else {
- // Don't think we'll ever get here...
- Step right = new Step(Axis.CHILD, NodeTest.ELEMENT, null);
- alp = new AbsoluteLocationPath(new ParentLocationPath(left, right));
- }
-
- RESULT = new FilteredAbsoluteLocationPath(alp);
+ RESULT = new FilteredAbsoluteLocationPath(
+ new AbsoluteLocationPath(parser.insertStep(step,
+ (RelativeLocationPath) rlp)));
:};
-
-
Step ::= NodeTest:ntest
{:
if (ntest instanceof Step) {
@@ -714,25 +740,25 @@
/*
* If the string appears to have the syntax of a QName, store
* namespace info in the literal expression. This is used for
- * element-available and function-available functions.
+ * element-available and function-available functions, among
+ * others. Also, the default namespace must be ignored.
*/
+ String namespace = null;
final int index = string.lastIndexOf(':');
- final String prefix = index >= 0
- ? string.substring(0, index)
- : Constants.EMPTYSTRING;
- String namespace = parser._symbolTable.lookupNamespace(prefix);
- RESULT = namespace == null
- ? new LiteralExpr(string)
- : new LiteralExpr(string, namespace);
+
+ if (index > 0) {
+ final String prefix = string.substring(0, index);
+ namespace = parser._symbolTable.lookupNamespace(prefix);
+ }
+ RESULT = (namespace == null) ? new LiteralExpr(string)
+ : new LiteralExpr(string, namespace);
:}
| INT:num
{:
- // bug fix 3592, num comes in as a Long rather than an Integer
- // see xpath.lex, {Digit}+ rule.
long value = num.longValue();
- if ((value < Integer.MIN_VALUE) || (value > Integer.MAX_VALUE)) {
- RESULT = new LongExpr(num.longValue());
+ if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
+ RESULT = new RealExpr(value);
}
else {
if (num.doubleValue() == -0)
@@ -741,7 +767,7 @@
RESULT = new IntExpr(num.intValue());
else if (num.doubleValue() == 0.0)
RESULT = new RealExpr(num.doubleValue());
- else
+ else
RESULT = new IntExpr(num.intValue());
}
:}
@@ -773,49 +799,48 @@
if (node == null) {
RESULT = new UnresolvedRef(varName);
}
-
:};
FunctionCall ::= FunctionName:fname LPAREN RPAREN
{:
- if (fname == parser.getQName("current")) {
+ if (fname == parser.getQNameIgnoreDefaultNs("current")) {
RESULT = new CurrentCall(fname);
}
- else if (fname == parser.getQName("number")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("number")) {
RESULT = new NumberCall(fname, parser.EmptyArgs);
}
- else if (fname == parser.getQName("string")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("string")) {
RESULT = new StringCall(fname, parser.EmptyArgs);
}
- else if (fname == parser.getQName("concat")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("concat")) {
RESULT = new ConcatCall(fname, parser.EmptyArgs);
}
- else if (fname == parser.getQName("true")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("true")) {
RESULT = new BooleanExpr(true);
}
- else if (fname == parser.getQName("false")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("false")) {
RESULT = new BooleanExpr(false);
}
- else if (fname == parser.getQName("name")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("name")) {
RESULT = new NameCall(fname);
}
- else if (fname == parser.getQName("generate-id")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("generate-id")) {
RESULT = new GenerateIdCall(fname, parser.EmptyArgs);
}
- else if (fname == parser.getQName("string-length")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("string-length")) {
RESULT = new StringLengthCall(fname, parser.EmptyArgs);
}
- else if (fname == parser.getQName("position")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("position")) {
RESULT = new PositionCall(fname);
}
- else if (fname == parser.getQName("last")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("last")) {
RESULT = new LastCall(fname);
}
- else if (fname == parser.getQName("local-name")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("local-name")) {
RESULT = new LocalNameCall(fname);
}
- else if (fname == parser.getQName("namespace-uri")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("namespace-uri")) {
RESULT = new NamespaceUriCall(fname);
}
else {
@@ -825,76 +850,81 @@
| FunctionName:fname LPAREN NonemptyArgumentList:argl RPAREN
{:
- if (fname == parser.getQName("concat")) {
+ if (fname == parser.getQNameIgnoreDefaultNs("concat")) {
RESULT = new ConcatCall(fname, argl);
}
- else if (fname == parser.getQName("number")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("number")) {
RESULT = new NumberCall(fname, argl);
}
- else if (fname == parser.getQName("document")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("document")) {
parser.setMultiDocument(true);
RESULT = new DocumentCall(fname, argl);
}
- else if (fname == parser.getQName("string")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("string")) {
RESULT = new StringCall(fname, argl);
}
- else if (fname == parser.getQName("boolean")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("boolean")) {
RESULT = new BooleanCall(fname, argl);
}
- else if (fname == parser.getQName("name")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("name")) {
RESULT = new NameCall(fname, argl);
}
- else if (fname == parser.getQName("generate-id")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("generate-id")) {
RESULT = new GenerateIdCall(fname, argl);
}
- else if (fname == parser.getQName("not")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("not")) {
RESULT = new NotCall(fname, argl);
}
- else if (fname == parser.getQName("format-number")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("format-number")) {
RESULT = new FormatNumberCall(fname, argl);
}
- else if (fname == parser.getQName("unparsed-entity-uri")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("unparsed-entity-uri")) {
RESULT = new UnparsedEntityUriCall(fname, argl);
}
- else if (fname == parser.getQName("key")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("key")) {
RESULT = new KeyCall(fname, argl);
}
- else if (fname == parser.getQName("id")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("id")) {
RESULT = new KeyCall(fname, argl);
}
- else if (fname == parser.getQName("ceiling")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("ceiling")) {
RESULT = new CeilingCall(fname, argl);
}
- else if (fname == parser.getQName("round")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("round")) {
RESULT = new RoundCall(fname, argl);
}
- else if (fname == parser.getQName("floor")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("floor")) {
RESULT = new FloorCall(fname, argl);
}
- else if (fname == parser.getQName("contains")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("contains")) {
RESULT = new ContainsCall(fname, argl);
}
- else if (fname == parser.getQName("string-length")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("string-length")) {
RESULT = new StringLengthCall(fname, argl);
}
- else if (fname == parser.getQName("starts-with")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("starts-with")) {
RESULT = new StartsWithCall(fname, argl);
}
- else if (fname == parser.getQName("function-available")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("function-available")) {
RESULT = new FunctionAvailableCall(fname, argl);
}
- else if (fname == parser.getQName("element-available")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("element-available")) {
RESULT = new ElementAvailableCall(fname, argl);
}
- else if (fname == parser.getQName("local-name")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("local-name")) {
RESULT = new LocalNameCall(fname, argl);
}
- else if (fname == parser.getQName("lang")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("lang")) {
RESULT = new LangCall(fname, argl);
}
- else if (fname == parser.getQName("namespace-uri")) {
+ else if (fname == parser.getQNameIgnoreDefaultNs("namespace-uri")) {
RESULT = new NamespaceUriCall(fname, argl);
}
+ // Special case for extension function nodeset()
+ else if (fname.getLocalPart().equals("nodeset")) {
+ parser.setCallsNodeset(true); // implies MultiDOM
+ RESULT = new FunctionCall(fname, argl);
+ }
else {
RESULT = new FunctionCall(fname, argl);
}
@@ -911,18 +941,24 @@
{: argl.insertElementAt(arg, 0); RESULT = argl; :};
FunctionName ::= QName:fname
- {:
- fname.clearDefaultNamespace();
- RESULT = fname;
- :};
+ {:
+ final String prefix = fname.getPrefix();
+ if (prefix == null || prefix.equals(Constants.EMPTYSTRING)) {
+ fname = parser.getQNameIgnoreDefaultNs(fname.getLocalPart());
+ }
+ RESULT = fname;
+ :};
VariableName ::= QName:vname
- {:
- vname.clearDefaultNamespace();
- RESULT = vname;
- :};
+ {:
+ final String prefix = vname.getPrefix();
+ if (prefix == null || prefix.equals(Constants.EMPTYSTRING)) {
+ vname = parser.getQNameIgnoreDefaultNs(vname.getLocalPart());
+ }
+ RESULT = vname;
+ :};
-Argument ::= Expr:ex
+Argument ::= Expr:ex
{: RESULT = ex; :};
NodeTest ::= NameTest:nt
@@ -939,14 +975,13 @@
| PIPARAM LPAREN Literal:l RPAREN
{:
- QName name = parser.getQName("name");
+ QName name = parser.getQNameIgnoreDefaultNs("name");
Expression exp = new EqualityExpr(Operators.EQ,
new NameCall(name),
new LiteralExpr(l));
Vector predicates = new Vector();
predicates.addElement(new Predicate(exp));
RESULT = new Step(Axis.CHILD, NodeTest.PI, predicates);
- //RESULT = new Integer(NodeTest.PI);
:}
| PI
@@ -961,54 +996,54 @@
QName ::= QNAME:qname
{: RESULT = parser.getQName(qname); :}
- | DIV
- {: RESULT = parser.getQName("div"); :}
+ | DIV
+ {: RESULT = parser.getQNameIgnoreDefaultNs("div"); :}
| MOD
- {: RESULT = parser.getQName("mod"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("mod"); :}
| KEY
- {: RESULT = parser.getQName("key"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("key"); :}
| ANCESTOR
- {: RESULT = parser.getQName("child"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("child"); :}
| ANCESTORORSELF
- {: RESULT = parser.getQName("ancestor-or-self"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("ancestor-or-self"); :}
| ATTRIBUTE
- {: RESULT = parser.getQName("attribute"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("attribute"); :}
| CHILD
- {: RESULT = parser.getQName("child"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("child"); :}
| DESCENDANT
- {: RESULT = parser.getQName("decendant"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("decendant"); :}
| DESCENDANTORSELF
- {: RESULT = parser.getQName("decendant-or-self"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("decendant-or-self"); :}
| FOLLOWING
- {: RESULT = parser.getQName("following"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("following"); :}
| FOLLOWINGSIBLING
- {: RESULT = parser.getQName("following-sibling"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("following-sibling"); :}
| NAMESPACE
- {: RESULT = parser.getQName("namespace"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("namespace"); :}
| PARENT
- {: RESULT = parser.getQName("parent"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("parent"); :}
| PRECEDING
- {: RESULT = parser.getQName("preceding"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("preceding"); :}
| PRECEDINGSIBLING
- {: RESULT = parser.getQName("preceding-sibling"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("preceding-sibling"); :}
| SELF
- {: RESULT = parser.getQName("self"); :}
+ {: RESULT = parser.getQNameIgnoreDefaultNs("self"); :}
| ID
- {: RESULT = parser.getQName("id"); :};
+ {: RESULT = parser.getQNameIgnoreDefaultNs("id"); :};
diff --git a/src/org/apache/xalan/xsltc/compiler/xpath.lex b/src/org/apache/xalan/xsltc/compiler/xpath.lex
index a82c95a..2f361a8 100644
--- a/src/org/apache/xalan/xsltc/compiler/xpath.lex
+++ b/src/org/apache/xalan/xsltc/compiler/xpath.lex
@@ -79,10 +79,22 @@
Exception
%yylexthrow}
-Digit=[0-9]
-Letter=[A-Za-z]
-NCNameChar=({Letter}|{Digit}|"."|"-"|"_")
+Letter={BaseChar}|{Ideographic}
+
+BaseChar=[\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u0131\u0134-\u013E\u0141-\u0148\u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4-\u01F5\u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC\u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7-\u04C8\u04CB-\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8-\u04F9\u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2\u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE\u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5-\u06E6\u0905-\u0939\u093D\u0958-\u0961\u0985-\u098C\u098F-\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC-\u09DD\u09DF-\u09E1\u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3\u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F-\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B36-\u0B39\u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60-\u0D61\u0E01-\u0E2E\u0E30\u0E32-\u0E33\u0E40-\u0E45\u0E81-\u0E82\u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EAE\u0EB0\u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69\u10A0-\u10C5\u10D0-\u10F6\u1100\u1102-\u1103\u1105-\u1107\u1109\u110B-\u110C\u110E-\u1112\u113C\u113E\u1140\u114C\u114E\u1150\u1154-\u1155\u1159\u115F-\u1161\u1163\u1165\u1167\u1169\u116D-\u116E\u1172-\u1173\u1175\u119E\u11A8\u11AB\u11AE-\u11AF\u11B7-\u11B8\u11BA\u11BC-\u11C2\u11EB\u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A-\u212B\u212E\u2180-\u2182\u3041-\u3094\u30A1-\u30FA\u3105-\u312C\uAC00-\uD7A3]
+
+Ideographic=[\u4E00-\u9FA5\u3007\u3021-\u3029]
+
+CombiningChar=[\u0300-\u0345\u0360-\u0361\u0483-\u0486\u0591-\u05A1\u05A3-\u05B9\u05BB-\u05BD\u05BF\u05C1-\u05C2\u05C4\u064B-\u0652\u0670\u06D6-\u06DC\u06DD-\u06DF\u06E0-\u06E4\u06E7-\u06E8\u06EA-\u06ED\u0901-\u0903\u093C\u093E-\u094C\u094D\u0951-\u0954\u0962-\u0963\u0981-\u0983\u09BC\u09BE\u09BF\u09C0-\u09C4\u09C7-\u09C8\u09CB-\u09CD\u09D7\u09E2-\u09E3\u0A02\u0A3C\u0A3E\u0A3F\u0A40-\u0A42\u0A47-\u0A48\u0A4B-\u0A4D\u0A70-\u0A71\u0A81-\u0A83\u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0B01-\u0B03\u0B3C\u0B3E-\u0B43\u0B47-\u0B48\u0B4B-\u0B4D\u0B56-\u0B57\u0B82-\u0B83\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7\u0C01-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55-\u0C56\u0C82-\u0C83\u0CBE-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5-\u0CD6\u0D02-\u0D03\u0D3E-\u0D43\u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0E31\u0E34-\u0E3A\u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB-\u0EBC\u0EC8-\u0ECD\u0F18-\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84\u0F86-\u0F8B\u0F90-\u0F95\u0F97\u0F99-\u0FAD\u0FB1-\u0FB7\u0FB9\u20D0-\u20DC\u20E1\u302A-\u302F\u3099\u309A]
+
+Digit=[\u0030-\u0039\u0660-\u0669\u06F0-\u06F9\u0966-\u096F\u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0BE7-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29]
+
+Extender=[\u00B7\u02D0\u02D1\u0387\u0640\u0E46\u0EC6\u3005\u3031-\u3035\u309D-\u309E\u30FC-\u30FE]
+
NCName=({Letter}|"_")({NCNameChar})*
+
+NCNameChar={Letter}|{Digit}|"."|"-"|"_"|{CombiningChar}|{Extender}
+
%%
"*" { return new Symbol(sym.STAR); }
diff --git a/src/org/apache/xalan/xsltc/dom/BitArray.java b/src/org/apache/xalan/xsltc/dom/BitArray.java
index 9e33047..16894a4 100644
--- a/src/org/apache/xalan/xsltc/dom/BitArray.java
+++ b/src/org/apache/xalan/xsltc/dom/BitArray.java
@@ -93,6 +93,10 @@
/**
* Constructor. Defines the initial size of the bit array (in bits).
*/
+ public BitArray() {
+ this(32);
+ }
+
public BitArray(int size) {
if (size < 32) size = 32;
_bitSize = size;
diff --git a/src/org/apache/xalan/xsltc/dom/CurrentNodeListIterator.java b/src/org/apache/xalan/xsltc/dom/CurrentNodeListIterator.java
index dfb9f3d..5e26eec 100644
--- a/src/org/apache/xalan/xsltc/dom/CurrentNodeListIterator.java
+++ b/src/org/apache/xalan/xsltc/dom/CurrentNodeListIterator.java
@@ -70,28 +70,31 @@
import org.apache.xalan.xsltc.runtime.BasisLibrary;
public final class CurrentNodeListIterator extends NodeIteratorBase {
- private NodeIterator _source;
+
private boolean _docOrder;
+ private NodeIterator _source;
private final CurrentNodeListFilter _filter;
private IntegerArray _nodes = new IntegerArray();
private int _current; // index in _nodes of the next node to try
+ private int _last = -1;
- private AbstractTranslet _translet;
private final int _currentNode;
- private int _last;
+ private AbstractTranslet _translet;
public CurrentNodeListIterator(NodeIterator source,
CurrentNodeListFilter filter,
int currentNode,
- AbstractTranslet translet) {
+ AbstractTranslet translet)
+ {
this(source, !source.isReverse(), filter, currentNode, translet);
}
public CurrentNodeListIterator(NodeIterator source, boolean docOrder,
CurrentNodeListFilter filter,
int currentNode,
- AbstractTranslet translet) {
+ AbstractTranslet translet)
+ {
_source = source;
_filter = filter;
_translet = translet;
@@ -99,11 +102,6 @@
_currentNode = currentNode;
}
- public NodeIterator forceNaturalOrder() {
- _docOrder = true;
- return this;
- }
-
public void setRestartable(boolean isRestartable) {
_isRestartable = isRestartable;
_source.setRestartable(isRestartable);
@@ -134,14 +132,13 @@
}
public int next() {
- final boolean docOrder = _docOrder;
final int last = _nodes.cardinality();
final int currentNode = _currentNode;
+ final AbstractTranslet translet = _translet;
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);
}
@@ -149,29 +146,12 @@
return END;
}
- private int computePositionOfLast() {
- int lastPosition = 0;
- final boolean docOrder = _docOrder;
- final int last = _nodes.cardinality();
- 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)) {
- lastPosition++;
- }
- }
- return lastPosition;
- }
-
public NodeIterator setStartNode(int node) {
NodeIterator retval = this;
if (_isRestartable) {
- // iterator is not a clone
_source.setStartNode(_startNode = node);
- // including ROOT
+
_nodes.clear();
while ((node = _source.next()) != END) {
_nodes.add(node);
@@ -179,13 +159,14 @@
_current = 0;
retval = resetPosition();
}
- // compute position of _last
- _last = computePositionOfLast();
return retval;
}
public int getLast() {
- return ( _last == -1 ) ? computePositionOfLast() : _last;
+ if (_last == -1) {
+ _last = computePositionOfLast();
+ }
+ return _last;
}
public void setMark() {
@@ -197,4 +178,20 @@
_source.gotoMark();
_current = _markedNode;
}
+
+ private int computePositionOfLast() {
+ final int last = _nodes.cardinality();
+ final int currNode = _currentNode;
+ final AbstractTranslet translet = _translet;
+
+ int lastPosition = 0;
+ for (int index = _current; index < last; ) {
+ int nodeIndex = _nodes.at(index++); // note increment
+ if (_filter.test(nodeIndex, index, last, currNode, translet, this)) {
+ lastPosition++;
+ }
+ }
+ return lastPosition;
+ }
}
+
diff --git a/src/org/apache/xalan/xsltc/dom/DOMAdapter.java b/src/org/apache/xalan/xsltc/dom/DOMAdapter.java
index 4d75669..450f844 100644
--- a/src/org/apache/xalan/xsltc/dom/DOMAdapter.java
+++ b/src/org/apache/xalan/xsltc/dom/DOMAdapter.java
@@ -73,6 +73,7 @@
import org.apache.xalan.xsltc.TransletException;
public final class DOMAdapter implements DOM {
+
private final DOMImpl _domImpl;
private short[] _mapping;
private short[] _reverse;
@@ -80,10 +81,13 @@
private short[] _NSreverse;
private StripFilter _filter = null;
+
+ private int _multiDOMMask;
public DOMAdapter(DOMImpl dom,
String[] namesArray,
- String[] namespaceArray) {
+ String[] namespaceArray)
+ {
_domImpl = dom;
_mapping = dom.getMapping(namesArray);
_reverse = dom.getReverseMapping(namesArray);
@@ -98,7 +102,9 @@
_NSreverse = _domImpl.getReverseNamespaceMapping(namespaces);
}
- /** returns singleton iterator containg the document root */
+ /**
+ * Returns singleton iterator containg the document root
+ */
public NodeIterator getIterator() {
return _domImpl.getIterator();
}
@@ -111,14 +117,22 @@
return _domImpl.getTreeString();
}
+ public int getMultiDOMMask() {
+ return _multiDOMMask;
+ }
+
+ public void setMultiDOMMask(int mask) {
+ _multiDOMMask = mask;
+ }
+
public NodeIterator getChildren(final int node) {
NodeIterator iterator = _domImpl.getChildren(node);
if (_filter == null) {
- return(iterator.setStartNode(node));
+ return iterator.setStartNode(node);
}
else {
- iterator = _domImpl.strippingIterator(iterator,_mapping,_filter);
- return(iterator.setStartNode(node));
+ iterator = _domImpl.strippingIterator(iterator, _mapping, _filter);
+ return iterator.setStartNode(node);
}
}
@@ -128,9 +142,10 @@
public NodeIterator getTypedChildren(final int type) {
NodeIterator iterator = _domImpl.getTypedChildren(_reverse[type]);
- if ((_reverse[type] == DOM.TEXT) && (_filter != null))
- iterator = _domImpl.strippingIterator(iterator,_mapping,_filter);
- return(iterator);
+ if (_reverse[type] == DOM.TEXT && _filter != null) {
+ return _domImpl.strippingIterator(iterator,_mapping,_filter);
+ }
+ return iterator;
}
public NodeIterator getNamespaceAxisIterator(final int axis, final int ns) {
@@ -139,26 +154,28 @@
public NodeIterator getAxisIterator(final int axis) {
NodeIterator iterator = _domImpl.getAxisIterator(axis);
- if (_filter != null)
- iterator = _domImpl.strippingIterator(iterator,_mapping,_filter);
- return(iterator);
+ if (_filter != null) {
+ return _domImpl.strippingIterator(iterator, _mapping, _filter);
+ }
+ return iterator;
}
public NodeIterator getTypedAxisIterator(final int axis, final int type) {
NodeIterator iterator;
if (axis == Axis.NAMESPACE) {
- if ((type == NO_TYPE) || (type > _NSreverse.length))
- iterator = _domImpl.getAxisIterator(axis);
- else
- iterator = _domImpl.getTypedAxisIterator(axis,_NSreverse[type]);
+ iterator = (type == NO_TYPE || type > _NSreverse.length) ?
+ _domImpl.getAxisIterator(axis) :
+ _domImpl.getTypedAxisIterator(axis,_NSreverse[type]);
}
- else
+ else {
iterator = _domImpl.getTypedAxisIterator(axis, _reverse[type]);
+ }
- if ((_reverse[type] == DOM.TEXT) && (_filter != null))
- iterator = _domImpl.strippingIterator(iterator,_mapping,_filter);
- return(iterator);
+ if (_reverse[type] == DOM.TEXT && _filter != null) {
+ iterator = _domImpl.strippingIterator(iterator, _mapping, _filter);
+ }
+ return iterator;
}
public NodeIterator getNthDescendant(int type, int n, boolean includeself) {
@@ -166,7 +183,8 @@
}
public NodeIterator getNodeValueIterator(NodeIterator iterator, int type,
- String value, boolean op) {
+ String value, boolean op)
+ {
return _domImpl.getNodeValueIterator(iterator, type, value, op);
}
@@ -278,4 +296,9 @@
return(_domImpl.isAttribute(node));
}
+ public String lookupNamespace(int node, String prefix)
+ throws TransletException
+ {
+ return _domImpl.lookupNamespace(node, prefix);
+ }
}
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 @@
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..f82c8df 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.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,8 +137,12 @@
// 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;
+ private String _documentURI = null;
+ static private int _documentURIIndex = 0;
// Support for access/navigation through org.w3c.dom API
private Node[] _nodes;
@@ -159,11 +164,11 @@
* Returns the origin of the document from which the tree was built
*/
public String getDocumentURI() {
- return(_documentURI);
+ return (_documentURI != null) ? _documentURI : "rtf" + _documentURIIndex++;
}
public String getDocumentURI(int node) {
- return(_documentURI);
+ return getDocumentURI();
}
public void setupMapping(String[] names, String[] namespaces) {
@@ -171,6 +176,37 @@
}
/**
+ * Lookup a namespace URI from a prefix starting at node. This method
+ * is used in the execution of xsl:element when the prefix is not known
+ * at compile time.
+ */
+ public String lookupNamespace(int node, String prefix)
+ throws TransletException
+ {
+ int anode, nsnode;
+ final AncestorIterator ancestors = new AncestorIterator();
+
+ if (isElement(node)) {
+ ancestors.includeSelf();
+ }
+
+ ancestors.setStartNode(node);
+ while ((anode = ancestors.next()) != NULL) {
+ final NodeIterator namespaces =
+ new NamespaceIterator().setStartNode(anode);
+
+ while ((nsnode = namespaces.next()) != NULL) {
+ if (_prefixArray[_prefix[nsnode]].equals(prefix)) {
+ return getNodeValue(nsnode);
+ }
+ }
+ }
+
+ // TODO: Internationalization?
+ throw new TransletException("Namespace prefix '" + prefix + "' is undeclared.");
+ }
+
+ /**
* Returns 'true' if a specific node is an element (of any type)
*/
public boolean isElement(final int node) {
@@ -206,11 +242,7 @@
// Hack for ordering attribute nodes
if (node1 >= _firstAttributeNode) node1 = _parent[node1];
if (node2 >= _firstAttributeNode) node2 = _parent[node2];
-
- if ((node2 < _treeNodeLimit) && (node1 < node2))
- return(true);
- else
- return(false);
+ return (node2 < _treeNodeLimit && node1 < node2);
}
/**
@@ -220,9 +252,8 @@
if (_nodes == null) {
_nodes = new Node[_type.length];
}
- return _nodes[index] != null
- ? _nodes[index]
- : (_nodes[index] = new NodeImpl(index));
+ return _nodes[index] != null ? _nodes[index]
+ : (_nodes[index] = new NodeImpl(index));
}
/**
@@ -240,9 +271,8 @@
if (_nodeLists == null) {
_nodeLists = new NodeList[_type.length];
}
- return _nodeLists[index] != null
- ? _nodeLists[index]
- : (_nodeLists[index] = new NodeListImpl(index));
+ return _nodeLists[index] != null ? _nodeLists[index]
+ : (_nodeLists[index] = new NodeListImpl(index));
}
/**
@@ -257,8 +287,7 @@
* Create an empty org.w3c.dom.NodeList
*/
private NodeList getEmptyNodeList() {
- return EmptyNodeList != null
- ? EmptyNodeList
+ return EmptyNodeList != null ? EmptyNodeList
: (EmptyNodeList = new NodeListImpl(new int[0]));
}
@@ -266,8 +295,7 @@
* Create an empty org.w3c.dom.NamedNodeMap
*/
private NamedNodeMap getEmptyNamedNodeMap() {
- return EmptyNamedNodeMap != null
- ? EmptyNamedNodeMap
+ return EmptyNamedNodeMap != null ? EmptyNamedNodeMap
: (EmptyNamedNodeMap = new NamedNodeMapImpl(new int[0]));
}
@@ -755,18 +783,19 @@
}
public NodeIterator reset() {
- if (hasChildren(_startNode))
- _currentChild = _offsetOrChild[_startNode];
- else
- _currentChild = END;
+ _currentChild = hasChildren(_startNode) ?
+ _offsetOrChild[_startNode] : END;
return resetPosition();
}
public int next() {
- for (int node = _currentChild; node != END;
- node = _nextSibling[node]) {
- if (_type[node] == _nodeType) {
- _currentChild = _nextSibling[node];
+ final short[] type = _type;
+ final int nodeType = _nodeType;
+ final int[] nextSibling = _nextSibling;
+
+ for (int node = _currentChild; node != END; node = nextSibling[node]) {
+ if (type[node] == nodeType) {
+ _currentChild = nextSibling[node];
return returnNode(node);
}
}
@@ -982,9 +1011,14 @@
_nodeType = nodeType;
}
- // assumes caller will pass element nodes
public NodeIterator setStartNode(int node) {
if (_isRestartable) {
+ // If not an element node, then set iterator at END
+ if (!isElement(node)) {
+ _attribute = END;
+ return resetPosition();
+ }
+
for (node = _lengthOrAttr[_startNode = node];
node != NULL && _type[node] != _nodeType;
node = _nextSibling[node]);
@@ -1053,6 +1087,7 @@
while ((_ns == DOM.NULL) && (_node != DOM.NULL)) {
_node = _parent[_node];
_ns = _lengthOrAttr[_node];
+
while ((_ns != DOM.NULL) && (_type[_ns] != NAMESPACE)) {
_ns = _nextSibling[_ns];
}
@@ -1376,12 +1411,15 @@
public NodeIterator setStartNode(int node) {
if (_isRestartable) {
_last = -1;
- if (node >= _firstAttributeNode)
- _startNode = node = _parent[node];
- else if (_includeSelf)
+ if (_includeSelf) {
_startNode = node;
- else
+ }
+ else if (node >= _firstAttributeNode) {
+ _startNode = node = _parent[node];
+ }
+ else {
_startNode = _parent[node];
+ }
_index = _startNode;
return resetPosition();
}
@@ -1395,12 +1433,9 @@
public int next() {
if (_index >= 0) {
- int bob = _index;
- if (_index == 0)
- _index = -1;
- else
- _index = _parent[_index];
- return returnNode(bob);
+ final int node = _index;
+ _index = (_index == 0) ? -1 : _parent[_index];
+ return returnNode(node);
}
return(NULL);
}
@@ -1482,7 +1517,9 @@
public int next() {
while (++_node < _limit) {
- if (_type[_node] > TEXT) return(returnNode(_node));
+ if (_type[_node] > TEXT) {
+ return(returnNode(_node));
+ }
}
return(NULL);
}
@@ -1946,10 +1983,7 @@
* Returns the type of a specific node
*/
public int getType(final int node) {
- if (node >= _type.length)
- return(0);
- else
- return _type[node];
+ return (node >= _type.length) ? 0 : _type[node];
}
/**
@@ -1957,10 +1991,8 @@
*/
public int getNamespaceType(final int node) {
final int type = _type[node];
- if (type >= NTYPES)
- return(_namespace[type-NTYPES]);
- else
- return(0); // default namespace
+ return (type >= NTYPES) ? _namespace[type-NTYPES]
+ : 0; // default namespace
}
/**
@@ -1980,20 +2012,16 @@
case ROOT:
return getNodeValue(_offsetOrChild[node]);
case TEXT:
+ // GTM - add escapign code here too.
case COMMENT:
return makeStringValue(node);
case PROCESSING_INSTRUCTION:
final String pistr = makeStringValue(node);
final int col = pistr.indexOf(' ');
- if (col > 0)
- return pistr.substring(col+1);
- else
- return pistr;
+ return (col > 0) ? pistr.substring(col+1) : pistr;
default:
- if (node < _firstAttributeNode)
- return getElementValue(node); // element string value
- else
- return makeStringValue(node); // attribute value
+ return (node < _firstAttributeNode) ? getElementValue(node) :
+ makeStringValue(node);
}
}
@@ -2061,20 +2089,16 @@
len = uri.length();
if (len > 0) len++;
}
-
- if ((name.length() > 0) && (name.charAt(len) == '@'))
- result[i] = (short)ATTRIBUTE;
- else
- result[i] = (short)ELEMENT;
+ result[i] = (short) ((name.length() > 0 && name.charAt(len) == '@') ?
+ ATTRIBUTE : ELEMENT);
}
// actual mapping of caller requested names
for (i = 0; i < namesLength; i++) {
result[getGeneralizedType(names[i])] = (short)(i + NTYPES);
}
-
- return(result);
+ return result;
}
/**
@@ -2093,7 +2117,7 @@
if (result[i + NTYPES] == ELEMENT)
result[i + NTYPES] = NO_TYPE;
}
- return(result);
+ return result;
}
/**
@@ -2127,15 +2151,11 @@
final int length = namespaces.length;
final short[] result = new short[length];
- for (i=0; i<length; i++) {
+ for (i = 0; i < length; i++) {
Integer type = (Integer)_nsIndex.get(namespaces[i]);
- if (type == null)
- result[i] = -1;
- else
- result[i] = type.shortValue();
+ result[i] = (type == null) ? -1 : type.shortValue();
}
-
- return(result);
+ return result;
}
/**
@@ -2162,6 +2182,13 @@
out.writeObject(_whitespace);
+ if (_dontEscape != null) {
+ out.writeObject(_dontEscape);
+ }
+ else {
+ out.writeObject(new BitArray(0));
+ }
+
out.flush();
}
@@ -2190,6 +2217,11 @@
_whitespace = (BitArray)in.readObject();
+ _dontEscape = (BitArray)in.readObject();
+ if (_dontEscape.size() == 0) {
+ _dontEscape = null;
+ }
+
_types = setupMapping(_namesArray);
}
@@ -2261,17 +2293,12 @@
return EMPTYSTRING;
case DOM.NAMESPACE:
final int index = _prefix[node];
- if (index < _prefixArray.length)
- return _prefixArray[index];
- else
- return EMPTYSTRING;
+ return (index < _prefixArray.length) ? _prefixArray[index]
+ : EMPTYSTRING;
case DOM.PROCESSING_INSTRUCTION:
final String pistr = makeStringValue(node);
final int col = pistr.indexOf(' ');
- if (col > -1)
- return(pistr.substring(0,col));
- else
- return pistr;
+ return (col > -1) ? pistr.substring(0,col) : pistr;
default:
// Construct the local part (omit '@' for attributes)
String name = getLocalName(node);
@@ -2281,8 +2308,9 @@
final int pi = _prefix[node];
if (pi > 0) {
final String prefix = _prefixArray[pi];
- if (prefix != EMPTYSTRING)
- name = prefix+':'+name;
+ if (prefix != EMPTYSTRING) {
+ name = prefix + ':' + name;
+ }
}
return name;
}
@@ -2298,10 +2326,7 @@
else {
final int type = getNamespaceType(node);
final String name = _uriArray[type];
- if (name == null)
- return(EMPTYSTRING);
- else
- return(name);
+ return (name == null) ? EMPTYSTRING : name;
}
}
@@ -2330,20 +2355,14 @@
*/
public String getAttributeValue(final int type, final int element) {
final int attr = getAttributeNode(type, element);
- if (attr != NULL)
- return makeStringValue(attr);
- else
- return EMPTYSTRING;
+ return (attr != NULL) ? makeStringValue(attr) : EMPTYSTRING;
}
/**
* Returns true if a given element has an attribute of a given type
*/
public boolean hasAttribute(final int type, final int node) {
- if (getAttributeNode(type, node) != NULL)
- return true;
- else
- return false;
+ return (getAttributeNode(type, node) != NULL);
}
/**
@@ -2369,10 +2388,8 @@
* Returns an iterator with all the children of a given node
*/
public NodeIterator getChildren(final int node) {
- if (hasChildren(node))
- return(new ChildrenIterator());
- else
- return(EMPTYITERATOR);
+ return hasChildren(node) ? new ChildrenIterator()
+ : EMPTYITERATOR;
}
/**
@@ -2440,66 +2457,58 @@
* containing nodes of a typed axis (ex.: child::foo)
*/
public NodeIterator getTypedAxisIterator(int axis, int type) {
- NodeIterator iterator = null;
-
/* This causes an error when using patterns for elements that
do not exist in the DOM (translet types which do not correspond
to a DOM type are mapped to the DOM.ELEMENT type).
*/
- if (type == NO_TYPE) {
- return(EMPTYITERATOR);
+ // Most common case handled first
+ if (axis == Axis.CHILD && type != ELEMENT) {
+ return new TypedChildrenIterator(type);
}
- else if ((type == ELEMENT) && (axis != Axis.NAMESPACE)) {
- iterator = new FilterIterator(getAxisIterator(axis),
- getElementFilter());
+
+ if (type == NO_TYPE) {
+ return EMPTYITERATOR;
+ }
+
+ if (type == ELEMENT && axis != Axis.NAMESPACE) {
+ return new FilterIterator(getAxisIterator(axis),
+ getElementFilter());
}
else {
switch (axis) {
case Axis.SELF:
- iterator = new TypedSingletonIterator(type);
- break;
- case Axis.CHILD:
- iterator = new TypedChildrenIterator(type);
- break;
+ return new TypedSingletonIterator(type);
case Axis.PARENT:
- return(new ParentIterator().setNodeType(type));
+ return new ParentIterator().setNodeType(type);
case Axis.ANCESTOR:
- return(new TypedAncestorIterator(type));
+ return new TypedAncestorIterator(type);
case Axis.ANCESTORORSELF:
- return((new TypedAncestorIterator(type)).includeSelf());
+ return (new TypedAncestorIterator(type)).includeSelf();
case Axis.ATTRIBUTE:
- return(new TypedAttributeIterator(type));
+ return new TypedAttributeIterator(type);
case Axis.DESCENDANT:
- iterator = new TypedDescendantIterator(type);
- break;
+ return new TypedDescendantIterator(type);
case Axis.DESCENDANTORSELF:
- iterator = (new TypedDescendantIterator(type)).includeSelf();
- break;
+ return (new TypedDescendantIterator(type)).includeSelf();
case Axis.FOLLOWING:
- iterator = new TypedFollowingIterator(type);
- break;
+ return new TypedFollowingIterator(type);
case Axis.PRECEDING:
- iterator = new TypedPrecedingIterator(type);
- break;
+ return new TypedPrecedingIterator(type);
case Axis.FOLLOWINGSIBLING:
- iterator = new TypedFollowingSiblingIterator(type);
- break;
+ return new TypedFollowingSiblingIterator(type);
case Axis.PRECEDINGSIBLING:
- iterator = new TypedPrecedingSiblingIterator(type);
- break;
+ return new TypedPrecedingSiblingIterator(type);
case Axis.NAMESPACE:
- if (type == ELEMENT)
- iterator = new NamespaceIterator();
- else
- iterator = new TypedNamespaceIterator(type);
- break;
+ return (type == ELEMENT) ?
+ (NodeIterator) new NamespaceIterator() :
+ (NodeIterator) new TypedNamespaceIterator(type);
default:
BasisLibrary.runTimeError(BasisLibrary.TYPED_AXIS_SUPPORT_ERR,
Axis.names[axis]);
}
}
- return(iterator);
+ return null;
}
/**
@@ -2510,26 +2519,21 @@
* nodes are taken, while 'ns' specifies the namespace URI type.
*/
public NodeIterator getNamespaceAxisIterator(int axis, int ns) {
-
- NodeIterator iterator = null;
-
if (ns == NO_TYPE) {
- return(EMPTYITERATOR);
+ return EMPTYITERATOR;
}
else {
switch (axis) {
case Axis.CHILD:
- iterator = new NamespaceChildrenIterator(ns);
- break;
+ return new NamespaceChildrenIterator(ns);
case Axis.ATTRIBUTE:
- iterator = new NamespaceAttributeIterator(ns);
- break;
+ return new NamespaceAttributeIterator(ns);
default:
BasisLibrary.runTimeError(BasisLibrary.TYPED_AXIS_SUPPORT_ERR,
Axis.names[axis]);
}
}
- return(iterator);
+ return null;
}
/**
@@ -2537,27 +2541,23 @@
* a given type.
*/
public NodeIterator getTypedDescendantIterator(int type) {
- NodeIterator iterator;
- if (type == ELEMENT)
- iterator = new FilterIterator(new DescendantIterator(),
- getElementFilter());
- else
- iterator = new TypedDescendantIterator(type);
- return(iterator);
+ return (type == ELEMENT) ? (NodeIterator)
+ new FilterIterator(new DescendantIterator(), getElementFilter())
+ : (NodeIterator) new TypedDescendantIterator(type);
}
/**
* Returns the nth descendant of a node
*/
public NodeIterator getNthDescendant(int type, int n, boolean includeself) {
- NodeIterator source;
- if (type == ELEMENT)
- source = new FilterIterator(new DescendantIterator(),
- getElementFilter());
- else
- source = new TypedDescendantIterator(type);
- if (includeself) ((NodeIteratorBase)source).includeSelf();
- return(new NthDescendantIterator(source, n, type));
+ NodeIterator source = (type == ELEMENT) ? (NodeIterator)
+ new FilterIterator(new DescendantIterator(), getElementFilter())
+ : (NodeIterator) new TypedDescendantIterator(type);
+
+ if (includeself) {
+ ((NodeIteratorBase)source).includeSelf();
+ }
+ return new NthDescendantIterator(source, n, type);
}
/**
@@ -2614,9 +2614,23 @@
_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 +2642,7 @@
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) {
@@ -2686,17 +2701,19 @@
* Performs a shallow copy (ref. XSLs copy())
*/
public String shallowCopy(final int node, TransletOutputHandler handler)
- throws TransletException {
-
+ throws TransletException
+ {
final int type = _type[node];
switch(type) {
case ROOT: // do nothing
return EMPTYSTRING;
case TEXT:
+
handler.characters(_text,
_offsetOrChild[node],
_lengthOrAttr[node]);
+
return null;
case PROCESSING_INSTRUCTION:
copyPI(node, handler);
@@ -2729,40 +2746,53 @@
private String copyElement(int node, int type,
TransletOutputHandler handler)
- throws TransletException {
-
+ throws TransletException
+ {
type = type - NTYPES;
String name = _namesArray[type];
final int pi = _prefix[node];
final int ui = _namespace[type];
+
if (pi > 0) {
final String prefix = _prefixArray[pi];
final String uri = _uriArray[ui];
final String local = getLocalName(node);
- if (prefix.equals(EMPTYSTRING))
- name = local;
- else
- name = prefix+':'+local;
+
+ name = prefix.equals(EMPTYSTRING) ? local : (prefix + ':' + local);
handler.startElement(name);
handler.namespace(prefix, uri);
}
else {
if (ui > 0) {
- handler.startElement(getLocalName(node));
+ handler.startElement(name = getLocalName(node));
handler.namespace(EMPTYSTRING, _uriArray[ui]);
}
else {
handler.startElement(name);
}
}
+
+ // Copy element namespaces
+ for (int a = _lengthOrAttr[node]; a != NULL; a = _nextSibling[a]) {
+ if (_type[a] == NAMESPACE) {
+ handler.namespace(_prefixArray[_prefix[a]],
+ makeStringValue(a));
+ }
+ }
+
return name;
}
/**
* Returns the string value of the entire tree
*/
+ private String _cachedStringValue = null;
+
public String getStringValue() {
- return getElementValue(ROOTNODE);
+ if (_cachedStringValue == null) {
+ _cachedStringValue = getElementValue(ROOTNODE);
+ }
+ return _cachedStringValue;
}
/**
@@ -2819,6 +2849,18 @@
if ((name = getNodeName(element)) != null) {
buffer.append('<');
buffer.append(name);
+
+ int attribute = _lengthOrAttr[element];
+ while (attribute != NULL) {
+ // Skip namespace nodes
+ if (_type[attribute] != NAMESPACE) {
+ buffer.append(' ').append(getNodeName(attribute))
+ .append("=\"").append(getNodeValue(attribute))
+ .append('"');
+ }
+ attribute = _nextSibling[attribute];
+ }
+
if (_offsetOrChild[element] == NULL) {
buffer.append("/>");
return buffer;
@@ -2899,8 +2941,7 @@
* 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 +3000,11 @@
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
@@ -2973,11 +3019,8 @@
private String getNamespaceURI(String prefix) {
// Get the stack associated with this namespace prefix
final Stack stack = (Stack)_nsPrefixes.get(prefix);
- if ((stack != null) && (!stack.empty())) {
- return((String)stack.peek());
- }
- else
- return(EMPTYSTRING);
+ return (stack != null && !stack.empty()) ? (String) stack.peek()
+ : EMPTYSTRING;
}
/**
@@ -3076,7 +3119,6 @@
*/
private short makeElementNode(String uri, String localname)
throws SAXException {
-
final String name;
if (uri != EMPTYSTRING)
name = uri + ':' + localname;
@@ -3170,6 +3212,7 @@
*/
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 +3231,14 @@
_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 +3268,34 @@
* 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);
}
+
+ // If local name is null set it to the empty string
+ if (localName == null) {
+ localName = EMPTYSTRING;
+ }
+
+ // 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) {
@@ -3273,13 +3325,14 @@
*/
public void characters(char[] ch, int start, int length) {
if (_currentOffset + length > _text.length) {
- // GTM resizeTextArray(_text.length * 2);
- // bug fix 6189, contributed by Mirko Seifert
resizeTextArray(
Math.max(_text.length * 2, _currentOffset + length));
}
System.arraycopy(ch, start, _text, _currentOffset, length);
_currentOffset += length;
+
+ _disableEscaping = !_escaping;
+
}
/**
@@ -3295,7 +3348,7 @@
_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 +3427,52 @@
_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;
+ }
}
}
+ // If local name is null set it to the empty string
+ if (localName == null) {
+ localName = EMPTYSTRING;
+ }
+
// 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?
+ _nextSibling2[(!attrsAdded && last != -1) ? last : attr] = DOM.NULL;
}
final int col = qname.lastIndexOf(':');
// Assign an internal type to this element (may exist)
- if ((uri != null) && (localName.length() > 0))
- _type[node] = makeElementNode(uri, localName);
- else
- _type[node] = makeElementNode(qname, col);
+ _type[node] = (uri != null && localName.length() > 0) ?
+ makeElementNode(uri, localName) : makeElementNode(qname, col);
// Assign an internal type to the element's prefix (may exist)
if (col > -1) {
@@ -3451,7 +3515,8 @@
*/
public void ignorableWhitespace(char[] ch, int start, int length) {
if (_currentOffset + length > _text.length) {
- resizeTextArray(_text.length * 2);
+ resizeTextArray(
+ Math.max(_text.length * 2, _currentOffset + length));
}
System.arraycopy(ch, start, _text, _currentOffset, length);
_currentOffset += length;
@@ -3502,7 +3567,8 @@
else
_nextSibling2[attr-1] = attr;
_nextSibling2[attr] = DOM.NULL;
- _prefix2[attr] = idx.shortValue();
+ // _prefix2[attr] = idx.shortValue();
+ _prefix2[attr] = ((Integer) stack.elementAt(0)).shortValue();
}
}
@@ -3521,7 +3587,8 @@
public void comment(char[] ch, int start, int length) {
makeTextNode(false);
if (_currentOffset + length > _text.length) {
- resizeTextArray(_text.length * 2);
+ resizeTextArray(
+ Math.max(_text.length * 2, _currentOffset + length));
}
System.arraycopy(ch, start, _text, _currentOffset, length);
_currentOffset += length;
@@ -3546,8 +3613,6 @@
private void characters(final String string) {
final int length = string.length();
if (_currentOffset + length > _text.length) {
- // GTM: resizeTextArray(_text.length * 2);
- // bug fix 6189, contributed by Mirko Seifert
resizeTextArray(
Math.max(_text.length * 2, _currentOffset + length));
}
@@ -3587,6 +3652,11 @@
// 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 +3726,11 @@
}
}
+ public boolean setEscaping(boolean value) {
+ final boolean temp = _escaping;
+ _escaping = value;
+ return temp;
+ }
+
} // end of DOMBuilder
}
diff --git a/src/org/apache/xalan/xsltc/compiler/LongExpr.java b/src/org/apache/xalan/xsltc/dom/ExtendedSAX.java
similarity index 77%
rename from src/org/apache/xalan/xsltc/compiler/LongExpr.java
rename to src/org/apache/xalan/xsltc/dom/ExtendedSAX.java
index e650658..8e87428 100644
--- a/src/org/apache/xalan/xsltc/compiler/LongExpr.java
+++ b/src/org/apache/xalan/xsltc/dom/ExtendedSAX.java
@@ -56,34 +56,14 @@
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
- * @author G. Todd Miller
+ * @author Morten Jorgensen
*
*/
+package org.apache.xalan.xsltc.dom;
-package org.apache.xalan.xsltc.compiler;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ext.LexicalHandler;
-import org.apache.xalan.xsltc.compiler.util.Type;
-import org.apache.bcel.generic.*;
-import org.apache.xalan.xsltc.compiler.util.*;
-
-final class LongExpr extends Expression {
- private final long _value;
-
- public LongExpr(long value) {
- _value = value;
- }
-
- public Type typeCheck(SymbolTable stable) throws TypeCheckError {
- return _type = Type.Lng;
- }
-
- public String toString() {
- return "long-expr(" + _value + ')';
- }
-
- public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
- ConstantPoolGen cpg = classGen.getConstantPool();
- InstructionList il = methodGen.getInstructionList();
- il.append(new PUSH(cpg, _value));
- }
+public interface ExtendedSAX extends ContentHandler, LexicalHandler {
+ public boolean setEscaping(boolean escape);
}
diff --git a/src/org/apache/xalan/xsltc/dom/MultiDOM.java b/src/org/apache/xalan/xsltc/dom/MultiDOM.java
index 95b7b87..95bfa77 100644
--- a/src/org/apache/xalan/xsltc/dom/MultiDOM.java
+++ b/src/org/apache/xalan/xsltc/dom/MultiDOM.java
@@ -76,6 +76,7 @@
import org.apache.xalan.xsltc.runtime.BasisLibrary;
public final class MultiDOM implements DOM {
+
private static final int NO_TYPE = DOM.FIRST_TYPE - 2;
private static final int INITIAL_SIZE = 4;
private static final int CLR = 0x00FFFFFF;
@@ -88,12 +89,11 @@
private Hashtable _documents = new Hashtable();
private final class AxisIterator implements NodeIterator {
- // constitutive data
private final int _axis;
private final int _type;
- // implementation mechanism
- private NodeIterator _source;
+
private int _mask;
+ private NodeIterator _source = null;
public AxisIterator(final int axis, final int type) {
_axis = axis;
@@ -112,18 +112,23 @@
}
public NodeIterator setStartNode(final int node) {
- _mask = node & SET;
- int dom = node >>> 24;
- // consider caching these
- if ((_type == NO_TYPE) || (_type == DOM.ELEMENT)) {
- _source = _adapters[dom].getAxisIterator(_axis);
+ final int dom = node >>> 24;
+ final int mask = node & SET;
+
+ // Get a new source first time and when mask changes
+ if (_source == null || _mask != mask) {
+ if (_type == NO_TYPE) {
+ _source = _adapters[dom].getAxisIterator(_axis);
+ }
+ else if (_axis == Axis.CHILD && _type != ELEMENT) {
+ _source = _adapters[dom].getTypedChildren(_type);
+ }
+ else {
+ _source = _adapters[dom].getTypedAxisIterator(_axis, _type);
+ }
}
- else if (_axis == Axis.CHILD) {
- _source = _adapters[dom].getTypedChildren(_type);
- }
- else {
- _source = _adapters[dom].getTypedAxisIterator(_axis,_type);
- }
+
+ _mask = mask;
_source.setStartNode(node & CLR);
return this;
}
@@ -142,10 +147,7 @@
}
public boolean isReverse() {
- if (_source == null)
- return(false);
- else
- return _source.isReverse();
+ return (_source == null) ? false : _source.isReverse();
}
public void setMark() {
@@ -262,8 +264,7 @@
// This method only has a function in DOM adapters
}
- public int addDOMAdapter(DOM dom) {
-
+ public int addDOMAdapter(DOMAdapter dom) {
// Add the DOM adapter to the array of DOMs
final int domNo = _free++;
if (domNo == _size) {
@@ -275,9 +276,11 @@
// Store reference to document (URI) in hashtable
String uri = dom.getDocumentURI(0);
- _documents.put(uri,new Integer(domNo));
+ _documents.put(uri, new Integer(domNo));
- return domNo << 24;
+ // Store mask in DOMAdapter
+ dom.setMultiDOMMask(domNo << 24);
+ return (domNo << 24);
}
public int getDocumentMask(String uri) {
@@ -288,7 +291,9 @@
return((domIdx.intValue() << 24));
}
- /** returns singleton iterator containg the document root */
+ /**
+ * Returns singleton iterator containg the document root
+ */
public NodeIterator getIterator() {
// main source document @ 0
return _adapters[0].getIterator();
@@ -453,4 +458,9 @@
return(_adapters[node>>>24].isAttribute(node & CLR));
}
+ public String lookupNamespace(int node, String prefix)
+ throws TransletException
+ {
+ return _adapters[node>>>24].lookupNamespace(node, prefix);
+ }
}
diff --git a/src/org/apache/xalan/xsltc/dom/NodeIteratorBase.java b/src/org/apache/xalan/xsltc/dom/NodeIteratorBase.java
index 310ae5e..78d56a4 100644
--- a/src/org/apache/xalan/xsltc/dom/NodeIteratorBase.java
+++ b/src/org/apache/xalan/xsltc/dom/NodeIteratorBase.java
@@ -83,7 +83,8 @@
public NodeIterator reset() {
final boolean temp = _isRestartable;
_isRestartable = true;
- setStartNode(_startNode);
+ // Must adjust _startNode if self is included
+ setStartNode(_includeSelf ? _startNode + 1 : _startNode);
_isRestartable = temp;
return this;
}
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 @@
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 @@
_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/StepIterator.java b/src/org/apache/xalan/xsltc/dom/StepIterator.java
index fe4cdbe..8edb6b3 100644
--- a/src/org/apache/xalan/xsltc/dom/StepIterator.java
+++ b/src/org/apache/xalan/xsltc/dom/StepIterator.java
@@ -104,12 +104,10 @@
if (_isRestartable) {
// Set start node for left-hand iterator...
_source.setStartNode(_startNode = node);
+
// ... and get start node for right-hand iterator from left-hand,
// with special case for //* path - see ParentLocationPath
- if (_includeSelf)
- _iterator.setStartNode(_startNode);
- else
- _iterator.setStartNode(_source.next());
+ _iterator.setStartNode(_includeSelf ? _startNode : _source.next());
return resetPosition();
}
return this;
@@ -118,10 +116,7 @@
public NodeIterator reset() {
_source.reset();
// Special case for //* path - see ParentLocationPath
- if (_includeSelf)
- _iterator.setStartNode(_startNode);
- else
- _iterator.setStartNode(_source.next());
+ _iterator.setStartNode(_includeSelf ? _startNode : _source.next());
return resetPosition();
}
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 @@
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..8bffb59 100644
--- a/src/org/apache/xalan/xsltc/runtime/AbstractTranslet.java
+++ b/src/org/apache/xalan/xsltc/runtime/AbstractTranslet.java
@@ -65,8 +65,8 @@
package org.apache.xalan.xsltc.runtime;
-import java.io.File;
-import java.util.Vector;
+import java.io.FileWriter;
+import java.util.ArrayList;
import java.util.Enumeration;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
@@ -77,6 +77,7 @@
import org.apache.xalan.xsltc.dom.KeyIndex;
import org.apache.xalan.xsltc.dom.DTDMonitor;
import org.apache.xalan.xsltc.util.IntegerArray;
+import org.apache.xalan.xsltc.runtime.output.*;
public abstract class AbstractTranslet implements Translet {
@@ -103,6 +104,25 @@
// Use one empty string instead of constantly instanciating String("");
private final static String EMPTYSTRING = "";
+
+ /************************************************************************
+ * Debugging
+ ************************************************************************/
+ public void printInternalState() {
+ System.out.println("-------------------------------------");
+ System.out.println("AbstractTranslet this = " + this);
+ System.out.println("vbase = " + vbase);
+ System.out.println("vframe = " + vframe);
+ System.out.println("varsStack.size() = " + varsStack.size());
+ System.out.println("pbase = " + pbase);
+ System.out.println("vframe = " + pframe);
+ System.out.println("paramsStack.size() = " + paramsStack.size());
+ System.out.println("namesArray.size = " + namesArray.length);
+ System.out.println("namespaceArray.size = " + namespaceArray.length);
+ System.out.println("");
+ System.out.println("Total memory = " + Runtime.getRuntime().totalMemory());
+ }
+
/**
* Wrap the initial input DOM in a dom adapter. This adapter is wrapped in
* a DOM multiplexer if the document() function is used (handled by compiled
@@ -123,18 +143,18 @@
// Variable's stack: <tt>vbase</tt> and <tt>vframe</tt> are used
// to denote the current variable frame.
protected int vbase = 0, vframe = 0;
- protected Vector varsStack = new Vector();
+ protected ArrayList varsStack = new ArrayList();
// Parameter's stack: <tt>pbase</tt> and <tt>pframe</tt> are used
// to denote the current parameter frame.
protected int pbase = 0, pframe = 0;
- protected Vector paramsStack = new Vector();
+ protected ArrayList paramsStack = new ArrayList();
/**
* Push a new parameter frame.
*/
public final void pushParamFrame() {
- paramsStack.insertElementAt(new Integer(pbase), pframe);
+ paramsStack.add(pframe, new Integer(pbase));
pbase = ++pframe;
}
@@ -143,51 +163,21 @@
*/
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.get(--pbase)).intValue();
+ for (int i = pframe - 1; i >= pbase; i--) {
+ paramsStack.remove(i);
}
+ 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) {
- String parName = new String(name);
- parName = replace(parName, '.', "$dot$");
- parName = replace(parName, '-', "$dash$");
- return addParameter(parName, value, false);
+ name = BasisLibrary.replace(name, ".-",
+ new String[] { "$dot$", "$dash$" });
+ return addParameter(name, value, false);
}
/**
@@ -196,16 +186,17 @@
* default value from the <xsl:parameter> element's select attribute or
* element body.
*/
- public final Object addParameter(String name, Object value,
- boolean isDefault) {
-
+ public final Object addParameter(String name, Object value,
+ boolean isDefault)
+ {
// Local parameters need to be re-evaluated for each iteration
for (int i = pframe - 1; i >= pbase; i--) {
- final Parameter param = (Parameter) paramsStack.elementAt(i);
+ final Parameter param = (Parameter) paramsStack.get(i);
+
if (param._name.equals(name)) {
// Only overwrite if current value is the default value and
// the new value is _NOT_ the default value.
- if ((param._isDefault == true) || (!isDefault)) {
+ if (param._isDefault || !isDefault) {
param._value = value;
param._isDefault = isDefault;
return value;
@@ -215,8 +206,7 @@
}
// Add new parameter to parameter stack
- final Parameter param = new Parameter(name, value, isDefault);
- paramsStack.insertElementAt(param, pframe++);
+ paramsStack.add(pframe++, new Parameter(name, value, isDefault));
return value;
}
@@ -224,6 +214,7 @@
* Clears the parameter stack.
*/
public void clearParameters() {
+ pbase = pframe = 0;
paramsStack.clear();
}
@@ -233,7 +224,7 @@
*/
public final Object getParameter(String name) {
for (int i = pframe - 1; i >= pbase; i--) {
- final Parameter param = (Parameter)paramsStack.elementAt(i);
+ final Parameter param = (Parameter)paramsStack.get(i);
if (param._name.equals(name)) return param._value;
}
return null;
@@ -243,9 +234,14 @@
* Push a new variable frame.
*/
public final void pushVarFrame(int frameSize) {
- varsStack.insertElementAt(new Integer(vbase), vframe);
+ varsStack.add(vframe, new Integer(vbase));
vbase = ++vframe;
vframe += frameSize;
+
+ // Clear stack frame
+ for (int i = vbase; i <= vframe + 1; i++) {
+ varsStack.add(i, null);
+ }
}
/**
@@ -253,16 +249,11 @@
*/
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.get(--vbase)).intValue();
+ for (int i = vbase; i < vframe; i++) {
+ varsStack.set(i, null); // for the GC
}
+ vframe = vbase; vbase = oldvbase;
}
}
@@ -270,18 +261,14 @@
* 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);
+ return varsStack.get(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.set(vbase + vindex, value);
}
/************************************************************************
@@ -501,17 +488,23 @@
************************************************************************/
public TransletOutputHandler openOutputHandler(String filename)
- throws TransletException {
+ throws TransletException
+ {
try {
- // Use the default SAX handler to send the output to the file
- DefaultSAXOutputHandler handler =
- new DefaultSAXOutputHandler(filename, _encoding);
+ final TransletOutputHandlerFactory factory
+ = TransletOutputHandlerFactory.newInstance();
- // Create a translet output handler and plug in the SAX handler
- TextOutput text = new TextOutput(handler, handler, _encoding);
- transferOutputSettings(text);
- text.startDocument();
- return(text);
+ factory.setEncoding(_encoding);
+ factory.setOutputMethod(_method);
+ factory.setWriter(new FileWriter(filename));
+ factory.setOutputType(TransletOutputHandlerFactory.STREAM);
+
+ final TransletOutputHandler handler
+ = factory.getTransletOutputHandler();
+
+ transferOutputSettings(handler);
+ handler.startDocument();
+ return handler;
}
catch (Exception e) {
throw new TransletException(e);
@@ -569,46 +562,43 @@
/**
* Transfer the output settings to the output post-processor
*/
- protected void transferOutputSettings(TransletOutputHandler output) {
-
- // It is an error if this method is called with anything else than
- // the translet post-processor (TextOutput)
- if (!(output instanceof TextOutput)) return;
-
- TextOutput handler = (TextOutput)output;
-
- // Transfer the output method setting
+ protected void transferOutputSettings(TransletOutputHandler handler) {
if (_method != null) {
- // Transfer all settings relevant to XML output
if (_method.equals("xml")) {
- if (_standalone != null) handler.setStandalone(_standalone);
- handler.setType(TextOutput.XML);
+ if (_standalone != null) {
+ handler.setStandalone(_standalone);
+ }
+ if (_omitHeader) {
+ handler.omitHeader(true);
+ }
handler.setCdataElements(_cdata);
- if (_version != null) handler.setVersion(_version);
- if (_omitHeader) handler.omitHeader(true);
+ if (_version != null) {
+ handler.setVersion(_version);
+ }
handler.setIndent(_indent);
- if (_doctypeSystem != null)
+ if (_doctypeSystem != null) {
handler.setDoctype(_doctypeSystem, _doctypePublic);
+ }
}
- // Transfer all output settings relevant to HTML output
else if (_method.equals("html")) {
- handler.setType(TextOutput.HTML);
handler.setIndent(_indent);
handler.setDoctype(_doctypeSystem, _doctypePublic);
- if (_mediaType != null) handler.setMediaType(_mediaType);
- }
- else if (_method.equals("text")) {
- handler.setType(TextOutput.TEXT);
- }
- else {
- handler.setType(TextOutput.QNAME);
+ if (_mediaType != null) {
+ handler.setMediaType(_mediaType);
+ }
}
}
else {
handler.setCdataElements(_cdata);
- if (_version != null) handler.setVersion(_version);
- if (_standalone != null) handler.setStandalone(_standalone);
- if (_omitHeader) handler.omitHeader(true);
+ if (_version != null) {
+ handler.setVersion(_version);
+ }
+ if (_standalone != null) {
+ handler.setStandalone(_standalone);
+ }
+ if (_omitHeader) {
+ handler.omitHeader(true);
+ }
handler.setIndent(_indent);
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..93f8f0c 100644
--- a/src/org/apache/xalan/xsltc/runtime/BasisLibrary.java
+++ b/src/org/apache/xalan/xsltc/runtime/BasisLibrary.java
@@ -79,6 +79,10 @@
import org.apache.xalan.xsltc.*;
import org.apache.xalan.xsltc.DOM;
import org.apache.xalan.xsltc.NodeIterator;
+import org.apache.xalan.xsltc.dom.Axis;
+import org.apache.xalan.xsltc.dom.DOMAdapter;
+import org.apache.xalan.xsltc.dom.MultiDOM;
+import org.apache.xalan.xsltc.dom.AbsoluteIterator;
import org.apache.xalan.xsltc.dom.SingletonIterator;
/**
@@ -427,7 +431,7 @@
if (name.equals("xsl:version"))
return("1.0");
if (name.equals("xsl:vendor"))
- return("Apache Xalan XSLTC");
+ return("Apache Software Foundation (Xalan XSLTC)");
if (name.equals("xsl:vendor-url"))
return("http://xml.apache.org/xalan-j");
@@ -447,6 +451,15 @@
return EMPTYSTRING;
}
+ /**
+ * Implements the nodeset() extension function.
+ */
+ public static NodeIterator nodesetF(DOM rtf) {
+ final DOMAdapter adapter = (DOMAdapter) rtf;
+ return new SingletonIterator(
+ DOM.ROOTNODE | adapter.getMultiDOMMask(), true);
+ }
+
//-- Begin utility functions
private static boolean isWhiteSpace(char ch) {
@@ -877,6 +890,31 @@
try {
StringBuffer result = new StringBuffer();
formatter.applyLocalizedPattern(pattern);
+
+ //------------------------------------------------------
+ // bug fix # 9179 - make sure localized pattern contains
+ // a leading zero before decimal, handle cases where
+ // decimal is in position zero, and >= to 1.
+ // localized pattern is ###.### convert to ##0.###
+ // localized pattern is .### convert to 0.###
+ //------------------------------------------------------
+ String localizedPattern = formatter.toPattern();
+ int index = localizedPattern.indexOf('.');
+ if ( index >= 1 && localizedPattern.charAt(index-1) == '#' ) {
+ //insert a zero before the decimal point in the pattern
+ StringBuffer newpattern = new StringBuffer();
+ newpattern.append(localizedPattern.substring(0, index-1));
+ newpattern.append("0");
+ newpattern.append(localizedPattern.substring(index));
+ formatter.applyLocalizedPattern(newpattern.toString());
+ } else if (index == 0) {
+ // insert a zero before decimal point in pattern
+ StringBuffer newpattern = new StringBuffer();
+ newpattern.append("0");
+ newpattern.append(localizedPattern);
+ formatter.applyLocalizedPattern(newpattern.toString());
+ }
+
formatter.format(number, result, _fieldPosition);
return(result.toString());
}
@@ -891,28 +929,31 @@
* obj is an instanceof Node then create a singleton iterator.
*/
public static NodeIterator referenceToNodeSet(Object obj) {
- try {
- // Convert var/param -> node
- if (obj instanceof Node) {
- return(new SingletonIterator(((Node)obj).node));
- }
- // Convert var/param -> node-set
- else if (obj instanceof NodeIterator) {
- return(((NodeIterator)obj).cloneIterator());
- }
- // Convert var/param -> result-tree fragment
- else if (obj instanceof DOM) {
- DOM dom = (DOM)obj;
- return(dom.getIterator());
- }
- else {
- final String className = obj.getClass().getName();
- runTimeError(DATA_CONVERSION_ERR, "reference", className);
- return null;
- }
+ // Convert var/param -> node
+ if (obj instanceof Node) {
+ return(new SingletonIterator(((Node)obj).node));
}
- catch (ClassCastException e) {
- runTimeError(DATA_CONVERSION_ERR, "reference", "node-set");
+ // Convert var/param -> node-set
+ else if (obj instanceof NodeIterator) {
+ return(((NodeIterator)obj).cloneIterator());
+ }
+ else {
+ final String className = obj.getClass().getName();
+ runTimeError(DATA_CONVERSION_ERR, "reference", className);
+ return null;
+ }
+ }
+
+ /**
+ * Utility function used to convert references to DOMs.
+ */
+ public static DOM referenceToResultTree(Object obj) {
+ try {
+ return ((DOM) obj);
+ }
+ catch (IllegalArgumentException e) {
+ final String className = obj.getClass().getName();
+ runTimeError(DATA_CONVERSION_ERR, "reference", className);
return null;
}
}
@@ -960,6 +1001,29 @@
}
}
+ /**
+ * This function is used in the execution of xsl:element
+ */
+ public static String getPrefix(String qname) {
+ final int index = qname.indexOf(':');
+ return (index > 0) ? qname.substring(0, index) : null;
+ }
+
+ /**
+ * This function is used in the execution of xsl:element
+ */
+ private static int prefixIndex = 0;
+ public static String generatePrefix() {
+ return ("ns" + prefixIndex++);
+ }
+
+ /**
+ * This function is used in the execution of xsl:element
+ */
+ public static String makeQName(String localName, String prefix) {
+ return (new StringBuffer(prefix).append(':').append(localName).toString());
+ }
+
public static final int RUN_TIME_INTERNAL_ERR = 0;
public static final int RUN_TIME_COPY_ERR = 1;
public static final int DATA_CONVERSION_ERR = 2;
@@ -1011,5 +1075,31 @@
System.out.println(msg);
}
+ /**
+ * Replace a certain character in a string with a new substring.
+ */
+ public static String replace(String base, char ch, String str) {
+ return (base.indexOf(ch) < 0) ? base :
+ replace(base, String.valueOf(ch), new String[] { str });
+ }
+
+ public static String replace(String base, String delim, String[] str) {
+ final int len = base.length();
+ final StringBuffer result = new StringBuffer();
+
+ for (int i = 0; i < len; i++) {
+ final char ch = base.charAt(i);
+ final int k = delim.indexOf(ch);
+
+ if (k >= 0) {
+ result.append(str[k]);
+ }
+ else {
+ result.append(ch);
+ }
+ }
+ return result.toString();
+ }
+
//-- End utility functions
}
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 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/DefaultRun.java b/src/org/apache/xalan/xsltc/runtime/DefaultRun.java
deleted file mode 100644
index 6b66121..0000000
--- a/src/org/apache/xalan/xsltc/runtime/DefaultRun.java
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * @(#)$Id$
- *
- * The Apache Software License, Version 1.1
- *
- *
- * Copyright (c) 2001 The Apache Software Foundation. All rights
- * reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The end-user documentation included with the redistribution,
- * if any, must include the following acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Xalan" and "Apache Software Foundation" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * nor may "Apache" appear in their name, without prior written
- * permission of the Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- * ====================================================================
- *
- * This software consists of voluntary contributions made by many
- * individuals on behalf of the Apache Software Foundation and was
- * originally based on software copyright (c) 2001, Sun
- * Microsystems., http://www.sun.com. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- *
- * @author Jacek Ambroziak
- * @author Santiago Pericas-Geertsen
- * @author G. Todd Miller
- * @author Morten Jorgensen
- *
- */
-
-package org.apache.xalan.xsltc.runtime;
-
-import java.io.*;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.UnknownHostException;
-import java.util.Vector;
-
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.xml.sax.XMLReader;
-import org.xml.sax.SAXException;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.ext.LexicalHandler;
-
-import org.apache.xalan.xsltc.*;
-import org.apache.xalan.xsltc.dom.DOMImpl;
-import org.apache.xalan.xsltc.dom.Axis;
-import org.apache.xalan.xsltc.dom.DTDMonitor;
-import org.apache.xalan.xsltc.runtime.Constants;
-
-final public class DefaultRun {
-
- private TransletOutputHandler _handler;
-
- private String _fileName;
- private String _className;
- private String _jarFileSrc;
- private boolean _isJarFileSpecified = false;
- private Vector _params = null;
- private boolean _uri, _debug;
-
- AbstractTranslet _translet;
-
- public DefaultRun(String className, String fileName,
- boolean uri, boolean debug) {
- _fileName = fileName;
- _className = className;
- _uri = uri;
- _debug = debug;
- }
-
- public void setParameters(Vector params) {
- _params = params;
- }
-
- private void setJarFileInputSrc(boolean flag, String jarFile) {
- // TODO: at this time we do not do anything with this
- // information, attempts to add the jarfile to the CLASSPATH
- // were successful via System.setProperty, but the effects
- // were not visible to the running JVM. For now we add jarfile
- // to CLASSPATH in the wrapper script that calls this program.
- _isJarFileSpecified = flag;
- // TODO verify jarFile exists...
- _jarFileSrc = jarFile;
- }
-
- private void doTransform() {
- try {
- final Class clazz = Class.forName(_className);
- final Translet translet = (Translet)clazz.newInstance();
-
- // Create a SAX parser and get the XMLReader object it uses
- final SAXParserFactory factory = SAXParserFactory.newInstance();
- try {
- factory.setFeature(Constants.NAMESPACE_FEATURE, true);
- }
- catch (Exception e) {
- factory.setNamespaceAware(true);
- }
- final SAXParser parser = factory.newSAXParser();
- final XMLReader reader = parser.getXMLReader();
-
- // Set the DOM's DOM builder as the XMLReader's SAX2 content handler
- final DOMImpl dom = new DOMImpl();
- reader.setContentHandler(dom.getBuilder());
- // Create a DTD monitor and pass it to the XMLReader object
- final DTDMonitor dtdMonitor = new DTDMonitor();
- dtdMonitor.handleDTD(reader);
-
- _translet = (AbstractTranslet)translet;
- dom.setDocumentURI(_fileName);
- if (_uri)
- reader.parse(_fileName);
- else {
- reader.parse(new File(_fileName).toURL().toExternalForm());
- }
-
- // Set size of key/id indices
- _translet.setIndexSize(dom.getSize());
- // If there are any elements with ID attributes, build an index
- dtdMonitor.buildIdIndex(dom, 0, _translet);
-
- _translet.setDTDMonitor(dtdMonitor);
-
- // Pass global parameters
- int n = _params.size();
- for (int i = 0; i < n; i++) {
- Parameter param = (Parameter) _params.elementAt(i);
- translet.addParameter(param._name, param._value);
- }
-
- // Transform the document
- String encoding = _translet._encoding;
-
- DefaultSAXOutputHandler saxHandler =
- new DefaultSAXOutputHandler(System.out, encoding);
- TextOutput textOutput =
- new TextOutput((ContentHandler)saxHandler,
- (LexicalHandler)saxHandler, encoding);
- translet.transform(dom, textOutput);
-
- if (_debug) {
- TransletOutputBase handler = new TransletOutputBase();
- long start = System.currentTimeMillis();
- final int nTimes = 100;
- for (int i = 0; i < nTimes; i++)
- translet.transform(dom, dom.getIterator(), handler);
- long end = System.currentTimeMillis();
- System.out.println("total " + (end - start) + " msec for "
- + nTimes + " transformations");
- System.out.println(((double)end - start)/nTimes + " msec avg");
- }
- }
- catch (TransletException e) {
- System.err.println("\nTranslet Error: " + e.getMessage());
- if (_debug) {
- System.err.println(e.toString());
- e.printStackTrace();
- }
- doSystemExit(1);
- }
- catch (RuntimeException e) {
- System.err.println("\nRuntime Error: " + e.getMessage());
- if (_debug) {
- System.err.println(e.toString());
- e.printStackTrace();
- }
- doSystemExit(1);
- }
- catch (FileNotFoundException e) {
- System.err.println("Error: File or URI '"+_fileName+"' not found.");
- doSystemExit(1);
- }
- catch (MalformedURLException e) {
- System.err.println("Error: Invalid URI '"+_fileName+"'.");
- doSystemExit(1);
- }
- catch (ClassNotFoundException e) {
- System.err.println("Error: Cannot find class '"+_className+"'.");
- doSystemExit(1);
- }
- catch (UnknownHostException e) {
- System.err.println("Error: Can't resolve URI specification '"+
- _fileName+"'.");
- doSystemExit(1);
- }
- catch (Exception e) {
- e.printStackTrace();
- System.err.println("Error: internal error.");
- doSystemExit(1);
- }
- }
-
- /** If we should call System.exit or not */
- protected static boolean allowSystemExit = true;
-
- /** Worker method to call System.exit or not */
- protected static void doSystemExit(int retVal) {
- if (allowSystemExit)
- System.exit(retVal);
- }
-
- private final static String USAGE_STRING =
- "Usage: \n" +
- " xslt [-j <jarfile>] {-u <document_url> | <document>} <class>\n"+
- " [<name1>=<value1> ...]\n\n" +
- " <document> is the xml document to be transformed, or\n" +
- " <document_url> is a url for the xml document,\n" +
- " <class> is the translet class which is either in\n" +
- " user's CLASSPATH or in the <jarfile> specified \n" +
- " with the -j option.\n" +
- " also: [-x] (debug), [-s] (don't allow System.exit)";
-
- public static void printUsage() {
- System.err.println(USAGE_STRING);
- System.exit(1);
- }
-
- public static void main(String[] args) {
- try {
- if (args.length > 0) {
- int i;
- boolean uri = false, debug = false;
- boolean isJarFileSpecified = false;
- String jarFile = null;
-
- // Parse options starting with '-'
- for (i = 0; i < args.length && args[i].charAt(0) == '-'; i++) {
- if (args[i].equals("-u")) {
- uri = true;
- }
- else if (args[i].equals("-s")){
- allowSystemExit = false;
- }
- else if (args[i].equals("-x")) {
- debug = true;
- }
- else if (args[i].equals("-j")) {
- isJarFileSpecified = true;
- jarFile = args[++i];
- }
- else {
- printUsage();
- }
- }
-
- // Enough arguments left ?
- if (args.length - i < 2) {
- printUsage();
- }
-
- // Get document file and class name
- DefaultRun handler = new DefaultRun(args[i+1], args[i],
- uri, debug);
- handler.setJarFileInputSrc(isJarFileSpecified, jarFile);
-
- // Parse stylesheet parameters
- Vector params = new Vector();
- for (i += 2; i < args.length; i++) {
- int equal = args[i].indexOf('=');
- if (equal > 0) {
- final Parameter param =
- new Parameter(args[i].substring(0, equal),
- args[i].substring(equal + 1,
- args[i].length()));
- params.addElement(param);
- }
- else {
- printUsage();
- }
- }
-
- if (i == args.length) {
- handler.setParameters(params);
- handler.doTransform();
- doSystemExit(0);
- }
- }else{
- printUsage();
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- }
- }
-}
diff --git a/src/org/apache/xalan/xsltc/runtime/DefaultSAXOutputHandler.java b/src/org/apache/xalan/xsltc/runtime/DefaultSAXOutputHandler.java
index 37e3c3e..f808a3c 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 @@
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
@@ -213,11 +215,11 @@
buffer.append(_version);
buffer.append("\" encoding=\"");
buffer.append(_encoding);
- if (_standalone != null) {
+ if ( _standalone != null ) {
buffer.append("\" standalone=\"");
buffer.append(_standalone);
}
- buffer.append("\" ?>\n");
+ buffer.append("\"?>\n");
characters(buffer.toString());
}
@@ -239,7 +241,8 @@
/**
* 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 @@
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 @@
_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 @@
* 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..f77f890 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,18 +99,22 @@
public void endDocument() throws TransletException {
try {
- _saxHandler.endDocument();
+ _domBuilder.endDocument();
}
catch (SAXException e) {
throw new TransletException(e);
}
}
+ public void characters(String characters) throws TransletException {
+ characters(characters.toCharArray(), 0, characters.length());
+ }
+
public void characters(char[] characters, int offset, int length)
throws TransletException {
try {
maybeEmitStartElement();
- _saxHandler.characters(characters, offset, length);
+ _domBuilder.characters(characters, offset, length);
}
catch (SAXException e) {
throw new TransletException(e);
@@ -136,7 +135,7 @@
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 +160,9 @@
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,22 +174,27 @@
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) {}
public void setIndent(boolean indent) {}
public void omitHeader(boolean value) {}
- public void setCdataElements(Hashtable elements) { }
+ public void setCdataElements(Hashtable elements) {}
+ public void setDoctype(String system, String pub) {}
+ public void setMediaType(String mediaType) {}
+ public void setStandalone(String standalone) {}
+ public void setVersion(String version) {}
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..dec46b5 100644
--- a/src/org/apache/xalan/xsltc/runtime/StringValueHandler.java
+++ b/src/org/apache/xalan/xsltc/runtime/StringValueHandler.java
@@ -71,7 +71,9 @@
private char[] _buffer = new char[32];
private int _free = 0;
- public void characters(char[] ch, int off, int len) {
+ public void characters(char[] ch, int off, int len)
+ throws TransletException
+ {
if (_free + len >= _buffer.length) {
char[] newBuffer = new char[_free + len + 32];
System.arraycopy(_buffer, 0, newBuffer, 0, _free);
@@ -86,4 +88,33 @@
_free = 0; // getValue resets
return new String(_buffer, 0, length);
}
+
+ public void characters(String characters) throws TransletException {
+ characters(characters.toCharArray(), 0, characters.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..73068e0 100644
--- a/src/org/apache/xalan/xsltc/runtime/TextOutput.java
+++ b/src/org/apache/xalan/xsltc/runtime/TextOutput.java
@@ -72,10 +72,11 @@
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
@@ -96,12 +97,11 @@
private boolean _startTagOpen = false;
private boolean _headTagOpen = false;
private boolean _cdataTagOpen = false;
+ private boolean _is8859Encoded = false;
// 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 +124,15 @@
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;
@@ -179,6 +179,7 @@
_saxHandler = handler;
init();
_encoding = encoding;
+ _is8859Encoded = _encoding.equalsIgnoreCase("iso-8859-1");
}
/**
@@ -194,6 +195,7 @@
_lexHandler = lex;
init();
_encoding = encoding;
+ _is8859Encoded = _encoding.equalsIgnoreCase("iso-8859-1");
}
/**
@@ -252,8 +254,8 @@
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 +266,10 @@
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) {
@@ -350,12 +335,13 @@
}
}
- /**
- * Utility method - pass a string to the SAX handler's characters() method
- */
- private void characters(String str) throws SAXException {
- final char[] ch = str.toCharArray();
- characters(ch, 0, ch.length);
+ public void characters(String str) throws TransletException {
+ try {
+ characters(str.toCharArray(), 0, str.length());
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
}
/**
@@ -417,17 +403,19 @@
// the first CDATA and '>' at the beginning of the next. Other
// special characters/sequences are _NOT_ escaped within CDATA.
Integer I = (Integer)_cdataStack.peek();
- if ((I.intValue() == _depth) && (!_cdataTagOpen))
+ if ((I.intValue() == _depth) && (!_cdataTagOpen)) {
startCDATA(ch, off, len);
- // Output characters escaped if required.
- else if (_escapeChars)
- if (_cdataTagOpen)
+ }
+ else if (_escapeChars) {
+ if (_cdataTagOpen) {
escapeCDATA(ch, off, len);
- else
+ } else {
escapeCharacters(ch, off, len);
- // Output the chracters as the are if not.
- else
+ }
+ }
+ else {
_saxHandler.characters(ch, off, len);
+ }
return;
case HTML:
@@ -467,9 +455,7 @@
* 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) {
@@ -552,9 +538,11 @@
if (limit > ch.length) limit = ch.length;;
+
// Step through characters and escape all special characters
for (int i = off; i < limit; i++) {
- switch (ch[i]) {
+ char current = ch[i];
+ switch (current) {
case '&':
_saxHandler.characters(ch, offset, i - offset);
_saxHandler.characters(AMP, 0, AMP_length);
@@ -576,9 +564,9 @@
offset = i + 1;
break;
default:
- // Escape all characters not in the basic ASCII character set
- // to simple (hexadecimal) character references
- if (ch[i] > '\u007F') {
+ if ( (current >= '\u007F' && current < '\u00A0') ||
+ (_is8859Encoded && (current > '\u00FF')) )
+ {
StringBuffer buf = new StringBuffer(CHAR_ESC_START);
buf.append(Integer.toString((int)ch[i]));
buf.append(';');
@@ -670,6 +658,14 @@
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 +677,17 @@
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 +709,8 @@
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 +763,51 @@
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 +819,102 @@
public void attribute(String name, final String value)
throws TransletException {
- 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);
- }
- else {
- // Output as regular attribute
- _attributes.add(expandAttribute(name), escapeString(value));
- }
- return;
- case HTML:
- 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.
+ if (_outputType == TEXT) return;
- // URL-encode href attributes in HTML output
- final String tmp = name.toLowerCase();
- if (tmp.equals(HREF_STR) || tmp.equals(SRC_STR)) {
- _attributes.add(name,quickAndDirtyUrlEncode(escapeAttr(value)));
+ 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 XML:
+ if (!_startTagOpen) {
+ BasisLibrary.runTimeError(BasisLibrary.STRAY_ATTRIBUTE_ERR, patchedName);
+ }
+
+ // Output as namespace declaration
+ if (name.startsWith(XMLNS_PREFIX)) {
+ namespace(name.length() > 6 ? name.substring(6) : EMPTYSTRING, value);
}
else {
- _attributes.add(expandAttribute(name), escapeAttr(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) {
+ 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.
+ */
+ final String tmp = name.toLowerCase();
+ 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 {
+ if (index >= 0) {
+ _attributes.setAttribute(index, EMPTYSTRING, EMPTYSTRING,
+ name, "CDATA", escapeNonURLAttr(value));
+ }
+ else {
+ _attributes.addAttribute(EMPTYSTRING, EMPTYSTRING,
+ name, "CDATA", escapeNonURLAttr(value));
+ }
+ }
+ 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 @@
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 @@
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 @@
_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 @@
* 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 @@
_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 @@
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 @@
* 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 @@
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/runtime/TransletOutputBase.java b/src/org/apache/xalan/xsltc/runtime/TransletOutputBase.java
index 79bc81a..61d69ea 100644
--- a/src/org/apache/xalan/xsltc/runtime/TransletOutputBase.java
+++ b/src/org/apache/xalan/xsltc/runtime/TransletOutputBase.java
@@ -71,6 +71,7 @@
public class TransletOutputBase implements TransletOutputHandler {
public void startDocument() throws TransletException {}
public void endDocument() throws TransletException {}
+ public void characters(String characters) throws TransletException {}
public void characters(char[] characters, int offset, int length)
throws TransletException {}
public void startElement(String elementName) throws TransletException {}
@@ -89,5 +90,9 @@
public void setIndent(boolean indent) {}
public void omitHeader(boolean value) {}
public void setCdataElements(Hashtable elements) {}
+ public void setDoctype(String system, String pub) {}
+ public void setMediaType(String mediaType) {}
+ public void setStandalone(String standalone) {}
+ public void setVersion(String version) {}
public void close() {}
}
diff --git a/src/org/apache/xalan/xsltc/runtime/output/OutputBase.java b/src/org/apache/xalan/xsltc/runtime/output/OutputBase.java
new file mode 100644
index 0000000..ebb864e
--- /dev/null
+++ b/src/org/apache/xalan/xsltc/runtime/output/OutputBase.java
@@ -0,0 +1,302 @@
+/*
+ * @(#)$Id$
+ *
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF
+ * USE, DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, Sun
+ * Microsystems., http://www.sun.com. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * @author Santiago Pericas-Geertsen
+ * @author G. Todd Miller
+ *
+ */
+
+package org.apache.xalan.xsltc.runtime.output;
+
+import java.util.Stack;
+
+import org.apache.xalan.xsltc.*;
+import org.apache.xalan.xsltc.runtime.*;
+import org.apache.xalan.xsltc.runtime.Hashtable;
+
+import org.apache.xalan.xsltc.TransletException;
+import org.apache.xalan.xsltc.TransletOutputHandler;
+import org.apache.xalan.xsltc.runtime.Hashtable;
+
+public abstract class OutputBase implements TransletOutputHandler, Constants {
+
+ /**
+ * Document system identifier
+ */
+ protected String _doctypeSystem = null;
+
+ /**
+ * Document public identifier
+ */
+ protected String _doctypePublic = null;
+
+ /**
+ * Holds the current tree depth.
+ */
+ protected int _depth = 0;
+
+ /**
+ * Each entry (prefix) in this hashtable points to a Stack of URIs
+ */
+ protected Hashtable _namespaces;
+
+ /**
+ * The top of this stack contains an id of the element that last declared
+ * a namespace. Used to ensure prefix/uri map scopes are closed correctly
+ */
+ protected Stack _nodeStack;
+
+ /**
+ * The top of this stack is the prefix that was last mapped to an URI
+ */
+ protected Stack _prefixStack;
+
+ /**
+ * Contains all elements that should be output as CDATA sections.
+ */
+ protected Hashtable _cdata = null;
+
+ /**
+ * The top of this stack contains the element id of the last element whose
+ * contents should be output as CDATA sections.
+ */
+ protected Stack _cdataStack;
+
+ /**
+ * Set to true when a CDATA section is being output.
+ */
+ protected boolean _cdataTagOpen = false;
+
+ /**
+ * Set to true when a start tag is being output.
+ */
+ protected boolean _startTagOpen = false;
+
+ /**
+ * Set to false after processing first element.
+ */
+ protected boolean _firstElement = true;
+
+ /**
+ * Initialize global variables
+ */
+ protected void initCDATA() {
+ // CDATA stack
+ _cdataStack = new Stack();
+ _cdataStack.push(new Integer(-1)); // push dummy value
+ }
+
+ protected void initNamespaces() {
+ // Namespaces
+ _namespaces = new Hashtable();
+ _nodeStack = new Stack();
+ _prefixStack = new Stack();
+
+ // Define the default namespace (initially maps to "" uri)
+ 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;
+ }
+
+ /**
+ * Set the output document system/public identifiers
+ */
+ public void setDoctype(String system, String pub) {
+ _doctypeSystem = system;
+ _doctypePublic = pub;
+
+ }
+
+ public void setCdataElements(Hashtable elements) {
+ _cdata = elements;
+ }
+
+
+ /**
+ * 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".
+ */
+ protected static String patchName(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;
+ }
+
+ /**
+ * Declare a prefix to point to a namespace URI
+ */
+ protected boolean pushNamespace(String prefix, String uri) {
+ // Prefixes "xml" and "xmlns" cannot be redefined
+ if (prefix.startsWith(XML_PREFIX)) {
+ return false;
+ }
+
+ Stack stack;
+ // Get the stack that contains URIs for the specified prefix
+ if ((stack = (Stack)_namespaces.get(prefix)) == null) {
+ _namespaces.put(prefix, stack = new Stack());
+ }
+
+ if (!stack.empty() && uri.equals(stack.peek())) {
+ return false;
+ }
+
+ stack.push(uri);
+ _prefixStack.push(prefix);
+ _nodeStack.push(new Integer(_depth));
+ return true;
+ }
+
+ /**
+ * Undeclare the namespace that is currently pointed to by a given prefix
+ */
+ protected boolean popNamespace(String prefix) {
+ // Prefixes "xml" and "xmlns" cannot be redefined
+ if (prefix.startsWith(XML_PREFIX)) {
+ return false;
+ }
+
+ Stack stack;
+ if ((stack = (Stack)_namespaces.get(prefix)) != null) {
+ stack.pop();
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Pop all namespace definitions that were delcared by the current element
+ */
+ protected void popNamespaces() {
+ while (true) {
+ if (_nodeStack.isEmpty()) return;
+ Integer i = (Integer)(_nodeStack.peek());
+ if (i.intValue() != _depth) return;
+ _nodeStack.pop();
+ popNamespace((String)_prefixStack.pop());
+ }
+ }
+
+ /**
+ * Use a namespace prefix to lookup a namespace URI
+ */
+ protected String lookupNamespace(String prefix) {
+ final Stack stack = (Stack)_namespaces.get(prefix);
+ return stack != null && !stack.isEmpty() ? (String)stack.peek() : null;
+ }
+
+ /**
+ * Returns the local name of a qualified name. If the name has
+ * no prefix, then it works as the identity (SAX2).
+ */
+ protected static String getLocalName(String qname) {
+ final int col = qname.lastIndexOf(':');
+ return (col > 0) ? qname.substring(col + 1) : qname;
+ }
+
+ /**
+ * Returns the URI of an element or attribute. Note that default namespaces
+ * do not apply directly to attributes.
+ */
+ protected 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,
+ qname.substring(0, col));
+ }
+ }
+ return uri;
+ }
+
+ // -- Temporary
+ public void namespace(String prefix, String uri) throws TransletException { }
+ public void setType(int type) { }
+ public void setIndent(boolean indent) { }
+ public void omitHeader(boolean value) { }
+ public boolean setEscaping(boolean escape) throws TransletException { return true; }
+ public void setMediaType(String mediaType) { }
+ public void setStandalone(String standalone) { }
+ public void setVersion(String version) { }
+ public void close() { }
+
+}
diff --git a/src/org/apache/xalan/xsltc/runtime/output/SAXHTMLOutput.java b/src/org/apache/xalan/xsltc/runtime/output/SAXHTMLOutput.java
new file mode 100644
index 0000000..77e4355
--- /dev/null
+++ b/src/org/apache/xalan/xsltc/runtime/output/SAXHTMLOutput.java
@@ -0,0 +1,204 @@
+/*
+ * @(#)$Id$
+ *
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF
+ * USE, DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, Sun
+ * Microsystems., http://www.sun.com. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * @author Santiago Pericas-Geertsen
+ * @author G. Todd Miller
+ *
+ */
+
+package org.apache.xalan.xsltc.runtime.output;
+
+import java.util.Stack;
+import java.io.IOException;
+
+import org.xml.sax.SAXException;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ext.LexicalHandler;
+import org.apache.xalan.xsltc.TransletException;
+import org.apache.xalan.xsltc.runtime.BasisLibrary;
+import org.apache.xalan.xsltc.runtime.AttributeList;
+
+public class SAXHTMLOutput extends SAXOutput {
+
+ public SAXHTMLOutput(ContentHandler handler, String encoding)
+ throws IOException
+ {
+ super(handler, encoding);
+ }
+
+ public SAXHTMLOutput(ContentHandler handler, LexicalHandler lex,
+ String encoding) throws IOException
+ {
+ super(handler, lex, encoding);
+ }
+
+ public void endDocument() throws TransletException {
+ try {
+ // Close any open start tag
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+
+ // Close output document
+ _saxHandler.endDocument();
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ /**
+ * 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 {
+ try {
+ // Close any open start tag
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+
+ // Handle document type declaration (for first element only)
+ if (_lexHandler != null) {
+ if ((_doctypeSystem != null) || (_doctypePublic != null))
+ _lexHandler.startDTD(elementName,
+ _doctypePublic,_doctypeSystem);
+ _lexHandler = null;
+ }
+
+ _depth++;
+ _elementName = elementName;
+ _attributes.clear();
+ _startTagOpen = true;
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ /**
+ * End an element or CDATA section in the output document
+ */
+ public void endElement(String elementName) throws TransletException {
+ try {
+ // Close any open element
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+ _saxHandler.endElement(EMPTYSTRING, EMPTYSTRING, elementName);
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+
+ }
+
+ public void attribute(String name, final String value)
+ throws TransletException
+ {
+ final String patchedName = patchName(name);
+ final String localName = getLocalName(patchedName);
+ final int index = _attributes.getIndex(name);
+
+ if (!_startTagOpen) {
+ BasisLibrary.runTimeError(BasisLibrary.STRAY_ATTRIBUTE_ERR,name);
+ }
+
+ if (index >= 0) {
+ _attributes.setAttribute(index, EMPTYSTRING, EMPTYSTRING,
+ name, "CDATA", value);
+ }
+ else {
+ _attributes.addAttribute(EMPTYSTRING, EMPTYSTRING,
+ name, "CDATA", value);
+ }
+ }
+
+ /**
+ * Send characters to the output document
+ */
+ public void characters(char[] ch, int off, int len)
+ throws TransletException
+ {
+ try {
+ // Close any open start tag
+ if (_startTagOpen) closeStartTag();
+ _saxHandler.characters(ch, off, len);
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ /**
+ * This method is called when all the data needed for a call to the
+ * SAX handler's startElement() method has been gathered.
+ */
+ protected void closeStartTag() throws TransletException {
+ try {
+ _startTagOpen = false;
+
+ // Now is time to send the startElement event
+ _saxHandler.startElement(null, _elementName, _elementName,
+ _attributes);
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+}
diff --git a/src/org/apache/xalan/xsltc/runtime/output/SAXOutput.java b/src/org/apache/xalan/xsltc/runtime/output/SAXOutput.java
new file mode 100644
index 0000000..f324812
--- /dev/null
+++ b/src/org/apache/xalan/xsltc/runtime/output/SAXOutput.java
@@ -0,0 +1,140 @@
+/*
+ * @(#)$Id$
+ *
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF
+ * USE, DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, Sun
+ * Microsystems., http://www.sun.com. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * @author Santiago Pericas-Geertsen
+ * @author G. Todd Miller
+ *
+ */
+
+package org.apache.xalan.xsltc.runtime.output;
+
+import java.util.Stack;
+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.TransletException;
+import org.apache.xalan.xsltc.runtime.Constants;
+
+abstract class SAXOutput extends OutputBase implements Constants {
+
+ protected ContentHandler _saxHandler;
+ protected LexicalHandler _lexHandler = null;
+ protected AttributesImpl _attributes = new AttributesImpl();
+ protected String _elementName = null;
+ protected String _encoding = null;
+
+ public SAXOutput(ContentHandler handler, String encoding) {
+ _saxHandler = handler;
+ _encoding = encoding;
+ }
+
+ public SAXOutput(ContentHandler hdler, LexicalHandler lex, String encoding) {
+ _saxHandler = hdler;
+ _lexHandler = lex;
+ _encoding = encoding;
+ }
+
+ public void startDocument() throws TransletException {
+ try {
+ _saxHandler.startDocument();
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ public void characters(String characters)
+ throws TransletException
+ {
+ characters(characters.toCharArray(), 0, characters.length());
+ }
+
+ public void comment(String comment) throws TransletException {
+ try {
+ // Close any open element before emitting comment
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+ else if (_cdataTagOpen) {
+ closeCDATA();
+ }
+
+ // Ignore if a lexical handler has not been set
+ if (_lexHandler != null) {
+ _lexHandler.comment(comment.toCharArray(), 0, comment.length());
+ }
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ public void processingInstruction(String target, String data)
+ throws TransletException
+ {
+ // Redefined in SAXXMLOutput
+ }
+
+ protected void closeStartTag() throws TransletException {
+ }
+
+ protected void closeCDATA() throws SAXException {
+ // Redefined in SAXXMLOutput
+ }
+}
diff --git a/src/org/apache/xalan/xsltc/runtime/output/SAXTextOutput.java b/src/org/apache/xalan/xsltc/runtime/output/SAXTextOutput.java
new file mode 100644
index 0000000..28353cc
--- /dev/null
+++ b/src/org/apache/xalan/xsltc/runtime/output/SAXTextOutput.java
@@ -0,0 +1,148 @@
+/*
+ * @(#)$Id$
+ *
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF
+ * USE, DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, Sun
+ * Microsystems., http://www.sun.com. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * @author Santiago Pericas-Geertsen
+ *
+ */
+
+package org.apache.xalan.xsltc.runtime.output;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.SAXException;
+
+import org.apache.xalan.xsltc.TransletException;
+
+public class SAXTextOutput extends SAXOutput {
+
+ public SAXTextOutput(ContentHandler handler, String encoding)
+ {
+ super(handler, encoding);
+ }
+
+ public SAXTextOutput(ContentHandler handler, LexicalHandler lex,
+ String encoding)
+ {
+ super(handler, lex, encoding);
+ }
+
+ public void startDocument() throws TransletException {
+ try {
+ _saxHandler.startDocument();
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ public void endDocument() throws TransletException {
+ try {
+ _saxHandler.endDocument();
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ public void startElement(String elementName)
+ throws TransletException
+ {
+ }
+
+ public void endElement(String elementName)
+ throws TransletException
+ {
+ }
+
+ public void characters(String characters)
+ throws TransletException
+ {
+ try {
+ _saxHandler.characters(characters.toCharArray(), 0,
+ characters.length());
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ public void characters(char[] characters, int offset, int length)
+ throws TransletException
+ {
+ try {
+ _saxHandler.characters(characters, offset, length);
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ public void comment(String comment) throws TransletException {
+ }
+
+ public void attribute(String name, String value)
+ throws TransletException
+ {
+ }
+
+ public void processingInstruction(String target, String data)
+ throws TransletException
+ {
+ }
+}
+
diff --git a/src/org/apache/xalan/xsltc/runtime/output/SAXXMLOutput.java b/src/org/apache/xalan/xsltc/runtime/output/SAXXMLOutput.java
new file mode 100644
index 0000000..55ec226
--- /dev/null
+++ b/src/org/apache/xalan/xsltc/runtime/output/SAXXMLOutput.java
@@ -0,0 +1,366 @@
+/*
+ * @(#)$Id$
+ *
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF
+ * USE, DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, Sun
+ * Microsystems., http://www.sun.com. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * @author Santiago Pericas-Geertsen
+ * @author G. Todd Miller
+ *
+ */
+
+package org.apache.xalan.xsltc.runtime.output;
+
+import java.util.Stack;
+import java.io.IOException;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ext.LexicalHandler;
+import org.apache.xalan.xsltc.TransletException;
+import org.apache.xalan.xsltc.runtime.Hashtable;
+import org.xml.sax.SAXException;
+import org.apache.xalan.xsltc.runtime.BasisLibrary;
+
+public class SAXXMLOutput extends SAXOutput {
+
+ private static final char[] BEGCDATA = "<![CDATA[".toCharArray();
+ private static final char[] ENDCDATA = "]]>".toCharArray();
+ private static final char[] CNTCDATA = "]]]]><![CDATA[>".toCharArray();
+
+ public SAXXMLOutput(ContentHandler handler, String encoding)
+ throws IOException
+ {
+ super(handler, encoding);
+ initCDATA();
+ initNamespaces();
+ }
+
+ public SAXXMLOutput(ContentHandler handler, LexicalHandler lex,
+ String encoding) throws IOException
+ {
+ super(handler, lex, encoding);
+ initCDATA();
+ initNamespaces();
+ }
+
+ public void endDocument() throws TransletException {
+ try {
+ // Close any open start tag
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+ else if (_cdataTagOpen) {
+ closeCDATA();
+ }
+
+ // Close output document
+ _saxHandler.endDocument();
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ /**
+ * 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 {
+// System.out.println("SAXXMLOutput.startElement name = " + elementName);
+ try {
+ // Close any open start tag
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+ else if (_cdataTagOpen) {
+ closeCDATA();
+ }
+
+ // Handle document type declaration (for first element only)
+ if (_firstElement) {
+ if (_doctypeSystem != null) {
+ _lexHandler.startDTD(elementName, _doctypePublic,
+ _doctypeSystem);
+ }
+ _firstElement = false;
+ }
+
+ _depth++;
+ _elementName = elementName;
+ _attributes.clear();
+ _startTagOpen = true;
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ /**
+ * Put an attribute and its value in the start tag of an element.
+ * Signal an exception if this is attempted done outside a start tag.
+ */
+ public void attribute(String name, final String value)
+ throws TransletException
+ {
+ final String patchedName = patchName(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);
+
+ if (!_startTagOpen) {
+ BasisLibrary.runTimeError(BasisLibrary.STRAY_ATTRIBUTE_ERR,
+ patchedName);
+ }
+
+ if (index >= 0) { // Duplicate attribute?
+ _attributes.setAttribute(index, uri, localName,
+ patchedName, "CDATA", value);
+ }
+ else {
+ _attributes.addAttribute(uri, localName, patchedName,
+ "CDATA", value);
+ }
+ }
+
+ public void characters(char[] ch, int off, int len)
+ throws TransletException
+ {
+// System.out.println("SAXXMLOutput.characters ch = " + new String(ch, off, len));
+
+ try {
+ // Close any open start tag
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+
+ Integer I = (Integer)_cdataStack.peek();
+ if ((I.intValue() == _depth) && (!_cdataTagOpen)) {
+ startCDATA(ch, off, len);
+ }
+ else {
+ _saxHandler.characters(ch, off, len);
+ }
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ public void endElement(String elementName) throws TransletException {
+// System.out.println("SAXXMLOutput.endElement name = " + elementName);
+ try {
+ // Close any open element
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+ else if (_cdataTagOpen) {
+ closeCDATA();
+ }
+
+ _saxHandler.endElement(getNamespaceURI(elementName, true),
+ getLocalName(elementName), elementName);
+
+ popNamespaces();
+ if (((Integer)_cdataStack.peek()).intValue() == _depth){
+ _cdataStack.pop();
+ }
+ _depth--;
+
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ /**
+ * Send a namespace declaration in the output document. The namespace
+ * declaration will not be include if the namespace is already in scope
+ * with the same prefix.
+ */
+ public void namespace(final String prefix, final String uri)
+ throws TransletException
+ {
+ if (_startTagOpen) {
+ pushNamespace(prefix, uri);
+ }
+ else {
+ if ((prefix == EMPTYSTRING) && (uri == EMPTYSTRING)) return;
+ BasisLibrary.runTimeError(BasisLibrary.STRAY_NAMESPACE_ERR,
+ prefix, uri);
+ }
+ }
+
+ /**
+ * Send a processing instruction to the output document
+ */
+ public void processingInstruction(String target, String data)
+ throws TransletException {
+ try {
+ // Close any open element
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+ else if (_cdataTagOpen) {
+ closeCDATA();
+ }
+
+ // Pass the processing instruction to the SAX handler
+ _saxHandler.processingInstruction(target, data);
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ /**
+ * Declare a prefix to point to a namespace URI. Inform SAX handler
+ * if this is a new prefix mapping.
+ */
+ protected boolean pushNamespace(String prefix, String uri) {
+ try {
+ if (super.pushNamespace(prefix, uri)) {
+ _saxHandler.startPrefixMapping(prefix, uri);
+ return true;
+ }
+ }
+ catch (SAXException e) {
+ // falls through
+ }
+ return false;
+ }
+
+ /**
+ * Undeclare the namespace that is currently pointed to by a given
+ * prefix. Inform SAX handler if prefix was previously mapped.
+ */
+ protected boolean popNamespace(String prefix) {
+ try {
+ if (super.popNamespace(prefix)) {
+ _saxHandler.endPrefixMapping(prefix);
+ return true;
+ }
+ }
+ catch (SAXException e) {
+ // falls through
+ }
+ return false;
+ }
+
+ /**
+ * This method is called when all the data needed for a call to the
+ * SAX handler's startElement() method has been gathered.
+ */
+ protected void closeStartTag() throws TransletException {
+ try {
+ _startTagOpen = false;
+
+ final String localName = getLocalName(_elementName);
+ final String uri = getNamespaceURI(_elementName, true);
+
+ // Now is time to send the startElement event
+ _saxHandler.startElement(uri, localName, _elementName,
+ _attributes);
+
+ if (_cdata != null) {
+ final StringBuffer expandedName = (uri == EMPTYSTRING) ?
+ new StringBuffer(_elementName) :
+ new StringBuffer(uri).append(':').append(localName);
+
+ if (_cdata.containsKey(expandedName.toString())) {
+ _cdataStack.push(new Integer(_depth));
+ }
+ }
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ protected void closeCDATA() throws SAXException {
+ // Output closing bracket - "]]>"
+ _saxHandler.characters(ENDCDATA, 0, ENDCDATA.length);
+ _cdataTagOpen = false;
+ }
+
+ /**
+ * Utility method - pass a whole charactes as CDATA to SAX handler
+ */
+ private void startCDATA(char[] ch, int off, int len) throws SAXException {
+ final int limit = off + len;
+ int offset = off;
+
+ // Output start bracket - "<![CDATA["
+ _saxHandler.characters(BEGCDATA, 0, BEGCDATA.length);
+
+ // Detect any occurence of "]]>" in the character array
+ for (int i = offset; i < limit - 2; i++) {
+ if (ch[i] == ']' && ch[i + 1] == ']' && ch[i + 2] == '>') {
+ _saxHandler.characters(ch, offset, i - offset);
+ _saxHandler.characters(CNTCDATA, 0, CNTCDATA.length);
+ offset = i+3;
+ i += 2; // Skip next chars ']' and '>'
+ }
+ }
+
+ // Output the remaining characters
+ if (offset < limit) {
+ _saxHandler.characters(ch, offset, limit - offset);
+ }
+ _cdataTagOpen = true;
+ }
+}
+
diff --git a/src/org/apache/xalan/xsltc/runtime/output/StreamHTMLOutput.java b/src/org/apache/xalan/xsltc/runtime/output/StreamHTMLOutput.java
new file mode 100644
index 0000000..c0439f9
--- /dev/null
+++ b/src/org/apache/xalan/xsltc/runtime/output/StreamHTMLOutput.java
@@ -0,0 +1,419 @@
+/*
+ * @(#)$Id$
+ *
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF
+ * USE, DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, Sun
+ * Microsystems., http://www.sun.com. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * @author Santiago Pericas-Geertsen
+ * @author G. Todd Miller
+ *
+ */
+
+package org.apache.xalan.xsltc.runtime.output;
+
+import java.util.Vector;
+
+import java.io.Writer;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.xalan.xsltc.*;
+import org.apache.xalan.xsltc.runtime.*;
+import org.apache.xalan.xsltc.runtime.Hashtable;
+
+public class StreamHTMLOutput extends StreamOutput {
+
+ private static final String HREF_STR = "href";
+ private static final String CITE_STR = "cite";
+ private static final String SRC_STR = "src";
+
+ private static final Hashtable _emptyElements = new Hashtable();
+ private static final String[] tags = { "area", "base", "basefont", "br",
+ "col", "frame", "hr", "img", "input",
+ "isindex", "link", "meta", "param" };
+ static {
+ for (int i = 0; i < tags.length; i++) {
+ _emptyElements.put(tags[i], "");
+ }
+ }
+
+ private boolean _headTagOpen = false;
+ private boolean _inStyleScript = false;
+ private String _mediaType = "text/html";
+
+ public StreamHTMLOutput(StreamOutput output) {
+ super(output);
+ setIndent(true); // default for HTML
+// System.out.println("StreamHTMLOutput.<init>");
+ }
+
+ public StreamHTMLOutput(Writer writer, String encoding) {
+ super(writer, encoding);
+// System.out.println("StreamHTMLOutput.<init>");
+ }
+
+ public StreamHTMLOutput(OutputStream out, String encoding)
+ throws IOException
+ {
+ super(out, encoding);
+// System.out.println("StreamHTMLOutput.<init>");
+ }
+
+ public void startDocument() throws TransletException {
+ // empty
+ }
+
+ public void endDocument() throws TransletException {
+ // Finally, output buffer to writer
+ outputBuffer();
+ }
+
+ public void startElement(String elementName) throws TransletException {
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+
+ // Handle document type declaration (for first element only)
+ if (_firstElement) {
+ if (_doctypeSystem != null || _doctypePublic != null) {
+ appendDTD(elementName);
+ }
+ _firstElement = false;
+ }
+
+ if (_indent) {
+ if (!_emptyElements.containsKey(elementName.toLowerCase())) {
+ indent(_lineFeedNextStartTag);
+ _lineFeedNextStartTag = true;
+ _indentNextEndTag = false;
+ }
+ _indentLevel++;
+ }
+
+ _buffer.append('<').append(elementName);
+ _startTagOpen = true;
+ _indentNextEndTag = false;
+
+ if (elementName.equalsIgnoreCase("head")) {
+ _headTagOpen = true;
+ }
+ else if (elementName.equalsIgnoreCase("style") ||
+ elementName.equalsIgnoreCase("script"))
+ {
+ _inStyleScript = true;
+ }
+ }
+
+ public void endElement(String elementName)
+ throws TransletException
+ {
+ if (_inStyleScript &&
+ (elementName.equalsIgnoreCase("style") ||
+ elementName.equalsIgnoreCase("script")))
+ {
+ _inStyleScript = false;
+ }
+
+ if (_startTagOpen) {
+ appendAttributes();
+ if (_emptyElements.containsKey(elementName.toLowerCase())) {
+ _buffer.append('>');
+ }
+ else {
+ closeStartTag();
+ _buffer.append("</").append(elementName).append('>');
+ }
+ _startTagOpen = false;
+
+ if (_indent) {
+ _indentLevel--;
+ _indentNextEndTag = true;
+ }
+ }
+ else {
+ if (_indent) {
+ _indentLevel--;
+
+ if (_indentNextEndTag) {
+ indent(_indentNextEndTag);
+ _indentNextEndTag = true;
+ _lineFeedNextStartTag = true;
+ }
+ }
+ _buffer.append("</").append(elementName).append('>');
+ _indentNextEndTag = true;
+ }
+ }
+
+ public void characters(String characters)
+ throws TransletException
+ {
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+
+ if (_escaping && !_inStyleScript) {
+ escapeCharacters(characters.toCharArray(), 0, characters.length());
+ }
+ else {
+ _buffer.append(characters);
+ }
+ }
+
+ public void characters(char[] characters, int offset, int length)
+ throws TransletException
+ {
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+
+ if (_escaping && !_inStyleScript) {
+ escapeCharacters(characters, offset, length);
+ }
+ else {
+ _buffer.append(characters, offset, length);
+ }
+ }
+
+ public void attribute(String name, String value)
+ throws TransletException
+ {
+// System.out.println("attribute = " + name + " " + value);
+ if (_startTagOpen) {
+ int k;
+ Attribute attr;
+
+ if (name.equalsIgnoreCase(HREF_STR) ||
+ name.equalsIgnoreCase(SRC_STR) ||
+ name.equals(CITE_STR))
+ {
+ attr = new Attribute(name, escapeURL(value));
+ }
+ else {
+ attr = new Attribute(name, escapeNonURL(value));
+ }
+
+ if ((k = _attributes.indexOf(attr)) >= 0) {
+ _attributes.setElementAt(attr, k);
+ }
+ else {
+ _attributes.add(attr);
+ }
+ }
+ }
+
+ public void comment(String comment) throws TransletException {
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+ appendComment(comment);
+ }
+
+ public void processingInstruction(String target, String data)
+ throws TransletException
+ {
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+
+ // Handle document type declaration
+ if (_firstElement) {
+ if (_doctypeSystem != null || _doctypePublic != null) {
+ appendDTD("html");
+ }
+ _firstElement = false;
+ }
+
+ // A PI in HTML ends with ">" instead of "?>"
+ _buffer.append("<?").append(target).append(' ')
+ .append(data).append('>');
+ }
+
+ public boolean setEscaping(boolean escape) throws TransletException
+ {
+ final boolean temp = _escaping;
+ _escaping = escape;
+ return temp;
+ }
+
+ public void close() {
+ try {
+ _writer.close();
+ }
+ catch (Exception e) {
+ // ignore
+ }
+ }
+
+ public void namespace(String prefix, String uri) throws TransletException
+ {
+ // ignore when method type is HTML
+ }
+
+ public void setCdataElements(Hashtable elements) {
+ // ignore when method type is HTML
+ }
+
+ public void setType(int type) {
+ // ignore: default is HTML
+ }
+
+ /**
+ * Set the output media type - only relevant for HTML output
+ */
+ public void setMediaType(String mediaType) {
+ _mediaType = mediaType;
+ }
+
+ /**
+ * Escape non ASCII characters (> u007F) as &#XXX; entities.
+ */
+ private String escapeNonURL(String base) {
+ final int length = base.length();
+ final StringBuffer result = new StringBuffer();
+
+ for (int i = 0; i < length; i++){
+ final char ch = base.charAt(i);
+
+ if ((ch >= '\u007F' && ch < '\u00A0') ||
+ (_is8859Encoded && ch > '\u00FF'))
+ {
+ result.append(CHAR_ESC_START)
+ .append(Integer.toString((int) ch))
+ .append(';');
+ }
+ else {
+ result.append(ch);
+ }
+ }
+ return result.toString();
+ }
+
+ /**
+ * This method escapes special characters used in HTML attribute values
+ */
+ private String escapeURL(String base) {
+ final char[] chs = base.toCharArray();
+ final StringBuffer result = new StringBuffer();
+
+ final int length = chs.length;
+ for (int i = 0; i < length; i++) {
+ final char ch = chs[i];
+
+ if (ch <= 0x20) {
+ result.append('%').append(makeHHString(ch));
+ }
+ else if (ch > '\u007F') {
+ result.append('%')
+ .append(makeHHString((ch >> 6) | 0xC0))
+ .append('%')
+ .append(makeHHString((ch & 0x3F) | 0x80));
+ }
+ else {
+ // These chars are reserved or unsafe in URLs
+ switch (ch) {
+ case '\u007F' :
+ case '\u007B' :
+ case '\u007D' :
+ case '\u007C' :
+ case '\\' :
+ case '\t' :
+ case '\u005E' :
+ case '\u007E' :
+ case '\u005B' :
+ case '\u005D' :
+ case '\u0060' :
+ case '\u0020' :
+ result.append('%')
+ .append(Integer.toHexString((int) ch));
+ break;
+ case '"':
+ result.append("%22");
+ break;
+ default:
+ result.append(ch);
+ break;
+ }
+ }
+ }
+ return result.toString();
+ }
+
+ private String makeHHString(int i) {
+ final String s = Integer.toHexString(i).toUpperCase();
+ return (s.length() == 1) ? "0" + s : s;
+ }
+
+ /**
+ * Emit HTML meta info
+ */
+ private void appendHeader() {
+ _buffer.append("<meta http-equiv=\"Content-Type\" content=\"")
+ .append(_mediaType).append("; charset=")
+ .append(_encoding).append("\">");
+ }
+
+ protected void closeStartTag() throws TransletException {
+ super.closeStartTag();
+
+ // Insert <META> tag directly after <HEAD> element in HTML output
+ if (_headTagOpen) {
+ appendHeader();
+ _headTagOpen = false;
+ }
+ }
+}
diff --git a/src/org/apache/xalan/xsltc/runtime/output/StreamOutput.java b/src/org/apache/xalan/xsltc/runtime/output/StreamOutput.java
new file mode 100644
index 0000000..fc1739f
--- /dev/null
+++ b/src/org/apache/xalan/xsltc/runtime/output/StreamOutput.java
@@ -0,0 +1,346 @@
+/*
+ * @(#)$Id$
+ *
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF
+ * USE, DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, Sun
+ * Microsystems., http://www.sun.com. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * @author Santiago Pericas-Geertsen
+ * @author G. Todd Miller
+ *
+ */
+
+package org.apache.xalan.xsltc.runtime.output;
+
+import java.io.Writer;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+
+import java.util.Vector;
+
+import org.apache.xalan.xsltc.TransletException;
+
+abstract class StreamOutput extends OutputBase {
+
+ protected static final String AMP = "&";
+ protected static final String LT = "<";
+ protected static final String GT = ">";
+ protected static final String CRLF = "
";
+ protected static final String QUOTE = """;
+ protected static final String NBSP = " ";
+
+ protected static final String CHAR_ESC_START = "&#";
+
+ protected static final char[] INDENT = " ".toCharArray();
+ protected static final int MAX_INDENT_LEVEL = (INDENT.length >> 1);
+ protected static final int MAX_INDENT = INDENT.length;
+
+ protected static final int BUFFER_SIZE = 64 * 1024;
+ protected static final int OUTPUT_BUFFER_SIZE = 4 * 1024;
+
+ protected Writer _writer;
+ protected StringBuffer _buffer;
+
+ protected boolean _is8859Encoded = false;
+ protected boolean _indent = false;
+ protected boolean _omitHeader = false;
+ protected String _standalone = null;
+ protected String _version = "1.0";
+
+ protected boolean _lineFeedNextStartTag = false;
+ protected boolean _linefeedNextEndTag = false;
+ protected boolean _indentNextEndTag = false;
+ protected int _indentLevel = 0;
+
+ protected boolean _escaping = true;
+ protected String _encoding = "UTF-8";
+
+ protected int _indentNumber = 2;
+
+ // protected HashSet _attributes = new HashSet();
+ protected Vector _attributes = new Vector();
+
+ static class Attribute {
+ public String name, value;
+
+ Attribute(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ public boolean equals(Object obj) {
+ try {
+ return name.equalsIgnoreCase(((Attribute) obj).name);
+ }
+ catch (ClassCastException e) {
+ return false;
+ }
+ }
+ }
+
+ protected StreamOutput(StreamOutput output) {
+ _writer = output._writer;
+ _encoding = output._encoding;
+ _is8859Encoded = output._is8859Encoded;
+ _buffer = output._buffer;
+ _indentNumber = output._indentNumber;
+ }
+
+ protected StreamOutput(Writer writer, String encoding) {
+ _writer = writer;
+ _encoding = encoding;
+ _is8859Encoded = encoding.equalsIgnoreCase("iso-8859-1");
+ _buffer = new StringBuffer(BUFFER_SIZE);
+ }
+
+ protected StreamOutput(OutputStream out, String encoding)
+ throws IOException
+ {
+ try {
+ _writer = new OutputStreamWriter(out, _encoding = encoding);
+ _is8859Encoded = encoding.equalsIgnoreCase("iso-8859-1");
+ }
+ catch (UnsupportedEncodingException e) {
+ _writer = new OutputStreamWriter(out, _encoding = "utf-8");
+ }
+ _buffer = new StringBuffer(BUFFER_SIZE);
+ }
+
+ public void setIndentNumber(int value) {
+ _indentNumber = value;
+ }
+
+ /**
+ * Set the output document system/public identifiers
+ */
+ public void setDoctype(String system, String pub) {
+ _doctypeSystem = system;
+ _doctypePublic = pub;
+ }
+
+ public void setIndent(boolean indent) {
+// System.out.println("StreamOutput.setIndent() indent = " + indent);
+ _indent = indent;
+ }
+
+ public void omitHeader(boolean value) {
+ _omitHeader = value;
+ }
+
+ public void setStandalone(String standalone) {
+ _standalone = standalone;
+ }
+
+ public void setVersion(String version) {
+ _version = version;
+ }
+
+ protected void outputBuffer() {
+ try {
+ int n = 0;
+ final int length = _buffer.length();
+ final String output = _buffer.toString();
+
+ // Output buffer in chunks of OUTPUT_BUFFER_SIZE
+ if (length > OUTPUT_BUFFER_SIZE) {
+ do {
+ _writer.write(output, n, OUTPUT_BUFFER_SIZE);
+ n += OUTPUT_BUFFER_SIZE;
+ } while (n + OUTPUT_BUFFER_SIZE < length);
+ }
+ _writer.write(output, n, length - n);
+ _writer.flush();
+ }
+ catch (IOException e) {
+ // ignore
+ }
+ }
+
+ protected void appendDTD(String name) {
+ _buffer.append("<!DOCTYPE ").append(name);
+ if (_doctypePublic == null) {
+ _buffer.append(" SYSTEM");
+ }
+ else {
+ _buffer.append(" PUBLIC \"").append(_doctypePublic).append("\"");
+ }
+ if (_doctypeSystem != null) {
+ _buffer.append(" \"").append(_doctypeSystem).append("\">\n");
+ }
+ else {
+ _buffer.append(">\n");
+ }
+ }
+
+ /**
+ * Adds a newline in the output stream and indents to correct level
+ */
+ protected void indent(boolean linefeed) {
+ if (linefeed) {
+ _buffer.append('\n');
+ }
+
+ _buffer.append(INDENT, 0,
+ _indentLevel < MAX_INDENT_LEVEL ? _indentLevel * _indentNumber
+ : MAX_INDENT);
+ }
+
+ protected void escapeCharacters(char[] ch, int off, int len) {
+ int limit = off + len;
+ int offset = off;
+
+ if (limit > ch.length) {
+ limit = ch.length;
+ }
+
+ // Step through characters and escape all special characters
+ for (int i = off; i < limit; i++) {
+ final char current = ch[i];
+
+ switch (current) {
+ case '&':
+ _buffer.append(ch, offset, i - offset);
+ _buffer.append(AMP);
+ offset = i + 1;
+ break;
+ case '<':
+ _buffer.append(ch, offset, i - offset);
+ _buffer.append(LT);
+ offset = i + 1;
+ break;
+ case '>':
+ _buffer.append(ch, offset, i - offset);
+ _buffer.append(GT);
+ offset = i + 1;
+ break;
+ case '\u00a0':
+ _buffer.append(ch, offset, i - offset);
+ _buffer.append(NBSP);
+ offset = i + 1;
+ break;
+ default:
+ if ((current >= '\u007F' && current < '\u00A0') ||
+ (_is8859Encoded && current > '\u00FF'))
+ {
+ _buffer.append(ch, offset, i - offset);
+ _buffer.append(CHAR_ESC_START);
+ _buffer.append(Integer.toString((int)ch[i]));
+ _buffer.append(';');
+ offset = i + 1;
+ }
+ }
+ }
+ // Output remaining characters (that do not need escaping).
+ if (offset < limit) {
+ _buffer.append(ch, offset, limit - offset);
+ }
+ }
+
+ protected void appendAttributes() {
+ // Append attributes to output buffer
+ if (!_attributes.isEmpty()) {
+ int i = 0;
+ final int length = _attributes.size();
+
+ do {
+ final Attribute attr = (Attribute) _attributes.elementAt(i);
+ _buffer.append(' ').append(attr.name).append("=\"")
+ .append(attr.value).append('"');
+ } while (++i < length);
+
+ _attributes.clear();
+ }
+ }
+
+ protected void closeStartTag() throws TransletException {
+ appendAttributes();
+ _buffer.append('>');
+ _startTagOpen = false;
+ }
+
+ /**
+ * Ensure that comments do not include the sequence "--" and
+ * that they do not end with "-".
+ */
+ protected void appendComment(String comment)
+ throws TransletException
+ {
+ boolean lastIsDash = false;
+ final int n = comment.length();
+
+ _buffer.append("<!--");
+ for (int i = 0; i < n; i++) {
+ final char ch = comment.charAt(i);
+ final boolean isDash = (ch == '-');
+
+ if (lastIsDash && isDash) {
+ _buffer.append(" -");
+ }
+ else {
+ _buffer.append(ch);
+ }
+ lastIsDash = isDash;
+ }
+ if (lastIsDash) {
+ _buffer.append(' ');
+ }
+ _buffer.append("-->");
+ }
+}
diff --git a/src/org/apache/xalan/xsltc/compiler/LongExpr.java b/src/org/apache/xalan/xsltc/runtime/output/StreamTextOutput.java
similarity index 63%
copy from src/org/apache/xalan/xsltc/compiler/LongExpr.java
copy to src/org/apache/xalan/xsltc/runtime/output/StreamTextOutput.java
index e650658..b15323d 100644
--- a/src/org/apache/xalan/xsltc/compiler/LongExpr.java
+++ b/src/org/apache/xalan/xsltc/runtime/output/StreamTextOutput.java
@@ -41,8 +41,8 @@
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF
+ * USE, DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
@@ -56,34 +56,70 @@
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
- * @author G. Todd Miller
+ * @author Santiago Pericas-Geertsen
*
*/
-package org.apache.xalan.xsltc.compiler;
+package org.apache.xalan.xsltc.runtime.output;
-import org.apache.xalan.xsltc.compiler.util.Type;
-import org.apache.bcel.generic.*;
-import org.apache.xalan.xsltc.compiler.util.*;
+import java.io.Writer;
+import java.io.IOException;
+import java.io.OutputStream;
-final class LongExpr extends Expression {
- private final long _value;
+import org.apache.xalan.xsltc.TransletException;
- public LongExpr(long value) {
- _value = value;
+public class StreamTextOutput extends StreamOutput {
+
+ public StreamTextOutput(Writer writer, String encoding) {
+ super(writer, encoding);
}
- public Type typeCheck(SymbolTable stable) throws TypeCheckError {
- return _type = Type.Lng;
+ public StreamTextOutput(OutputStream out, String encoding)
+ throws IOException
+ {
+ super(out, encoding);
}
- public String toString() {
- return "long-expr(" + _value + ')';
+ public void startDocument() throws TransletException {
}
- public void translate(ClassGenerator classGen, MethodGenerator methodGen) {
- ConstantPoolGen cpg = classGen.getConstantPool();
- InstructionList il = methodGen.getInstructionList();
- il.append(new PUSH(cpg, _value));
+ public void endDocument() throws TransletException {
+ outputBuffer();
+ }
+
+ public void startElement(String elementName)
+ throws TransletException
+ {
+ }
+
+ public void endElement(String elementName)
+ throws TransletException
+ {
+ }
+
+ public void characters(String characters)
+ throws TransletException
+ {
+ _buffer.append(characters);
+ }
+
+ public void characters(char[] characters, int offset, int length)
+ throws TransletException
+ {
+ _buffer.append(characters, offset, length);
+ }
+
+ public void comment(String comment) throws TransletException {
+ }
+
+ public void attribute(String name, String value)
+ throws TransletException
+ {
+ }
+
+ public void processingInstruction(String target, String data)
+ throws TransletException
+ {
}
}
+
diff --git a/src/org/apache/xalan/xsltc/runtime/output/StreamUnknownOutput.java b/src/org/apache/xalan/xsltc/runtime/output/StreamUnknownOutput.java
new file mode 100644
index 0000000..7e62e0a
--- /dev/null
+++ b/src/org/apache/xalan/xsltc/runtime/output/StreamUnknownOutput.java
@@ -0,0 +1,341 @@
+/*
+ * @(#)$Id$
+ *
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF
+ * USE, DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, Sun
+ * Microsystems., http://www.sun.com. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * @author Santiago Pericas-Geertsen
+ * @author G. Todd Miller
+ *
+ */
+
+package org.apache.xalan.xsltc.runtime.output;
+
+import java.util.ArrayList;
+
+import java.io.Writer;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.xalan.xsltc.*;
+import org.apache.xalan.xsltc.runtime.*;
+import org.apache.xalan.xsltc.runtime.Hashtable;
+
+public class StreamUnknownOutput extends StreamOutput {
+
+ private StreamOutput _handler;
+
+ private boolean _isHtmlOutput = false;
+ private boolean _firstTagOpen = false;
+ private boolean _firstElement = true;
+ private String _firstTagPrefix, _firstTag;
+
+ private ArrayList _attributes = null;
+ private ArrayList _namespaces = null;
+
+ // Cache calls to output properties events
+ private String _mediaType = null;
+ private boolean _callStartDocument = false;
+ private boolean _callSetVersion = false;
+ private boolean _callSetDoctype = false;
+
+ static class Pair {
+ public String name, value;
+
+ public Pair(String name, String value) {
+ this.name = name;
+ this.value = value;
+ }
+ }
+
+ public StreamUnknownOutput(Writer writer, String encoding) {
+ super(writer, encoding);
+ _handler = new StreamXMLOutput(writer, encoding);
+// System.out.println("StreamUnknownOutput.<init>");
+ }
+
+ public StreamUnknownOutput(OutputStream out, String encoding)
+ throws IOException
+ {
+ super(out, encoding);
+ _handler = new StreamXMLOutput(out, encoding);
+// System.out.println("StreamUnknownOutput.<init>");
+ }
+
+ public void startDocument()
+ throws TransletException
+ {
+ _callStartDocument = true;
+ }
+
+ public void endDocument()
+ throws TransletException
+ {
+ if (_firstTagOpen) {
+ initStreamOutput();
+ }
+ else if (_callStartDocument) {
+ _handler.startDocument();
+ }
+ _handler.endDocument();
+ }
+
+ public void startElement(String elementName)
+ throws TransletException
+ {
+// System.out.println("startElement() = " + elementName);
+ if (_firstElement) {
+ _firstElement = false;
+
+ _firstTag = elementName;
+ _firstTagPrefix = BasisLibrary.getPrefix(elementName);
+ if (_firstTagPrefix == null) {
+ _firstTagPrefix = EMPTYSTRING;
+ }
+
+ _firstTagOpen = true;
+ _isHtmlOutput = BasisLibrary.getLocalName(elementName)
+ .equalsIgnoreCase("html");
+ }
+ else {
+ if (_firstTagOpen) {
+ initStreamOutput();
+ }
+ _handler.startElement(elementName);
+ }
+ }
+
+ public void endElement(String elementName)
+ throws TransletException
+ {
+ if (_firstTagOpen) {
+ initStreamOutput();
+ }
+ _handler.endElement(elementName);
+ }
+
+ public void characters(String characters)
+ throws TransletException
+ {
+ if (_firstTagOpen) {
+ initStreamOutput();
+ }
+ _handler.characters(characters);
+ }
+
+ public void characters(char[] characters, int offset, int length)
+ throws TransletException
+ {
+ if (_firstTagOpen) {
+ initStreamOutput();
+ }
+ _handler.characters(characters, offset, length);
+ }
+
+ public void attribute(String name, String value)
+ throws TransletException
+ {
+ if (_firstTagOpen) {
+ if (_attributes == null) {
+ _attributes = new ArrayList();
+ }
+ _attributes.add(new Pair(name, value));
+ }
+ else {
+ _handler.attribute(name, value);
+ }
+ }
+
+ public void namespace(String prefix, String uri)
+ throws TransletException
+ {
+// System.out.println("namespace() = " + prefix + " " + uri);
+ if (_firstTagOpen) {
+ if (_namespaces == null) {
+ _namespaces = new ArrayList();
+ }
+ _namespaces.add(new Pair(prefix, uri));
+
+ // Check if output is XHTML instead of HTML
+ if (_firstTagPrefix.equals(prefix) && !uri.equals(EMPTYSTRING)) {
+ _isHtmlOutput = false;
+ }
+ }
+ else {
+ _handler.namespace(prefix, uri);
+ }
+ }
+
+ public void comment(String comment)
+ throws TransletException
+ {
+ if (_firstTagOpen) {
+ initStreamOutput();
+ }
+ _handler.comment(comment);
+ }
+
+ public void processingInstruction(String target, String data)
+ throws TransletException
+ {
+ if (_firstTagOpen) {
+ initStreamOutput();
+ }
+ _handler.processingInstruction(target, data);
+ }
+
+ public void setDoctype(String system, String pub) {
+ _handler.setDoctype(system, pub);
+
+ // Cache call to setDoctype()
+ super.setDoctype(system, pub);
+ _callSetDoctype = true;
+ }
+
+ /**
+ * This method cannot be cached because default is different in
+ * HTML and XML (we need more than a boolean).
+ */
+ public void setIndent(boolean indent) {
+ _handler.setIndent(indent);
+ }
+
+ public void setVersion(String version) {
+ _handler.setVersion(version);
+
+ // Cache call to setVersion()
+ super.setVersion(version);
+ _callSetVersion = true;
+ }
+
+ public void omitHeader(boolean value) {
+ _handler.omitHeader(value);
+ }
+
+ public void setStandalone(String standalone) {
+ _handler.setStandalone(standalone);
+ }
+
+ public void setMediaType(String mediaType) {
+ _handler.setMediaType(mediaType);
+ _mediaType = mediaType;
+ }
+
+ public boolean setEscaping(boolean escape)
+ throws TransletException
+ {
+ return _handler.setEscaping(escape);
+ }
+
+ public void setCdataElements(Hashtable elements) {
+ _handler.setCdataElements(elements);
+ }
+
+ public void setIndentNumber(int value) {
+ _handler.setIndentNumber(value);
+ }
+
+ private void initStreamOutput()
+ throws TransletException
+ {
+// System.out.println("initStreamOutput() _isHtmlOutput = " + _isHtmlOutput);
+ // Create a new handler if output is HTML
+ if (_isHtmlOutput) {
+ _handler = new StreamHTMLOutput(_handler);
+
+ if (_callSetVersion) {
+ _handler.setVersion(_version);
+ }
+ if (_callSetDoctype) {
+ _handler.setDoctype(_doctypeSystem, _doctypePublic);
+ }
+ if (_mediaType != null) {
+ _handler.setMediaType(_mediaType);
+ }
+ }
+
+ // Call startDocument() if necessary
+ if (_callStartDocument) {
+ _handler.startDocument();
+ _callStartDocument = false;
+ }
+
+ // Output first tag
+ _handler.startElement(_firstTag);
+
+ // Output namespaces of first tag
+ if (_namespaces != null) {
+ final int n = _namespaces.size();
+ for (int i = 0; i < n; i++) {
+ final Pair pair = (Pair) _namespaces.get(i);
+ _handler.namespace(pair.name, pair.value);
+ }
+ }
+
+ // Output attributes of first tag
+ if (_attributes != null) {
+ final int n = _attributes.size();
+ for (int i = 0; i < n; i++) {
+ final Pair pair = (Pair) _attributes.get(i);
+ _handler.attribute(pair.name, pair.value);
+ }
+ }
+
+ // Close first tag
+ _firstTagOpen = false;
+ }
+}
diff --git a/src/org/apache/xalan/xsltc/runtime/output/StreamXMLOutput.java b/src/org/apache/xalan/xsltc/runtime/output/StreamXMLOutput.java
new file mode 100644
index 0000000..fe5e02d
--- /dev/null
+++ b/src/org/apache/xalan/xsltc/runtime/output/StreamXMLOutput.java
@@ -0,0 +1,415 @@
+/*
+ * @(#)$Id$
+ *
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF
+ * USE, DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, Sun
+ * Microsystems., http://www.sun.com. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * @author Santiago Pericas-Geertsen
+ * @author G. Todd Miller
+ *
+ */
+
+package org.apache.xalan.xsltc.runtime.output;
+
+import java.util.Stack;
+import java.util.Vector;
+
+import java.io.Writer;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+
+import org.apache.xalan.xsltc.*;
+import org.apache.xalan.xsltc.runtime.*;
+import org.apache.xalan.xsltc.runtime.Hashtable;
+
+public class StreamXMLOutput extends StreamOutput {
+
+ private static final String BEGCDATA = "<![CDATA[";
+ private static final String ENDCDATA = "]]>";
+ private static final String CNTCDATA = "]]]]><![CDATA[>";
+ private static final String BEGCOMM = "<!--";
+ private static final String ENDCOMM = "-->";
+ private static final String CDATA_ESC_START = "]]>&#";
+ private static final String CDATA_ESC_END = ";<![CDATA[";
+
+ private String _elementName;
+
+ public StreamXMLOutput(Writer writer, String encoding) {
+ super(writer, encoding);
+ initCDATA();
+ initNamespaces();
+//System.out.println("StreamXMLOutput.<init>");
+ }
+
+ public StreamXMLOutput(OutputStream out, String encoding)
+ throws IOException
+ {
+ super(out, encoding);
+ initCDATA();
+ initNamespaces();
+//System.out.println("StreamXMLOutput.<init>");
+ }
+
+ public void startDocument() throws TransletException {
+//System.out.println("startDocument");
+ if (!_omitHeader) {
+ final StringBuffer header = new StringBuffer("<?xml version=\"");
+ header.append(_version).append("\" encoding=\"").append(_encoding);
+ if (_standalone != null) {
+ header.append("\" standalone=\"").append(_standalone);
+ }
+ header.append("\"?>\n");
+
+ // Always insert header at the beginning
+ _buffer.insert(0, header.toString());
+ }
+ }
+
+ public void endDocument() throws TransletException {
+// System.out.println("endDocument");
+ // Finally, output buffer to writer
+ outputBuffer();
+ }
+
+ public void startElement(String elementName) throws TransletException {
+// System.out.println("startElement = " + elementName);
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+ else if (_cdataTagOpen) {
+ closeCDATA();
+ }
+
+ // Handle document type declaration (for first element only)
+ if (_firstElement) {
+ if (_doctypeSystem != null) {
+ appendDTD(elementName);
+ }
+ _firstElement = false;
+ }
+
+ if (_indent) {
+ indent(_lineFeedNextStartTag);
+ _lineFeedNextStartTag = true;
+ _indentNextEndTag = false;
+ _indentLevel++;
+ }
+
+ _buffer.append('<').append(elementName);
+
+ _depth++;
+ _startTagOpen = true;
+ _elementName = elementName;
+ }
+
+ public void endElement(String elementName) throws TransletException {
+// System.out.println("endElement = " + elementName);
+ if (_cdataTagOpen) {
+ closeCDATA();
+ }
+
+ if (_startTagOpen) {
+ appendAttributes();
+ _buffer.append("/>");
+ _startTagOpen = false;
+
+ if (_indent) {
+ _indentLevel--;
+ _indentNextEndTag = true;
+ }
+ }
+ else {
+ if (_indent) {
+ _indentLevel--;
+
+ if (_indentNextEndTag) {
+ indent(_indentNextEndTag);
+ _indentNextEndTag = true;
+ _lineFeedNextStartTag = true;
+ }
+ }
+ _buffer.append("</").append(elementName).append('>');
+ _indentNextEndTag = true;
+ }
+
+ if (((Integer) _cdataStack.peek()).intValue() == _depth) {
+ _cdataStack.pop();
+ }
+
+ popNamespaces();
+ _depth--;
+ }
+
+ public void characters(String characters) throws TransletException {
+// System.out.println("characters() string '" + characters + "'");
+ characters(characters.toCharArray(), 0, characters.length());
+ }
+
+ public void characters(char[] characters, int offset, int length)
+ throws TransletException
+ {
+ if (length <= 0) return;
+
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+
+ final Integer I = (Integer) _cdataStack.peek();
+ if (I.intValue() == _depth && !_cdataTagOpen) {
+ startCDATA(characters, offset, length);
+ }
+ else if (_escaping) {
+ if (_cdataTagOpen) {
+ escapeCDATA(characters, offset, length);
+ }
+ else {
+ escapeCharacters(characters, offset, length);
+ }
+ }
+ else {
+ _buffer.append(characters, offset, length);
+ }
+ }
+
+ public void attribute(String name, String value)
+ throws TransletException
+ {
+// System.out.println("attribute = " + name + " " + value);
+ if (_startTagOpen) {
+ int k;
+ final Attribute attr =
+ new Attribute(patchName(name), escapeString(value));
+
+ if ((k = _attributes.indexOf(attr)) >= 0) {
+ _attributes.setElementAt(attr, k);
+ }
+ else {
+ _attributes.add(attr);
+ }
+ }
+ }
+
+ public void comment(String comment) throws TransletException {
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+ else if (_cdataTagOpen) {
+ closeCDATA();
+ }
+ appendComment(comment);
+ }
+
+ public void processingInstruction(String target, String data)
+ throws TransletException
+ {
+// System.out.println("PI target = " + target + " data = " + data);
+ if (_startTagOpen) {
+ closeStartTag();
+ }
+ else if (_cdataTagOpen) {
+ closeCDATA();
+ }
+
+ _buffer.append("<?").append(target).append(' ')
+ .append(data).append("?>");
+ }
+
+ public boolean setEscaping(boolean escape) throws TransletException
+ {
+ final boolean temp = _escaping;
+ _escaping = escape;
+ return temp;
+ }
+
+ public void namespace(final String prefix, final String uri)
+ throws TransletException
+ {
+// System.out.println("namespace prefix = " + prefix + " uri = " + uri);
+ String escaped = escapeString(uri);
+ if (_startTagOpen) {
+ if (pushNamespace(prefix, escaped)) {
+ _buffer.append(' ').append(XMLNS_PREFIX);
+ if (prefix != null && prefix != EMPTYSTRING) {
+ _buffer.append(':').append(prefix);
+ }
+ _buffer.append("=\"").append(escaped).append('"');
+ }
+ }
+ else if (prefix != EMPTYSTRING || uri != EMPTYSTRING) {
+ BasisLibrary.runTimeError(BasisLibrary.STRAY_NAMESPACE_ERR,
+ prefix, escaped);
+ }
+ }
+
+ protected void closeStartTag() throws TransletException {
+ super.closeStartTag();
+
+ if (_cdata != null) {
+ final String localName = getLocalName(_elementName);
+ final String uri = getNamespaceURI(_elementName, true);
+
+ final StringBuffer expandedName = (uri == EMPTYSTRING) ?
+ new StringBuffer(_elementName) :
+ new StringBuffer(uri).append(':').append(localName);
+
+ if (_cdata.containsKey(expandedName.toString())) {
+ _cdataStack.push(new Integer(_depth));
+ }
+ }
+ }
+
+ /**
+ * Utility method - pass a whole charactes as CDATA to SAX handler
+ */
+ private void startCDATA(char[] ch, int off, int len) {
+ final int limit = off + len;
+ int offset = off;
+
+ // Output start bracket - "<![CDATA["
+ _buffer.append(BEGCDATA);
+
+ // Detect any occurence of "]]>" in the character array
+ for (int i = offset; i < limit - 2; i++) {
+ if (ch[i] == ']' && ch[i + 1] == ']' && ch[i + 2] == '>') {
+ _buffer.append(ch, offset, i - offset)
+ .append(CNTCDATA);
+ offset = i + 3;
+ i += 2; // Skip next chars ']' and '>'.
+ }
+ }
+
+ // Output the remaining characters
+ if (offset < limit) {
+ _buffer.append(ch, offset, limit - offset);
+ }
+ _cdataTagOpen = true;
+ }
+
+ private void closeCDATA() {
+ _buffer.append(ENDCDATA);
+ _cdataTagOpen = false;
+ }
+
+ /**
+ * Utility method - escape special characters and pass to SAX handler
+ */
+ private void escapeCDATA(char[] ch, int off, int len) {
+ int offset = off;
+ int limit = off + len;
+
+ if (limit > ch.length) {
+ limit = ch.length;
+ }
+
+ // Step through characters and escape all special characters
+ for (int i = off; i < limit; i++) {
+ final char current = ch[i];
+
+ if (current > '\u00ff') {
+ _buffer.append(ch, offset, i - offset)
+ .append(CDATA_ESC_START)
+ .append(Integer.toString((int) current))
+ .append(CDATA_ESC_END);
+ offset = i + 1;
+ }
+ }
+ // Output remaining characters
+ if (offset < limit) {
+ _buffer.append(ch, offset, limit - offset);
+ }
+ }
+
+ /**
+ * This method escapes special characters used in attribute values
+ */
+ private String escapeString(String value) {
+ final char[] ch = value.toCharArray();
+ final int limit = ch.length;
+ StringBuffer result = new StringBuffer();
+
+ int offset = 0;
+ for (int i = 0; i < limit; i++) {
+ switch (ch[i]) {
+ case '&':
+ result.append(ch, offset, i - offset).append(AMP);
+ offset = i + 1;
+ break;
+ case '"':
+ result.append(ch, offset, i - offset).append(QUOTE);
+ offset = i + 1;
+ break;
+ case '<':
+ result.append(ch, offset, i - offset).append(LT);
+ offset = i + 1;
+ break;
+ case '>':
+ result.append(ch, offset, i - offset).append(GT);
+ offset = i + 1;
+ break;
+ case '\n':
+ result.append(ch, offset, i - offset).append(CRLF);
+ offset = i + 1;
+ break;
+ }
+ }
+
+ if (offset < limit) {
+ result.append(ch, offset, limit - offset);
+ }
+ return result.toString();
+ }
+}
diff --git a/src/org/apache/xalan/xsltc/runtime/output/TransletOutputHandlerFactory.java b/src/org/apache/xalan/xsltc/runtime/output/TransletOutputHandlerFactory.java
new file mode 100644
index 0000000..ad021fd
--- /dev/null
+++ b/src/org/apache/xalan/xsltc/runtime/output/TransletOutputHandlerFactory.java
@@ -0,0 +1,212 @@
+/*
+ * @(#)$Id$
+ *
+ * The Apache Software License, Version 1.1
+ *
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Xalan" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES{} LOSS OF
+ * USE, DATA, OR PROFITS{} OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation and was
+ * originally based on software copyright (c) 2001, Sun
+ * Microsystems., http://www.sun.com. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * @author Santiago Pericas-Geertsen
+ *
+ */
+
+package org.apache.xalan.xsltc.runtime.output;
+
+import java.io.Writer;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ext.LexicalHandler;
+import org.apache.xalan.xsltc.runtime.*;
+import org.apache.xalan.xsltc.TransletException;
+import org.apache.xalan.xsltc.TransletOutputHandler;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.xalan.xsltc.trax.SAX2DOM;
+
+public class TransletOutputHandlerFactory {
+
+ public static final int STREAM = 0;
+ public static final int SAX = 1;
+ public static final int DOM = 2;
+
+ private String _encoding = "utf-8";
+ private String _method = null;
+ private int _outputType = STREAM;
+ private OutputStream _ostream = System.out;
+ private Writer _writer = null;
+ private Node _node = null;
+ private int _indentNumber = -1;
+ private ContentHandler _handler = null;
+ private LexicalHandler _lexHandler = null;
+
+ static public TransletOutputHandlerFactory newInstance() {
+ return new TransletOutputHandlerFactory();
+ }
+
+ public void setOutputType(int outputType) {
+ _outputType = outputType;
+ }
+
+ public void setEncoding(String encoding) {
+ if (encoding != null) {
+ _encoding = encoding;
+ }
+ }
+
+ public void setOutputMethod(String method) {
+ _method = method;
+ }
+
+ public void setOutputStream(OutputStream ostream) {
+ _ostream = ostream;
+ }
+
+ public void setWriter(Writer writer) {
+ _writer = writer;
+ }
+
+ public void setHandler(ContentHandler handler) {
+ _handler = handler;
+ }
+
+ public void setLexicalHandler(LexicalHandler lex) {
+ _lexHandler = lex;
+ }
+
+ public void setNode(Node node) {
+ _node = node;
+ }
+
+ public Node getNode() {
+ return (_handler instanceof SAX2DOM) ? ((SAX2DOM)_handler).getDOM()
+ : null;
+ }
+
+ public void setIndentNumber(int value) {
+ _indentNumber = value;
+ }
+
+ public TransletOutputHandler getTransletOutputHandler()
+ throws IOException, ParserConfigurationException
+ {
+ switch (_outputType) {
+ case STREAM:
+ StreamOutput result = null;
+
+ if (_method == null) {
+ result = (_writer == null) ?
+ new StreamUnknownOutput(_ostream, _encoding) :
+ new StreamUnknownOutput(_writer, _encoding);
+ }
+ else if (_method.equalsIgnoreCase("xml")) {
+ result = (_writer == null) ?
+ new StreamXMLOutput(_ostream, _encoding) :
+ new StreamXMLOutput(_writer, _encoding);
+ }
+ else if (_method.equalsIgnoreCase("html")) {
+ result = (_writer == null) ?
+ new StreamHTMLOutput(_ostream, _encoding) :
+ new StreamHTMLOutput(_writer, _encoding);
+ }
+ else if (_method.equalsIgnoreCase("text")) {
+ result = (_writer == null) ?
+ new StreamTextOutput(_ostream, _encoding) :
+ new StreamTextOutput(_writer, _encoding);
+ }
+
+ if (result != null && _indentNumber >= 0) {
+ result.setIndentNumber(_indentNumber);
+ }
+ return result;
+ case DOM:
+ _handler = (_node != null) ? new SAX2DOM(_node) :
+ new SAX2DOM();
+ _lexHandler = (LexicalHandler)_handler;
+ // falls through
+ case SAX:
+ if (_method == null) {
+ _method = "xml"; // default case
+ }
+
+ if (_method.equalsIgnoreCase("xml")) {
+ return (_lexHandler == null) ?
+ new SAXXMLOutput(_handler, _encoding) :
+ new SAXXMLOutput(_handler, _lexHandler, _encoding);
+ }
+ else if (_method.equalsIgnoreCase("html")) {
+ return (_lexHandler == null) ?
+ new SAXHTMLOutput(_handler, _encoding) :
+ new SAXHTMLOutput(_handler, _lexHandler, _encoding);
+ }
+ else if (_method.equalsIgnoreCase("text")) {
+ return (_lexHandler == null) ?
+ new SAXTextOutput(_handler, _encoding) :
+ new SAXTextOutput(_handler, _lexHandler, _encoding);
+ }
+ break;
+ }
+ return null;
+ }
+
+ // Temporary - returns an instance of TextOutput
+ public TransletOutputHandler getOldTransletOutputHandler() throws IOException {
+ DefaultSAXOutputHandler saxHandler =
+ new DefaultSAXOutputHandler(_ostream, _encoding);
+ return new TextOutput((ContentHandler)saxHandler,
+ (LexicalHandler)saxHandler, _encoding);
+ }
+}
diff --git a/src/org/apache/xalan/xsltc/trax/DOM2SAX.java b/src/org/apache/xalan/xsltc/trax/DOM2SAX.java
index af2ddb7..48ee609 100644
--- a/src/org/apache/xalan/xsltc/trax/DOM2SAX.java
+++ b/src/org/apache/xalan/xsltc/trax/DOM2SAX.java
@@ -63,8 +63,13 @@
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.ext.LexicalHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.Locator;
import org.xml.sax.ErrorHandler;
@@ -74,6 +79,9 @@
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,54 +89,114 @@
import org.w3c.dom.Entity;
import org.w3c.dom.Notation;
-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 LexicalHandler _lex = 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 ErrorHandler getErrorHandler() {
- return null;
- }
-
- public boolean getFeature(String name) throws SAXNotRecognizedException,
- SAXNotSupportedException
+ public void setContentHandler(ContentHandler handler) throws
+ NullPointerException
{
- return false;
+ _sax = handler;
+ if (handler instanceof LexicalHandler) {
+ _lex = (LexicalHandler) handler;
+ }
}
- public void setFeature(String name, boolean value) throws
- SAXNotRecognizedException, SAXNotSupportedException
+ /**
+ * 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;
+ }
+
+ /*
+ * 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
+ {
+ final Stack uriStack = (Stack) _nsPrefixes.get(prefix);
+
+ if (uriStack != null) {
+ _sax.endPrefixMapping(prefix);
+ uriStack.pop();
+ }
+ }
+
+ /**
+ * 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
- case Node.COMMENT_NODE: // should be handled!!!
- case Node.CDATA_SECTION_NODE:
case Node.DOCUMENT_FRAGMENT_NODE:
case Node.DOCUMENT_TYPE_NODE :
case Node.ENTITY_NODE :
@@ -136,9 +204,29 @@
case Node.NOTATION_NODE :
// These node types are ignored!!!
break;
+ case Node.CDATA_SECTION_NODE:
+ final String cdata = node.getNodeValue();
+ if (_lex != null) {
+ _lex.startCDATA();
+ _sax.characters(cdata.toCharArray(), 0, cdata.length());
+ _lex.endCDATA();
+ }
+ else {
+ // in the case where there is no lex handler, we still
+ // want the text of the cdate to make its way through.
+ _sax.characters(cdata.toCharArray(), 0, cdata.length());
+ }
+ break;
+ case Node.COMMENT_NODE: // should be handled!!!
+ if (_lex != null) {
+ final String value = node.getNodeValue();
+ _lex.comment(value.toCharArray(), 0, value.length());
+ }
+ break;
case Node.DOCUMENT_NODE:
_sax.setDocumentLocator(this);
+
_sax.startDocument();
Node next = node.getFirstChild();
while (next != null) {
@@ -149,29 +237,85 @@
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 +330,133 @@
}
}
+ /**
+ * This class is only used internally so this method should never
+ * be called.
+ */
+ public DTDHandler getDTDHandler() {
+ return null;
+ }
+
+ /**
+ * 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
+ {
+ 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.");
}
- public void setContentHandler(ContentHandler handler) throws
- NullPointerException
- {
- if (handler == null ) throw new NullPointerException();
- _sax = handler;
- }
+
+ /**
+ * 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;
+ }
- // private
+ /**
+ * This class is only used internally so this method should never
+ * be called.
+ */
+ public String getSystemId() {
+ return null;
+ }
+
+ // 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..20b8d71 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;
@@ -71,168 +73,168 @@
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+import org.w3c.dom.Comment;
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.xml.sax.ext.LexicalHandler;
+import org.xml.sax.SAXException;
+import org.apache.xalan.xsltc.runtime.Constants;
-class SAX2DOM implements ContentHandler {
+public class SAX2DOM implements ContentHandler, LexicalHandler, Constants {
- private Document _document = null;
- private DocumentBuilder _builder = null;
- private Stack _nodeStk = null;
-
+ private Document _root = null;
+ private Stack _nodeStk = new Stack();
+ private Vector _namespaceDecls = 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();
- }
-
-
- public void ignorableWhitespace(char[] ch, int start, int length) {
- }
-
- public void processingInstruction(String target, String data) {
- }
-
- public void setDocumentLocator(Locator locator) {
- }
-
- public void skippedEntity(String name) {
+ _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) {
+ }
+
+ /**
+ * adds processing instruction node to DOM.
+ */
+ public void processingInstruction(String target, String data) {
+ final Node last = (Node)_nodeStk.peek();
+ ProcessingInstruction pi = _root.createProcessingInstruction(
+ target, data);
+ if (pi != null) last.appendChild(pi);
+ }
+
+ /**
+ * 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) {
}
- // 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;
- }
+ /**
+ * Lexical Handler method to create comment node in DOM tree.
+ */
+ public void comment(char[] ch, int start, int length) {
+ final Node last = (Node)_nodeStk.peek();
+ Comment comment = _root.createComment(new String(ch,start,length));
+ if (comment != null) last.appendChild(comment);
+ }
- // 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();
- }
- }
- }
+ // Lexical Handler methods- not implemented
+ public void startCDATA() { }
+ public void endCDATA() { }
+ public void startEntity(java.lang.String name) { }
+ public void endDTD() { }
+ public void endEntity(String name) { }
+ public void startDTD(String name, String publicId, String systemId)
+ throws SAXException { }
}
diff --git a/src/org/apache/xalan/xsltc/trax/TemplatesHandlerImpl.java b/src/org/apache/xalan/xsltc/trax/TemplatesHandlerImpl.java
index 3c8f8f0..0af479d 100644
--- a/src/org/apache/xalan/xsltc/trax/TemplatesHandlerImpl.java
+++ b/src/org/apache/xalan/xsltc/trax/TemplatesHandlerImpl.java
@@ -65,6 +65,7 @@
import javax.xml.transform.*;
import javax.xml.transform.sax.*;
+import org.xml.sax.Locator;
import org.apache.xalan.xsltc.Translet;
import org.apache.xalan.xsltc.runtime.AbstractTranslet;
import org.apache.xalan.xsltc.compiler.*;
@@ -76,12 +77,18 @@
public class TemplatesHandlerImpl extends Parser implements TemplatesHandler {
private String _systemId;
+ private int _indentNumber;
+
+ // Temporary
+ private boolean _oldOutputSystem;
/**
* Default constructor
*/
- protected TemplatesHandlerImpl() {
+ protected TemplatesHandlerImpl(int indentNumber, boolean oldOutputSystem) {
super(null);
+ _indentNumber = indentNumber;
+ _oldOutputSystem = oldOutputSystem;
}
/**
@@ -91,8 +98,9 @@
// 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,51 +134,61 @@
* 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();
// Set the translet class name if not already set
String transletName = TransformerFactoryImpl._defaultTransletName;
- if (_systemId != null) transletName = Util.baseName(_systemId);
+ if (_systemId != null) {
+ transletName = Util.baseName(_systemId);
+ }
xsltc.setClassName(transletName);
+ // Get java-legal class name from XSLTC module
+ transletName = xsltc.getClassName();
+
Stylesheet stylesheet = null;
SyntaxTreeNode root = getDocumentRoot();
// Compile the translet - this is where the work is done!
- if ((!errorsFound()) && (root != null)) {
+ if (!errorsFound() && root != null) {
// Create a Stylesheet element from the root node
stylesheet = makeStylesheet(root);
stylesheet.setSystemId(_systemId);
stylesheet.setParentStylesheet(null);
setCurrentStylesheet(stylesheet);
- // Create AST under the Stylesheet element (parse & type-check)
+ // Create AST under the Stylesheet element
createAST(stylesheet);
}
// Generate the bytecodes and output the translet class(es)
- if ((!errorsFound()) && (stylesheet != null)) {
+ if (!errorsFound() && stylesheet != null) {
stylesheet.setMultiDocument(xsltc.isMultiDocument());
stylesheet.translate();
}
- xsltc.printWarnings();
-
- // Check that the transformation went well before returning
- if (bytecodes == null) {
- xsltc.printErrors();
- return null;
+ if (!errorsFound()) {
+ // Check that the transformation went well before returning
+ final byte[][] bytecodes = xsltc.getBytecodes();
+ if (bytecodes != null) {
+ return new TemplatesImpl(xsltc.getBytecodes(), transletName,
+ getOutputProperties(), _indentNumber, _oldOutputSystem);
+ }
}
-
- return(new TemplatesImpl(bytecodes, transletName));
}
catch (CompilerException e) {
- return null;
+ // falls through
}
+ return null;
+ }
+
+ /**
+ * recieve an object for locating the origin of SAX document events.
+ * Most SAX parsers will use this method to inform content handler
+ * of the location of the parsed document.
+ */
+ public void setDocumentLocator(Locator locator) {
+ setSystemId(locator.getSystemId());
}
}
diff --git a/src/org/apache/xalan/xsltc/trax/TemplatesImpl.java b/src/org/apache/xalan/xsltc/trax/TemplatesImpl.java
index e1c099c..d0a2a95 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 <Jochen.Cordes@t-online.de>
+ * @author Santiago Pericas-Geertsen
*
*/
@@ -96,6 +97,13 @@
// and _bytecodes arrays (above).
private int _transletIndex = -1;
+ private Properties _outputProperties;
+
+ private int _indentNumber;
+
+ // Temporary
+ private boolean _oldOutputSystem;
+
// Our own private class loader - builds Class definitions from bytecodes
private class TransletClassLoader extends ClassLoader {
@@ -126,9 +134,15 @@
* The bytecodes for the translet and auxiliary classes, plus the name of
* the main translet class, must be supplied
*/
- protected TemplatesImpl(byte[][] bytecodes, String transletName) {
+ protected TemplatesImpl(byte[][] bytecodes, String transletName,
+ Properties outputProperties, int indentNumber,
+ boolean oldOutputSystem)
+ {
_bytecodes = bytecodes;
_name = transletName;
+ _outputProperties = outputProperties;
+ _indentNumber = indentNumber;
+ _oldOutputSystem = oldOutputSystem;
}
/**
@@ -176,8 +190,13 @@
(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());
}
}
);
@@ -250,7 +269,8 @@
*/
public Transformer newTransformer()
throws TransformerConfigurationException {
- return(new TransformerImpl(getTransletInstance()));
+ return new TransformerImpl(getTransletInstance(), _outputProperties,
+ _indentNumber, _oldOutputSystem);
}
/**
diff --git a/src/org/apache/xalan/xsltc/trax/TransformerFactoryImpl.java b/src/org/apache/xalan/xsltc/trax/TransformerFactoryImpl.java
index 2f2cc9b..29dbaa4 100644
--- a/src/org/apache/xalan/xsltc/trax/TransformerFactoryImpl.java
+++ b/src/org/apache/xalan/xsltc/trax/TransformerFactoryImpl.java
@@ -140,8 +140,11 @@
}
}
- // This flag is passed to the compiler - will produce stack traces etc.
+ // This flags are passed to the compiler
private boolean _debug = false;
+ private boolean _disableInlining = false;
+ private boolean _oldOutputSystem = false;
+ private int _indentNumber = -1;
/**
* javax.xml.transform.sax.TransformerFactory implementation.
@@ -206,20 +209,64 @@
* @throws IllegalArgumentException
*/
public void setAttribute(String name, Object value)
- throws IllegalArgumentException {
+ throws IllegalArgumentException
+ {
// Set the default translet name (ie. class name), which will be used
// for translets that cannot be given a name from their system-id.
- if ((name.equals("translet-name")) && (value instanceof String)) {
- _defaultTransletName = (String)value;
+ if (name.equals("translet-name") && value instanceof String) {
+ _defaultTransletName = (String) value;
+ return;
}
else if (name.equals("debug")) {
- _debug = true;
+ if (value instanceof Boolean) {
+ _debug = ((Boolean) value).booleanValue();
+ return;
+ }
+ else if (value instanceof String) {
+ _debug = ((String) value).equalsIgnoreCase("true");
+ return;
+ }
}
- else {
- // Throw an exception for all other attributes
- ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_INVALID_ATTR_ERR, name);
- throw new IllegalArgumentException(err.toString());
+ else if (name.equals("disable-inlining")) {
+ if (value instanceof Boolean) {
+ _disableInlining = ((Boolean) value).booleanValue();
+ return;
+ }
+ else if (value instanceof String) {
+ _disableInlining = ((String) value).equalsIgnoreCase("true");
+ return;
+ }
}
+ else if (name.equals("old-output")) {
+ if (value instanceof Boolean) {
+ _oldOutputSystem = ((Boolean) value).booleanValue();
+ return;
+ }
+ else if (value instanceof String) {
+ _oldOutputSystem = ((String) value).equalsIgnoreCase("true");
+ return;
+ }
+ }
+ else if (name.equals("indent-number")) {
+ if (value instanceof String) {
+ try {
+ _indentNumber = Integer.parseInt((String) value);
+ return;
+ }
+ catch (NumberFormatException e) {
+ // Falls through
+ }
+ }
+ else if (value instanceof Integer) {
+ _indentNumber = ((Integer) value).intValue();
+ return;
+ }
+ }
+
+ // Throw an exception for all other attributes
+ final ErrorMsg err
+ = new ErrorMsg(ErrorMsg.JAXP_INVALID_ATTR_ERR, name);
+ throw new IllegalArgumentException(err.toString());
}
/**
@@ -320,6 +367,7 @@
XSLTC xsltc = new XSLTC();
if (_debug) xsltc.setDebug(true);
+ if (_disableInlining) xsltc.setTemplateInlining(false);
xsltc.init();
// Compile the default copy-stylesheet
@@ -336,10 +384,14 @@
}
// Create a Transformer object and store for other calls
- Templates templates = new TemplatesImpl(bytecodes,_defaultTransletName);
+ Templates templates = new TemplatesImpl(bytecodes, _defaultTransletName,
+ xsltc.getOutputProperties(), _indentNumber, _oldOutputSystem);
+
_copyTransformer = templates.newTransformer();
- if (_uriResolver != null) _copyTransformer.setURIResolver(_uriResolver);
- return(_copyTransformer);
+ if (_uriResolver != null) {
+ _copyTransformer.setURIResolver(_uriResolver);
+ }
+ return _copyTransformer;
}
/**
@@ -363,21 +415,18 @@
/**
* Pass warning messages from the compiler to the error listener
*/
- private void passWarningsToListener(Vector messages) {
- try {
- // Nothing to do if there is no registered error listener
- if (_errorListener == null) return;
- // Nothing to do if there are not warning messages
- if (messages == null) return;
- // Pass messages to listener, one by one
- final int count = messages.size();
- for (int pos=0; pos<count; pos++) {
- String message = messages.elementAt(pos).toString();
- _errorListener.warning(new TransformerException(message));
- }
+ private void passWarningsToListener(Vector messages)
+ throws TransformerException
+ {
+ if (_errorListener == null || messages == null ) {
+ return;
}
- catch (TransformerException e) {
- // nada
+ // Pass messages to listener, one by one
+ final int count = messages.size();
+ for (int pos = 0; pos < count; pos++) {
+ String message = messages.elementAt(pos).toString();
+ _errorListener.error(
+ new TransformerConfigurationException(message));
}
}
@@ -429,6 +478,9 @@
xsltc.setXMLReader(dom2sax);
// try to get SAX InputSource from DOM Source.
input = SAXSource.sourceToInputSource(source);
+ if (input == null){
+ input = new InputSource(domsrc.getSystemId());
+ }
}
// Try to get InputStream or Reader from StreamSource
else if (source instanceof StreamSource) {
@@ -474,10 +526,10 @@
*/
public Templates newTemplates(Source source)
throws TransformerConfigurationException {
-
// Create and initialize a stylesheet compiler
final XSLTC xsltc = new XSLTC();
if (_debug) xsltc.setDebug(true);
+ if (_disableInlining) xsltc.setTemplateInlining(false);
xsltc.init();
// Set a document loader (for xsl:include/import) if defined
@@ -499,10 +551,17 @@
final String transletName = xsltc.getClassName();
// Pass compiler warnings to the error listener
- if (_errorListener != null)
- passWarningsToListener(xsltc.getWarnings());
- else
+ if (_errorListener != this) {
+ try {
+ passWarningsToListener(xsltc.getWarnings());
+ }
+ catch (TransformerException e) {
+ throw new TransformerConfigurationException(e);
+ }
+ }
+ else {
xsltc.printWarnings();
+ }
// Check that the transformation went well before returning
if (bytecodes == null) {
@@ -514,7 +573,8 @@
ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_COMPILE_ERR);
throw new TransformerConfigurationException(err.toString());
}
- return(new TemplatesImpl(bytecodes, transletName));
+ return new TemplatesImpl(bytecodes, transletName,
+ xsltc.getOutputProperties(), _indentNumber, _oldOutputSystem);
}
/**
@@ -527,7 +587,10 @@
*/
public TemplatesHandler newTemplatesHandler()
throws TransformerConfigurationException {
- return(new TemplatesHandlerImpl());
+ final TemplatesHandlerImpl handler =
+ new TemplatesHandlerImpl(_indentNumber, _oldOutputSystem);
+ handler.init();
+ return handler;
}
/**
diff --git a/src/org/apache/xalan/xsltc/trax/TransformerHandlerImpl.java b/src/org/apache/xalan/xsltc/trax/TransformerHandlerImpl.java
index b1a87b7..6000457 100644
--- a/src/org/apache/xalan/xsltc/trax/TransformerHandlerImpl.java
+++ b/src/org/apache/xalan/xsltc/trax/TransformerHandlerImpl.java
@@ -63,12 +63,14 @@
package org.apache.xalan.xsltc.trax;
import org.xml.sax.*;
+import org.xml.sax.ext.DeclHandler;
import javax.xml.transform.*;
import javax.xml.transform.sax.*;
import org.apache.xalan.xsltc.Translet;
import org.apache.xalan.xsltc.dom.DOMImpl;
+import org.apache.xalan.xsltc.dom.DOMBuilder;
import org.apache.xalan.xsltc.dom.DTDMonitor;
import org.apache.xalan.xsltc.runtime.AbstractTranslet;
import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
@@ -76,13 +78,13 @@
/**
* Implementation of a JAXP1.1 TransformerHandler
*/
-public class TransformerHandlerImpl implements TransformerHandler {
+public class TransformerHandlerImpl implements TransformerHandler, DeclHandler {
private TransformerImpl _transformer;
private AbstractTranslet _translet = null;
private String _systemId;
private DOMImpl _dom = null;
- private ContentHandler _handler = null;
+ private DOMBuilder _handler = null;
private DTDMonitor _dtd = null;
private Result _result = null;
@@ -97,6 +99,13 @@
// Get a reference to the translet wrapped inside the transformer
_translet = _transformer.getTranslet();
+
+ // Create a DOMBuilder object and get the handler
+ _dom = new DOMImpl();
+ _handler = _dom.getBuilder();
+
+ // Create a new DTD monitor
+ _dtd = new DTDMonitor();
}
/**
@@ -126,7 +135,7 @@
* @return The Transformer object
*/
public Transformer getTransformer() {
- return(_transformer);
+ return _transformer;
}
/**
@@ -157,7 +166,8 @@
* Receive notification of character data.
*/
public void characters(char[] ch, int start, int length)
- throws SAXException {
+ throws SAXException
+ {
_handler.characters(ch, start, length);
}
@@ -172,9 +182,8 @@
throw new SAXException(err.toString());
}
- // Create an internal DOM (not W3C) and get SAX2 input handler
- _dom = new DOMImpl();
- _handler = _dom.getBuilder();
+ // Set document URI
+ _dom.setDocumentURI(_systemId);
// Proxy call
_handler.startDocument();
@@ -187,12 +196,12 @@
public void endDocument() throws SAXException {
// Signal to the DOMBuilder that the document is complete
_handler.endDocument();
- // Pass unparsed entity declarations (if any) to the translet
- if (_dtd != null) _translet.setDTDMonitor(_dtd);
+
// Run the transformation now if we have a reference to a Result object
if (_result != null) {
try {
_transformer.setDOM(_dom);
+ _transformer.setDTDMonitor(_dtd); // for id/key
_transformer.transform(null, _result);
}
catch (TransformerException e) {
@@ -235,31 +244,54 @@
}
/**
+ * Implements org.xml.sax.ext.LexicalHandler.startCDATA()
+ */
+ public void startCDATA() throws SAXException {
+ _handler.startCDATA();
+ }
+
+ /**
+ * Implements org.xml.sax.ext.LexicalHandler.endCDATA()
+ */
+ public void endCDATA() throws SAXException {
+ _handler.endCDATA();
+ }
+
+ /**
+ * Implements org.xml.sax.ext.LexicalHandler.comment()
+ * Receieve notification of a comment
+ */
+ public void comment(char[] ch, int start, int length)
+ throws SAXException
+ {
+ _handler.comment(ch, start, length);
+ }
+
+ /**
* Implements org.xml.sax.ContentHandler.ignorableWhitespace()
* Receive notification of ignorable whitespace in element
* content. Similar to characters(char[], int, int).
*/
public void ignorableWhitespace(char[] ch, int start, int length)
- throws SAXException {
+ throws SAXException
+ {
_handler.ignorableWhitespace(ch, start, length);
}
/**
* Implements org.xml.sax.ContentHandler.setDocumentLocator()
* Receive an object for locating the origin of SAX document events.
- * We do not handle this method, and the input is quietly ignored
*/
public void setDocumentLocator(Locator locator) {
- // Not handled by DOMBuilder - ignored
+ _handler.setDocumentLocator(locator);
}
/**
* Implements org.xml.sax.ContentHandler.skippedEntity()
* Receive notification of a skipped entity.
- * We do not handle this method, and the input is quietly ignored
*/
- public void skippedEntity(String name) {
- // Not handled by DOMBuilder - ignored
+ public void skippedEntity(String name) throws SAXException {
+ _handler.skippedEntity(name);
}
/**
@@ -280,66 +312,86 @@
}
/**
- * Implements org.xml.sax.DTDHandler.notationDecl()
- * End the scope of a prefix-URI Namespace mapping.
- * We do not handle this method, and the input is quietly ignored.
+ * Implements org.xml.sax.ext.LexicalHandler.startDTD()
*/
- public void notationDecl(String name, String publicId, String systemId) {
- // Not handled by DTDMonitor - ignored
+ public void startDTD(String name, String publicId, String systemId)
+ throws SAXException
+ {
+ _handler.startDTD(name, publicId, systemId);
+ }
+
+ /**
+ * Implements org.xml.sax.ext.LexicalHandler.endDTD()
+ */
+ public void endDTD() throws SAXException {
+ _handler.endDTD();
+ }
+
+ /**
+ * Implements org.xml.sax.ext.LexicalHandler.startEntity()
+ */
+ public void startEntity(String name) throws SAXException {
+ _handler.startEntity(name);
+ }
+
+ /**
+ * Implements org.xml.sax.ext.LexicalHandler.endEntity()
+ */
+ public void endEntity(String name) throws SAXException {
+ _handler.endEntity(name);
}
/**
* Implements org.xml.sax.DTDHandler.unparsedEntityDecl()
- * End the scope of a prefix-URI Namespace mapping.
*/
- public void unparsedEntityDecl(String name, String publicId,
- String systemId, String notationName)
- throws SAXException {
- // Create new contained for unparsed entities
- if (_dtd == null) _dtd = new DTDMonitor();
+ public void unparsedEntityDecl(String name, String publicId,
+ String systemId, String notationName) throws SAXException
+ {
_dtd.unparsedEntityDecl(name, publicId, systemId, notationName);
}
/**
- * Implements org.xml.sax.ext.LexicalHandler.startDTD()
- * We do not handle this method, and the input is quietly ignored
+ * Implements org.xml.sax.DTDHandler.notationDecl()
*/
- public void startDTD(String name, String publicId, String systemId) { }
+ public void notationDecl(String name, String publicId, String systemId)
+ throws SAXException
+ {
+ _dtd.notationDecl(name, publicId, systemId);
+ }
/**
- * Implements org.xml.sax.ext.LexicalHandler.endDTD()
- * We do not handle this method, and the input is quietly ignored
+ * Implements org.xml.sax.ext.DeclHandler.attributeDecl()
*/
- public void endDTD() { }
+ public void attributeDecl(String eName, String aName, String type,
+ String valueDefault, String value) throws SAXException
+ {
+ _dtd.attributeDecl(eName, aName, type, valueDefault, value);
+ }
/**
- * Implements org.xml.sax.ext.LexicalHandler.startEntity()
- * We do not handle this method, and the input is quietly ignored
+ * Implements org.xml.sax.ext.DeclHandler.elementDecl()
*/
- public void startEntity(String name) { }
+ public void elementDecl(String name, String model)
+ throws SAXException
+ {
+ _dtd.elementDecl(name, model);
+ }
/**
- * Implements org.xml.sax.ext.LexicalHandler.endEntity()
- * We do not handle this method, and the input is quietly ignored
+ * Implements org.xml.sax.ext.DeclHandler.externalEntityDecl()
*/
- public void endEntity(String name) { }
+ public void externalEntityDecl(String name, String publicId, String systemId)
+ throws SAXException
+ {
+ _dtd.externalEntityDecl(name, publicId, systemId);
+ }
/**
- * Implements org.xml.sax.ext.LexicalHandler.startCDATA()
- * We do not handle this method, and the input is quietly ignored
+ * Implements org.xml.sax.ext.DeclHandler.externalEntityDecl()
*/
- public void startCDATA() { }
-
- /**
- * Implements org.xml.sax.ext.LexicalHandler.endCDATA()
- * We do not handle this method, and the input is quietly ignored
- */
- public void endCDATA() { }
-
- /**
- * Implements org.xml.sax.ext.LexicalHandler.comment()
- * We do not handle this method, and the input is quietly ignored
- */
- public void comment(char[] ch, int start, int length) { }
-
+ public void internalEntityDecl(String name, String value)
+ throws SAXException
+ {
+ _dtd.internalEntityDecl(name, value);
+ }
}
diff --git a/src/org/apache/xalan/xsltc/trax/TransformerImpl.java b/src/org/apache/xalan/xsltc/trax/TransformerImpl.java
index 24e66cf..9e4e531 100644
--- a/src/org/apache/xalan/xsltc/trax/TransformerImpl.java
+++ b/src/org/apache/xalan/xsltc/trax/TransformerImpl.java
@@ -101,9 +101,12 @@
import org.apache.xalan.xsltc.Translet;
import org.apache.xalan.xsltc.TransletException;
+import org.apache.xalan.xsltc.TransletOutputHandler;
import org.apache.xalan.xsltc.DOMCache;
import org.apache.xalan.xsltc.dom.*;
+import org.apache.xalan.xsltc.compiler.Constants;
import org.apache.xalan.xsltc.runtime.*;
+import org.apache.xalan.xsltc.runtime.output.*;
import org.apache.xalan.xsltc.compiler.*;
import org.apache.xalan.xsltc.compiler.util.ErrorMsg;
@@ -113,12 +116,13 @@
implements DOMCache, ErrorListener {
private AbstractTranslet _translet = null;
+ private String _method = null;
private String _encoding = null;
- private ContentHandler _handler = null;
+ private ContentHandler _handler = null;
private ErrorListener _errorListener = this;
private URIResolver _uriResolver = null;
- private Properties _properties = null;
+ private Properties _properties, _propertiesClone;
// Used for default output property settings
private final static String EMPTY_STRING = "";
@@ -129,25 +133,39 @@
// Pre-set DOMImpl to use as input (used only with TransformerHandlerImpl)
private DOMImpl _dom = null;
+ private DTDMonitor _dtdMonitor = null;
+
private final static String LEXICAL_HANDLER_PROPERTY =
"http://xml.org/sax/properties/lexical-handler";
private static final String NAMESPACE_FEATURE =
"http://xml.org/sax/features/namespaces";
+ private TransletOutputHandlerFactory _tohFactory = null;
+
+ private int _indentNumber;
+
+ // Temporary
+ private boolean _oldOutputSystem;
+
/**
* Implements JAXP's Transformer constructor
* Our Transformer objects always need a translet to do the actual work
*/
- protected TransformerImpl(Translet translet) {
- _translet = (AbstractTranslet)translet;
- _properties = createOutputProperties();
+ protected TransformerImpl(Translet translet, Properties outputProperties,
+ int indentNumber, boolean oldOutputSystem)
+ {
+ _translet = (AbstractTranslet) translet;
+ _properties = createOutputProperties(outputProperties);
+ _oldOutputSystem = oldOutputSystem;
+ _propertiesClone = (Properties) _properties.clone();
+ _indentNumber = indentNumber;
}
/**
* Returns the translet wrapped inside this Transformer
*/
protected AbstractTranslet getTranslet() {
- return(_translet);
+ return _translet;
}
/**
@@ -158,31 +176,168 @@
* @throws TransformerException
*/
public void transform(Source source, Result result)
- throws TransformerException {
-
+ throws TransformerException
+ {
if (_translet == null) {
ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_TRANSLET_ERR);
throw new TransformerException(err.toString());
}
- _handler = getOutputHandler(result);
- if (_handler == null) {
- ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_HANDLER_ERR);
- throw new TransformerException(err.toString());
+ // Pass output properties to the translet
+ setOutputProperties(_translet, _properties);
+
+ if (!_oldOutputSystem) {
+ final TransletOutputHandler toHandler = getOutputHandler(result);
+
+ if (toHandler == null) {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_HANDLER_ERR);
+ throw new TransformerException(err.toString());
+ }
+
+ if (_uriResolver != null) {
+ _translet.setDOMCache(this);
+ }
+
+ transform(source, toHandler, _encoding);
+
+ if (result instanceof DOMResult) {
+ ((DOMResult)result).setNode(_tohFactory.getNode());
+ }
+ }
+ else {
+ _handler = getOldOutputHandler(result);
+ if (_handler == null) {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_HANDLER_ERR);
+ throw new TransformerException(err.toString());
+ }
+
+ if (_uriResolver != null) {
+ _translet.setDOMCache(this);
+ }
+
+ // Run the transformation
+ transform(source, (ContentHandler)_handler, _encoding);
+
+ // If a DOMResult, then we must set the DOM Tree so it can
+ // be retrieved later
+ if (result instanceof DOMResult) {
+ ((DOMResult)result).setNode(((SAX2DOM)_handler).getDOM());
+ }
+ }
+ }
+
+ /**
+ * Create an output handler for the transformation output based on
+ * the type and contents of the TrAX Result object passed to the
+ * transform() method.
+ */
+ private TransletOutputHandler getOutputHandler(Result result)
+ throws TransformerException
+ {
+ // Get output method using get() to ignore defaults
+ _method = (String) _properties.get(OutputKeys.METHOD);
+
+ // Get encoding using getProperty() to use defaults
+ _encoding = (String) _properties.getProperty(OutputKeys.ENCODING);
+
+ _tohFactory = TransletOutputHandlerFactory.newInstance();
+ _tohFactory.setEncoding(_encoding);
+ if (_method != null) {
+ _tohFactory.setOutputMethod(_method);
}
- if (_uriResolver != null) {
- _translet.setDOMCache(this);
+ // Set indentation number in the factory
+ if (_indentNumber >= 0) {
+ _tohFactory.setIndentNumber(_indentNumber);
}
- // Run the transformation
- transform(source, (ContentHandler)_handler, _encoding);
+ // Return the content handler for this Result object
+ try {
+ // Result object could be SAXResult, DOMResult, or StreamResult
+ if (result instanceof SAXResult) {
+ final SAXResult target = (SAXResult)result;
+ final ContentHandler handler = target.getHandler();
- // If a DOMResult, then we must set the DOM Tree so it can
- // be retrieved later
- if (result instanceof DOMResult) {
- ((DOMResult)result).setNode(((SAX2DOM)_handler).getDOM());
+ _tohFactory.setHandler(handler);
+ if (handler instanceof LexicalHandler) {
+ _tohFactory.setLexicalHandler((LexicalHandler) handler);
+ }
+ _tohFactory.setOutputType(TransletOutputHandlerFactory.SAX);
+ return _tohFactory.getTransletOutputHandler();
+ }
+ else if (result instanceof DOMResult) {
+ _tohFactory.setNode(((DOMResult) result).getNode());
+ _tohFactory.setOutputType(TransletOutputHandlerFactory.DOM);
+ return _tohFactory.getTransletOutputHandler();
+ }
+ else if (result instanceof StreamResult) {
+ // Get StreamResult
+ final StreamResult target = (StreamResult) result;
+
+ // StreamResult may have been created with a java.io.File,
+ // java.io.Writer, java.io.OutputStream or just a String
+ // systemId.
+
+ _tohFactory.setOutputType(TransletOutputHandlerFactory.STREAM);
+
+ // try to get a Writer from Result object
+ final Writer writer = target.getWriter();
+ if (writer != null) {
+ _tohFactory.setWriter(writer);
+ return _tohFactory.getTransletOutputHandler();
+ }
+
+ // or try to get an OutputStream from Result object
+ final OutputStream ostream = target.getOutputStream();
+ if (ostream != null) {
+ _tohFactory.setOutputStream(ostream);
+ return _tohFactory.getTransletOutputHandler();
+ }
+
+ // or try to get just a systemId string from Result object
+ String systemId = result.getSystemId();
+ if (systemId == null) {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_RESULT_ERR);
+ throw new TransformerException(err.toString());
+ }
+
+ // System Id may be in one of several forms, (1) a uri
+ // that starts with 'file:', (2) uri that starts with 'http:'
+ // or (3) just a filename on the local system.
+ URL url = null;
+ if (systemId.startsWith("file:")) {
+ url = new URL(systemId);
+ _tohFactory.setOutputStream(
+ new FileOutputStream(url.getFile()));
+ return _tohFactory.getTransletOutputHandler();
+ }
+ else if (systemId.startsWith("http:")) {
+ url = new URL(systemId);
+ final URLConnection connection = url.openConnection();
+ _tohFactory.setOutputStream(connection.getOutputStream());
+ return _tohFactory.getTransletOutputHandler();
+ }
+ else {
+ // system id is just a filename
+ url = new File(systemId).toURL();
+ _tohFactory.setOutputStream(
+ new FileOutputStream(url.getFile()));
+ return _tohFactory.getTransletOutputHandler();
+ }
+ }
}
+ // If we cannot write to the location specified by the SystemId
+ catch (UnknownServiceException e) {
+ throw new TransformerException(e);
+ }
+ catch (ParserConfigurationException e) {
+ throw new TransformerException(e);
+ }
+ // If we cannot create the file specified by the SystemId
+ catch (IOException e) {
+ throw new TransformerException(e);
+ }
+ return null;
}
/**
@@ -190,7 +345,7 @@
* based on the type and contents of the TrAX Result object passed to
* the transform() method.
*/
- private ContentHandler getOutputHandler(Result result) throws
+ private ContentHandler getOldOutputHandler(Result result) throws
TransformerException
{
// Try to get the encoding from the translet (may not be set)
@@ -211,7 +366,7 @@
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
@@ -281,80 +436,6 @@
return null;
}
-
-/*************
- private ContentHandler getOutputHandler(Result result)
- throws TransformerException {
- // Try to get the encoding from Translet (may not be set)
- if (_translet._encoding != null) {
- _encoding = _translet._encoding;
- }
- else {
- _encoding = "UTF-8"; // default output encoding
- }
-
- try {
- String systemId = result.getSystemId();
-
- // Handle SAXResult output handler
- if (result instanceof SAXResult) {
- final SAXResult target = (SAXResult)result;
- final ContentHandler handler = target.getHandler();
- // Simple as feck, just pass the SAX handler back...
- if (handler != null) return handler;
- }
- // Handle StreamResult output handler
- else if (result instanceof StreamResult) {
- final StreamResult target = (StreamResult)result;
- final OutputStream ostream = target.getOutputStream();
- final Writer writer = target.getWriter();
-
- if (ostream != null)
- return (new DefaultSAXOutputHandler(ostream, _encoding));
- else if (writer != null)
- return (new DefaultSAXOutputHandler(writer, _encoding));
- else if ((systemId != null) && systemId.startsWith("file:")) {
- final URL url = new URL(systemId);
- final OutputStream os = new FileOutputStream(url.getFile());
- return (new DefaultSAXOutputHandler(os, _encoding));
- }
- }
- // Handle DOMResult output handler
- else if (result instanceof DOMResult) {
- return (new SAX2DOM());
- }
-
- // Common, final handling of all input sources, only used if the
- // other contents of the Result object could not be used
- if (systemId != null) {
- if ((new File(systemId)).exists()) systemId = "file:"+systemId;
- final URL url = new URL(systemId);
- final URLConnection connection = url.openConnection();
- final OutputStream ostream = connection.getOutputStream();
- return(new DefaultSAXOutputHandler(ostream, _encoding));
- }
- else {
- ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_RESULT_ERR);
- throw new TransformerException(err.toString());
- }
- }
- // If we cannot write to the location specified by the SystemId
- catch (UnknownServiceException e) {
- throw new TransformerException(e);
- }
- // If we cannot create a SAX2DOM adapter
- catch (ParserConfigurationException e) {
- ErrorMsg err = new ErrorMsg(ErrorMsg.SAX2DOM_ADAPTER_ERR);
- throw new TransformerException(err.toString());
- }
- // If we cannot create the file specified by the SystemId
- catch (IOException e) {
- throw new TransformerException(e);
- }
- }
-
-**********************/
-
/**
* Set the internal DOMImpl that will be used for the next transformation
*/
@@ -363,18 +444,19 @@
}
/**
+ * Set the internal DOMImpl that will be used for the next transformation
+ */
+ protected void setDTDMonitor(DTDMonitor dtdMonitor) {
+ _dtdMonitor = dtdMonitor;
+ }
+
+ /**
* Builds an internal DOM from a TrAX Source object
*/
private DOMImpl getDOM(Source source, int mask)
- throws TransformerException {
+ throws TransformerException
+ {
try {
- // Use the pre-defined DOM if present
- if (_dom != null) {
- DOMImpl dom = _dom;
- _dom = null; // use only once, so reset to 'null'
- return(dom);
- }
-
DOMImpl dom = null;
DTDMonitor dtd = null;
@@ -382,10 +464,18 @@
if (source instanceof SAXSource) {
// Get all info from the input SAXSource object
final SAXSource sax = (SAXSource)source;
- final XMLReader reader = sax.getXMLReader();
+ XMLReader reader = sax.getXMLReader();
final InputSource input = sax.getInputSource();
final String systemId = sax.getSystemId();
+ // if reader was not set with setXMLReader by user,
+ // then we must create one ourselves.
+ if (reader == null) {
+ SAXParserFactory pfactory= SAXParserFactory.newInstance();
+ pfactory.setNamespaceAware(true);
+ reader = pfactory.newSAXParser().getXMLReader();
+ }
+
// Create a DTD monitor to trap all DTD/declarative events
dtd = new DTDMonitor();
dtd.handleDTD(reader);
@@ -409,8 +499,14 @@
// 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 +521,13 @@
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
@@ -465,13 +567,15 @@
reader.setContentHandler(builder);
InputSource input;
- if (streamInput != null)
+ if (streamInput != null) {
input = new InputSource(streamInput);
- else if (streamReader != null)
+ input.setSystemId(systemId);
+ } else if (streamReader != null) {
input = new InputSource(streamReader);
- else if (systemId != null)
+ input.setSystemId(systemId);
+ } else if (systemId != null) {
input = new InputSource(systemId);
- else {
+ } else {
ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_NO_SOURCE_ERR);
throw new TransformerException(err.toString());
}
@@ -486,6 +590,11 @@
dtd = xsltcsrc.getDTD();
dom = xsltcsrc.getDOM();
}
+ // DOM already set via a call to setDOM()
+ else if (_dom != null) {
+ dtd = _dtdMonitor; // must be set via setDTDMonitor()
+ dom = _dom; _dom = null; // use only once, so reset to 'null'
+ }
else {
return null;
}
@@ -519,23 +628,45 @@
/**
* Internal transformation method - uses the internal APIs of XSLTC
*/
+ private void transform(Source src, TransletOutputHandler handler,
+ String encoding) throws TransformerException
+ {
+ try {
+ _translet.transform(getDOM(src, 0), handler);
+ }
+ catch (TransletException e) {
+ if (_errorListener != null) postErrorToListener(e.getMessage());
+ throw new TransformerException(e);
+ }
+ catch (RuntimeException e) {
+ if (_errorListener != null) postErrorToListener(e.getMessage());
+ throw new TransformerException(e);
+ }
+ catch (Exception e) {
+ if (_errorListener != null) postErrorToListener(e.getMessage());
+ throw new TransformerException(e);
+ }
+ }
+
+ /**
+ * Internal transformation method - uses the internal APIs of XSLTC
+ */
private void transform(Source src, ContentHandler sax, String encoding)
throws TransformerException {
try {
// Build an iternal DOMImpl from the TrAX Source
DOMImpl dom = getDOM(src, 0);
- // Pass output properties to the translet
- setOutputProperties(_translet, _properties);
-
// This handler will post-process the translet output
TextOutput handler;
// Check if the ContentHandler also implements LexicalHandler
- if (sax instanceof LexicalHandler)
+ if (sax instanceof LexicalHandler) {
handler = new TextOutput(sax, (LexicalHandler)sax, encoding);
- else
+ }
+ else {
handler = new TextOutput(sax, encoding);
+ }
_translet.transform(dom, handler);
}
catch (TransletException e) {
@@ -640,7 +771,7 @@
* @return Properties in effect for this Transformer
*/
public Properties getOutputProperties() {
- return(_properties);
+ return (Properties) _properties.clone();
}
/**
@@ -653,12 +784,13 @@
* @throws IllegalArgumentException if the property name is not known
*/
public String getOutputProperty(String name)
- throws IllegalArgumentException {
+ throws IllegalArgumentException
+ {
if (!validOutputProperty(name)) {
ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
throw new IllegalArgumentException(err.toString());
}
- return(_properties.getProperty(name));
+ return _properties.getProperty(name);
}
/**
@@ -671,8 +803,29 @@
* @throws IllegalArgumentException Never, errors are ignored
*/
public void setOutputProperties(Properties properties)
- throws IllegalArgumentException {
- _properties.putAll(properties);
+ throws IllegalArgumentException
+ {
+ if (properties != null) {
+ final Enumeration names = properties.propertyNames();
+
+ while (names.hasMoreElements()) {
+ final String name = (String) names.nextElement();
+
+ // Ignore lower layer properties
+ if (isDefaultProperty(name, properties)) continue;
+
+ if (validOutputProperty(name)) {
+ _properties.setProperty(name, properties.getProperty(name));
+ }
+ else {
+ ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
+ throw new IllegalArgumentException(err.toString());
+ }
+ }
+ }
+ else {
+ _properties = _propertiesClone;
+ }
}
/**
@@ -686,7 +839,8 @@
* @throws IllegalArgumentException Never, errors are ignored
*/
public void setOutputProperty(String name, String value)
- throws IllegalArgumentException {
+ throws IllegalArgumentException
+ {
if (!validOutputProperty(name)) {
ErrorMsg err = new ErrorMsg(ErrorMsg.JAXP_UNKNOWN_PROP_ERR, name);
throw new IllegalArgumentException(err.toString());
@@ -699,43 +853,50 @@
* initiating the transformation
*/
private void setOutputProperties(AbstractTranslet translet,
- Properties properties) {
+ Properties properties)
+ {
// Return right now if no properties are set
if (properties == null) return;
// Get a list of all the defined properties
Enumeration names = properties.propertyNames();
while (names.hasMoreElements()) {
- // Get the next property name and value
- String name = (String)names.nextElement();
- String value = (String)properties.get(name);
+ // Note the use of get() instead of getProperty()
+ String name = (String) names.nextElement();
+ String value = (String) properties.get(name);
+
+ // Ignore default properties
+ if (value == null) continue;
// Pass property value to translet - override previous setting
- if (name.equals(OutputKeys.ENCODING))
+ if (name.equals(OutputKeys.ENCODING)) {
translet._encoding = value;
- else if (name.equals(OutputKeys.METHOD))
+ }
+ else if (name.equals(OutputKeys.METHOD)) {
translet._method = value;
- else if (name.equals(OutputKeys.DOCTYPE_PUBLIC))
+ }
+ else if (name.equals(OutputKeys.DOCTYPE_PUBLIC)) {
translet._doctypePublic = value;
- else if (name.equals(OutputKeys.DOCTYPE_SYSTEM))
+ }
+ else if (name.equals(OutputKeys.DOCTYPE_SYSTEM)) {
translet._doctypeSystem = value;
- else if (name.equals(OutputKeys.MEDIA_TYPE))
+ }
+ else if (name.equals(OutputKeys.MEDIA_TYPE)) {
translet._mediaType = value;
- else if (name.equals(OutputKeys.STANDALONE))
+ }
+ else if (name.equals(OutputKeys.STANDALONE)) {
translet._standalone = value;
- else if (name.equals(OutputKeys.VERSION))
+ }
+ else if (name.equals(OutputKeys.VERSION)) {
translet._version = value;
+ }
else if (name.equals(OutputKeys.OMIT_XML_DECLARATION)) {
- if ((value != null) && (value.toLowerCase().equals("yes")))
- translet._omitHeader = true;
- else
- translet._omitHeader = false;
+ translet._omitHeader =
+ (value != null && value.toLowerCase().equals("yes"));
}
else if (name.equals(OutputKeys.INDENT)) {
- if ((value != null) && (value.toLowerCase().equals("yes")))
- translet._indent = true;
- else
- translet._indent = false;
+ translet._indent =
+ (value != null && value.toLowerCase().equals("yes"));
}
else if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) {
if (value != null) {
@@ -750,68 +911,45 @@
}
/**
- * Internal method to pass any properties to the translet prior to
- * initiating the transformation
+ * Internal method to create the initial set of properties. There
+ * are two layers of properties: the default layer and the base layer.
+ * The latter contains properties defined in the stylesheet or by
+ * the user using this API.
*/
- private Properties createOutputProperties() {
-
- // Level3: Return the default property value
- 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);
- third.setProperty(OutputKeys.VERSION, "1.0");
+ private Properties createOutputProperties(Properties outputProperties) {
+ final Properties defaults = new Properties();
+ defaults.setProperty(OutputKeys.ENCODING, "UTF-8");
+ defaults.setProperty(OutputKeys.METHOD, XML_STRING);
+ defaults.setProperty(OutputKeys.INDENT, NO_STRING);
+ defaults.setProperty(OutputKeys.MEDIA_TYPE, "text/xml");
+ defaults.setProperty(OutputKeys.OMIT_XML_DECLARATION, NO_STRING);
+ defaults.setProperty(OutputKeys.STANDALONE, NO_STRING);
+ defaults.setProperty(OutputKeys.VERSION, "1.0");
- // Level2: Return the property value is set in the translet
- // Creating these properties with the third-level properties as default
- Properties second = new Properties(third);
- if (_translet != null) {
- String value = _translet._encoding;
- if (value != null) second.setProperty(OutputKeys.ENCODING, value);
-
- value = _translet._method;
- if (value != null) second.setProperty(OutputKeys.METHOD, value);
-
- if (_translet._indent)
- second.setProperty(OutputKeys.INDENT, "yes");
- else
- second.setProperty(OutputKeys.INDENT, "no");
-
- value = _translet._doctypePublic;
- if (value != null)
- second.setProperty(OutputKeys.DOCTYPE_PUBLIC, value);
-
- value = _translet._doctypeSystem;
- if (value != null)
- second.setProperty(OutputKeys.DOCTYPE_SYSTEM, value);
-
- value = makeCDATAString(_translet._cdata);
- if (value != null)
- second.setProperty(OutputKeys.CDATA_SECTION_ELEMENTS,value);
-
- value = _translet._mediaType;
- if (value != null) second.setProperty(OutputKeys.MEDIA_TYPE, value);
-
- if (_translet._omitHeader)
- second.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
- else
- second.setProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
-
- value = _translet._standalone;
- if (value != null) second.setProperty(OutputKeys.STANDALONE, value);
-
- value = _translet._version;
- if (value != null) second.setProperty(OutputKeys.VERSION, value);
+ // Copy propeties set in stylesheet to base
+ final Properties base = new Properties(defaults);
+ if (outputProperties != null) {
+ final Enumeration names = outputProperties.propertyNames();
+ while (names.hasMoreElements()) {
+ final String name = (String) names.nextElement();
+ base.setProperty(name, outputProperties.getProperty(name));
+ }
}
- // Creating the properties with the second-level properties as default
- return(new Properties(second));
+ // Update defaults based on output method
+ final String method = base.getProperty(OutputKeys.METHOD);
+ if (method != null) {
+ if (method.equals("html")) {
+ defaults.setProperty(OutputKeys.INDENT, "yes");
+ defaults.setProperty(OutputKeys.VERSION, "4.0");
+ defaults.setProperty(OutputKeys.MEDIA_TYPE, "text/html");
+ }
+ else if (method.equals("text")) {
+ defaults.setProperty(OutputKeys.MEDIA_TYPE, "text/plain");
+ }
+ }
+
+ return base;
}
/**
@@ -819,18 +957,24 @@
* the JAXP 1.1 / TrAX spec
*/
private boolean validOutputProperty(String name) {
- if (name.equals(OutputKeys.ENCODING)) return true;
- if (name.equals(OutputKeys.METHOD)) return true;
- if (name.equals(OutputKeys.INDENT)) return true;
- if (name.equals(OutputKeys.DOCTYPE_PUBLIC)) return true;
- if (name.equals(OutputKeys.DOCTYPE_SYSTEM)) return true;
- if (name.equals(OutputKeys.CDATA_SECTION_ELEMENTS)) return true;
- if (name.equals(OutputKeys.MEDIA_TYPE)) return true;
- if (name.equals(OutputKeys.OMIT_XML_DECLARATION)) return true;
- if (name.equals(OutputKeys.STANDALONE)) return true;
- if (name.equals(OutputKeys.VERSION)) return true;
- if (name.charAt(0) == '{') return true;
- return false;
+ return (name.equals(OutputKeys.ENCODING) ||
+ name.equals(OutputKeys.METHOD) ||
+ name.equals(OutputKeys.INDENT) ||
+ name.equals(OutputKeys.DOCTYPE_PUBLIC) ||
+ name.equals(OutputKeys.DOCTYPE_SYSTEM) ||
+ name.equals(OutputKeys.CDATA_SECTION_ELEMENTS) ||
+ name.equals(OutputKeys.MEDIA_TYPE) ||
+ name.equals(OutputKeys.OMIT_XML_DECLARATION) ||
+ name.equals(OutputKeys.STANDALONE) ||
+ name.equals(OutputKeys.VERSION) ||
+ name.charAt(0) == '{');
+ }
+
+ /**
+ * Checks if a given output property is default (2nd layer only)
+ */
+ private boolean isDefaultProperty(String name, Properties properties) {
+ return (properties.get(name) == null);
}
/**
@@ -924,8 +1068,9 @@
* the transformation (always does in our case).
*/
public void error(TransformerException e)
- throws TransformerException {
- System.err.println("ERROR: "+e.getMessageAndLocation());
+ throws TransformerException
+ {
+ System.err.println("ERROR: " + e.getMessageAndLocation());
throw(e);
}
@@ -943,11 +1088,13 @@
* the transformation (always does in our case).
*/
public void fatalError(TransformerException e)
- throws TransformerException {
- System.err.println("FATAL: "+e.getMessageAndLocation());
+ throws TransformerException
+ {
+ System.err.println("FATAL: " + e.getMessageAndLocation());
Throwable wrapped = e.getException();
- if (wrapped != null)
+ if (wrapped != null) {
System.err.println(" : "+wrapped.getMessage());
+ }
throw(e);
}
@@ -965,11 +1112,13 @@
* the transformation (never does in our case).
*/
public void warning(TransformerException e)
- throws TransformerException {
- System.err.println("WARNING: "+e.getMessageAndLocation());
+ throws TransformerException
+ {
+ System.err.println("WARNING: " + e.getMessageAndLocation());
Throwable wrapped = e.getException();
- if (wrapped != null)
+ if (wrapped != null) {
System.err.println(" : "+wrapped.getMessage());
+ }
}
}
diff --git a/src/org/apache/xalan/xsltc/util/IntegerArray.java b/src/org/apache/xalan/xsltc/util/IntegerArray.java
index c3a2297..f416018 100644
--- a/src/org/apache/xalan/xsltc/util/IntegerArray.java
+++ b/src/org/apache/xalan/xsltc/util/IntegerArray.java
@@ -87,7 +87,9 @@
}
public Object clone() {
- return new IntegerArray(_array);
+ final IntegerArray clone = new IntegerArray(_array);
+ clone._free = _free;
+ return clone;
}
public int[] toIntArray() {
@@ -105,23 +107,24 @@
}
public int indexOf(int n) {
- for (int i = 0; i < _free; i++)
- if (n == _array[i])
- return i;
+ for (int i = 0; i < _free; i++) {
+ if (n == _array[i]) return i;
+ }
return -1;
}
public final void add(int value) {
- if (_free == _size)
+ if (_free == _size) {
growArray(_size * 2);
+ }
_array[_free++] = value;
}
/** adds new int at the end if not already present */
public void addNew(int value) {
- for (int i = 0; i < _free; i++)
- if (_array[i] == value) // already in array
- return;
+ for (int i = 0; i < _free; i++) {
+ if (_array[i] == value) return; // already in array
+ }
add(value);
}
@@ -163,7 +166,8 @@
}
out.println(_array[_free - 1]);
}
- else
+ else {
out.println("IntegerArray: empty");
+ }
}
}
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