You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by tm...@apache.org on 2002/05/21 00:15:33 UTC
cvs commit: xml-xalan/java/src/org/apache/xalan/xsltc/runtime/output SAXHTMLOutput.java SAXOutput.java SAXXMLOutput.java
tmiller 02/05/20 15:15:33
Modified: java/src/org/apache/xalan/xsltc/runtime/output
SAXHTMLOutput.java SAXOutput.java SAXXMLOutput.java
Log:
updated new code, on-going development
Revision Changes Path
1.2 +100 -42 xml-xalan/java/src/org/apache/xalan/xsltc/runtime/output/SAXHTMLOutput.java
Index: SAXHTMLOutput.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/runtime/output/SAXHTMLOutput.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SAXHTMLOutput.java 17 May 2002 16:52:56 -0000 1.1
+++ SAXHTMLOutput.java 20 May 2002 22:15:33 -0000 1.2
@@ -1,5 +1,5 @@
/*
- * @(#)$Id: SAXHTMLOutput.java,v 1.1 2002/05/17 16:52:56 tmiller Exp $
+ * @(#)$Id: SAXHTMLOutput.java,v 1.2 2002/05/20 22:15:33 tmiller Exp $
*
* The Apache Software License, Version 1.1
*
@@ -68,28 +68,30 @@
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 {
- private boolean _headTagOpen = false;
+ private boolean _headTagOpen = false;
+ private String _mediaType = "text/html";
- public SAXHTMLOutput(ContentHandler handler, String encoding) {
+ public SAXHTMLOutput(ContentHandler handler, String encoding) {
super(handler, encoding);
- }
+ }
- public SAXHTMLOutput(ContentHandler handler, LexicalHandler lex,
+ public SAXHTMLOutput(ContentHandler handler, LexicalHandler lex,
String encoding)
- {
+ {
super(handler, lex, encoding);
- }
+ }
- public void startElement(String elementName) throws TransletException {
- }
+ public void startElement(String elementName) throws TransletException {
+ }
- public void attribute(String name, final String value)
+ public void attribute(String name, final String value)
throws TransletException
- {
+ {
final String patchedName = patchQName(name);
final String localName = getLocalName(patchedName);
final int index = _attributes.getIndex(name);
@@ -97,42 +99,98 @@
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") || tmp.equals("src") ||
- tmp.equals("cite"))
- {
- /************
- if (index >= 0) {
- _attributes.setAttribute(index, EMPTYSTRING, EMPTYSTRING,
- name, "CDATA", quickAndDirtyUrlEncode(escapeAttr(value)));
- }
- else {
- _attributes.addAttribute(EMPTYSTRING, EMPTYSTRING, name,
- "CDATA", quickAndDirtyUrlEncode(escapeAttr(value)));
- }
- **************/
+ if (index >= 0) {
+ _attributes.setAttribute(index, EMPTYSTRING, EMPTYSTRING,
+ name, "CDATA", value);
}
else {
- if (index >= 0) {
- _attributes.setAttribute(index, EMPTYSTRING, EMPTYSTRING,
- name, "CDATA", value);
- }
- else {
- _attributes.addAttribute(EMPTYSTRING, EMPTYSTRING,
- name, "CDATA", value);
+ _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.
+ */
+ public void closeStartTag() throws TransletException {
+ try {
+ _startTagOpen = false;
+
+ // Now is time to send the startElement event
+ _saxHandler.startElement(null, _elementName, _elementName,
+ _attributes);
+
+ // Insert <META> tag directly after <HEAD> element in HTML output
+ if (_headTagOpen) {
+ emitHeader();
+ _headTagOpen = false;
}
}
- }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+
+ /**
+ * Emit header through the SAX handler
+ */
+ private void emitHeader() throws SAXException {
+ AttributeList attrs = new AttributeList();
+ attrs.add("http-equiv", "Content-Type");
+ attrs.add("content", _mediaType+"; charset="+_encoding);
+ _saxHandler.startElement(EMPTYSTRING, EMPTYSTRING, "meta", attrs);
+ _saxHandler.endElement(EMPTYSTRING, EMPTYSTRING, "meta");
+ }
+ /**
+ * 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,
+ (String)(_qnameStack.pop()));
+ } catch (SAXException e) {
+ throw new TransletException(e);
+ }
+
+ }
+ private void initNamespaces() {
+ //empty
+ }
+
+ private String lookupNamespace(String prefix) {
+ return null; // no-op
+ }
+
+ private void popNamespace(String prefix) throws SAXException {
+ //empty
+ }
+
+ private String getNamespaceURI(String qname, boolean isElement)
+ throws TransletException
+ {
+ return null; // no-op
+ }
}
1.2 +49 -49 xml-xalan/java/src/org/apache/xalan/xsltc/runtime/output/SAXOutput.java
Index: SAXOutput.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/runtime/output/SAXOutput.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SAXOutput.java 17 May 2002 16:52:56 -0000 1.1
+++ SAXOutput.java 20 May 2002 22:15:33 -0000 1.2
@@ -1,5 +1,5 @@
/*
- * @(#)$Id: SAXOutput.java,v 1.1 2002/05/17 16:52:56 tmiller Exp $
+ * @(#)$Id: SAXOutput.java,v 1.2 2002/05/20 22:15:33 tmiller Exp $
*
* The Apache Software License, Version 1.1
*
@@ -63,6 +63,7 @@
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;
@@ -72,82 +73,79 @@
import org.apache.xalan.xsltc.runtime.DefaultSAXOutputHandler;
public class SAXOutput extends OutputBase implements Constants {
- protected ContentHandler _saxHandler;
- protected LexicalHandler _lexicalHandler;
- protected boolean _startTagOpen = false;
- protected String _encoding = null;
- protected AttributesImpl _attributes = new AttributesImpl();
+ protected ContentHandler _saxHandler;
+ protected LexicalHandler _lexHandler;
+ protected boolean _startTagOpen = false;
+ protected AttributesImpl _attributes = new AttributesImpl();
+ protected String _elementName = null;
+
+ // parameters set by <xsl:output> element, or by set/getOutputProperty()
+ protected String _encoding = null;
+ protected String _doctypeSystem = null;
+ protected String _doctypePublic = null;
+
+ // The top of this stack contains the QName of the currently open element
+ protected Stack _qnameStack;
- public SAXOutput(ContentHandler handler, String encoding) {
+ public SAXOutput(ContentHandler handler, String encoding) {
_saxHandler = handler;
_encoding = encoding;
- }
+ }
- public SAXOutput(ContentHandler hdler, LexicalHandler lex, String encoding){
+ public SAXOutput(ContentHandler hdler, LexicalHandler lex, String encoding){
_saxHandler = hdler;
- _lexicalHandler = lex;
+ _lexHandler = lex;
_encoding = encoding;
- }
+ }
- public void startDocument() throws TransletException {
+ public void startDocument() throws TransletException {
try {
_saxHandler.startDocument();
} catch (SAXException e) {
throw new TransletException(e);
}
- }
+ }
- public void endDocument() throws TransletException {
+ public void endDocument() throws TransletException {
try {
_saxHandler.endDocument();
} catch (SAXException e) {
throw new TransletException(e);
}
- }
-
- // ContentHandler: startElement(String namespace, String lname,
- // String qname, Attributes)
- public void startElement(String elementName) throws TransletException {
- try {
- _saxHandler.startElement(EMPTYSTRING, EMPTYSTRING,
- elementName, _attributes);
- } catch (SAXException e) {
- throw new TransletException(e);
- }
- }
+ }
- // ContentHandler: endElement(String namespace, String lname, String qname)
- public void endElement(String elementName) throws TransletException {
- try {
- _saxHandler.endElement(EMPTYSTRING, EMPTYSTRING, elementName);
- } catch (SAXException e) {
- throw new TransletException(e);
- }
- }
- public void characters(String characters)
+ public void characters(String characters)
throws TransletException
- {
+ {
try {
_saxHandler.characters(characters.toCharArray(), 0,
characters.length());
} catch (SAXException e) {
throw new TransletException(e);
}
- }
+ }
+
+ /**
+ * Set the output document system/public identifiers
+ */
+ public void setDoctype(String system, String pub) {
+ _doctypeSystem = system;
+ _doctypePublic = pub;
+ }
+
- public void characters(char[] characters, int offset, int length)
- throws TransletException
- {
- try {
- _saxHandler.characters(characters, offset, length);
- } catch (SAXException e) {
- throw new TransletException(e);
- }
- }
- protected static String patchQName(String qname) throws TransletException {
+ /**
+ * 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 patchQName(String qname) throws TransletException {
final int lastColon = qname.lastIndexOf(':');
if (lastColon > 0) {
final int firstColon = qname.indexOf(':');
@@ -159,12 +157,14 @@
return qname;
}
+ /**
+ * returns the local name of a qualified name. If the name has no prefix
+ * then return null.
+ */
protected static String getLocalName(String qname) throws
TransletException
{
final int col = qname.lastIndexOf(':');
return (col > 0) ? qname.substring(col + 1) : null;
}
-
-
}
1.2 +328 -7 xml-xalan/java/src/org/apache/xalan/xsltc/runtime/output/SAXXMLOutput.java
Index: SAXXMLOutput.java
===================================================================
RCS file: /home/cvs/xml-xalan/java/src/org/apache/xalan/xsltc/runtime/output/SAXXMLOutput.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- SAXXMLOutput.java 17 May 2002 16:52:56 -0000 1.1
+++ SAXXMLOutput.java 20 May 2002 22:15:33 -0000 1.2
@@ -1,5 +1,5 @@
/*
- * @(#)$Id: SAXXMLOutput.java,v 1.1 2002/05/17 16:52:56 tmiller Exp $
+ * @(#)$Id: SAXXMLOutput.java,v 1.2 2002/05/20 22:15:33 tmiller Exp $
*
* The Apache Software License, Version 1.1
*
@@ -63,20 +63,341 @@
package org.apache.xalan.xsltc.runtime.output;
+import java.util.Stack;
+
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;
+import org.apache.xalan.xsltc.runtime.DefaultSAXOutputHandler;
public class SAXXMLOutput extends SAXOutput {
- public SAXXMLOutput(ContentHandler handler, String encoding) {
- super(handler, encoding);
- }
+ // Each entry (prefix) in this hashtable points to a Stack of URIs
+ private 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
+ private Stack _nodeStack;
+ // The top of this stack is the prefix that was last mapped to an URI
+ private Stack _prefixStack;
+
+
+ // Contains all elements that should be output as CDATA sections
+ private Hashtable _cdata = null;
+
+ private boolean _cdataTagOpen = false;
+ // The top of this stack contains the element id of the last element whose
+ // contents should be output as CDATA sections.
+ private Stack _cdataStack;
+
+ // Holds the current tree depth (see startElement() and endElement()).
+ private int _depth = 0;
+
+ // The top of this stack contains the QName of the currently open element
+ private Stack _qnameStack;
- public SAXXMLOutput(ContentHandler handler, LexicalHandler lex,
+ 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) {
+ super(handler, encoding);
+ }
+
+ public SAXXMLOutput(ContentHandler handler, LexicalHandler lex,
String encoding)
- {
+ {
super(handler, lex, encoding);
- }
+ }
+
+ public void endDocument() throws TransletException {
+ try {
+ // Close any open start tag
+ if (_startTagOpen) closeStartTag();
+ if (_cdataTagOpen) closeCDATA();
+
+ // Close output document
+ _saxHandler.endDocument();
+ } 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.
+ */
+ public void closeStartTag() throws TransletException {
+ try {
+ _startTagOpen = false;
+
+ // Now is time to send the startElement event
+ _saxHandler.startElement(getNamespaceURI(_elementName, true),
+ getLocalName(_elementName), _elementName, _attributes);
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ /**
+ * 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,
+ qname.substring(0, col));
+ }
+ }
+ return uri;
+ }
+
+ /**
+ * Use a namespace prefix to lookup a namespace URI
+ */
+ private String lookupNamespace(String prefix) {
+ final Stack stack = (Stack)_namespaces.get(prefix);
+ return stack != null && !stack.isEmpty() ? (String)stack.peek() : null;
+ }
+
+
+ private void closeCDATA() throws SAXException {
+ // Output closing bracket - "]]>"
+ _saxHandler.characters(ENDCDATA, 0, ENDCDATA.length);
+ _cdataTagOpen = false;
+ }
+
+ /**
+ * 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 = 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);
+ 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 {
+ 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
+ {
+ try {
+ // Close any open start tag
+ if (_startTagOpen) closeStartTag();
+
+ // Take special precautions if within a CDATA section. If we
+ // encounter the sequence ']]>' within the CDATA, we need to
+ // break the section in two and leave the ']]' at the end of
+ // 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)) {
+ startCDATA(ch, off, len);
+ }
+ else {
+ _saxHandler.characters(ch, off, len);
+ }
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ public void endElement(String elementName) throws TransletException {
+ try {
+ // Close any open element
+ if (_startTagOpen) closeStartTag();
+ if (_cdataTagOpen) closeCDATA();
+
+ final String qname = (String) _qnameStack.pop();
+ _saxHandler.endElement(getNamespaceURI(qname, true),
+ getLocalName(qname), qname);
+
+ popNamespaces();
+ if (((Integer)_cdataStack.peek()).intValue() == _depth){
+ _cdataStack.pop();
+ }
+ _depth--;
+
+ } catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ /**
+ * The <xsl:output method="xml"/> instruction can specify that certain
+ * XML elements should be output as CDATA sections. This methods allows
+ * the translet to insert these elements into a hashtable of strings.
+ * Every output element is looked up in this hashtable before it is
+ * output.
+ */
+ public void setCdataElements(Hashtable elements) {
+ _cdata = elements;
+ }
+
+ /**
+ * Set the XML output document version - should be 1.0
+ */
+ public void setVersion(String version) {
+ if (_saxHandler instanceof DefaultSAXOutputHandler) {
+ ((DefaultSAXOutputHandler)_saxHandler).setVersion(version);
+ }
+ }
+
+ /**
+ * 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();
+ if (_cdataTagOpen) closeCDATA();
+
+ // Handle document type declaration (for first element only)
+ if (_lexHandler != null) {
+ if (_doctypeSystem != null) {
+ _lexHandler.startDTD(elementName,
+ _doctypePublic,_doctypeSystem);
+ }
+ _lexHandler = null;
+ }
+
+ _depth++;
+ _elementName = elementName;
+ _attributes.clear();
+ _startTagOpen = true;
+ _qnameStack.push(elementName);
+
+ if ((_cdata != null) && (_cdata.get(elementName) != null)) {
+ _cdataStack.push(new Integer(_depth));
+ }
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+ /**
+ * Initialize namespace stacks
+ */
+ private void initNamespaces() {
+ _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;
+ }
+
+ /**
+ * Pop all namespace definitions that were delcared by the current element
+ */
+ private void popNamespaces() throws TransletException {
+ try {
+ while (true) {
+ if (_nodeStack.isEmpty()) return;
+ Integer i = (Integer)(_nodeStack.peek());
+ if (i.intValue() != _depth) return;
+ _nodeStack.pop();
+ popNamespace((String)_prefixStack.pop());
+ }
+ }
+ catch (SAXException e) {
+ throw new TransletException(e);
+ }
+ }
+
+
+ /**
+ * 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;
+ if ((stack = (Stack)_namespaces.get(prefix)) != null) {
+ stack.pop();
+ _saxHandler.endPrefixMapping(prefix);
+ }
+ }
+
+
+
+
+ /**
+ * 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=i+2; // Skip next chars ']' and '>'.
+ }
+ }
+
+ // Output the remaining characters
+ if (offset < limit) _saxHandler.characters(ch, offset, limit - offset);
+
+ _cdataTagOpen = true;
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: xalan-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: xalan-cvs-help@xml.apache.org