From: Wolfgang M. M. <wol...@us...> - 2004-09-12 09:26:02
|
Update of /cvsroot/exist/eXist-1.0/src/org/exist/util/serializer In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21081/src/org/exist/util/serializer Modified Files: SAXSerializer.java XMLIndenter.java DOMSerializer.java XMLWriter.java Added Files: AttrList.java Receiver.java ReceiverToSAX.java Log Message: * Added support for XQuery pragmas to set serialization and watchdog settings. * org.exist.storage.serializers.Serializer now passes all output to an instance of the Receiver interface instead of a SAX ContentHandler. Receiver resembles SAX, but has methods that are closer to eXist's internal storage. For example, it directly accepts a QName in startElement to avoid unnecessary string allocations. * Fixed various performance leaks in cross-document joins. --- NEW FILE: ReceiverToSAX.java --- /* * eXist Open Source Native XML Database * Copyright (C) 2001-04 Wolfgang M. Meier (wol...@ex...) * and others (see http://exist-db.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: ReceiverToSAX.java,v 1.1 2004/09/12 09:25:16 wolfgang_m Exp $ */ package org.exist.util.serializer; import org.exist.dom.QName; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.ext.LexicalHandler; import org.xml.sax.helpers.AttributesImpl; /** * A wrapper class that forwards the method calls defined in the * {@link org.exist.util.serializer.Receiver} interface to a * SAX content handler and lexical handler. * * @author wolf */ public class ReceiverToSAX implements Receiver { private ContentHandler contentHandler; private LexicalHandler lexicalHandler = null; /** * */ public ReceiverToSAX(ContentHandler handler) { super(); this.contentHandler = handler; } public void setLexicalHandler(LexicalHandler handler) { this.lexicalHandler = handler; } /* (non-Javadoc) * @see org.exist.util.serializer.Receiver#startDocument() */ public void startDocument() throws SAXException { contentHandler.startDocument(); } /* (non-Javadoc) * @see org.exist.util.serializer.Receiver#endDocument() */ public void endDocument() throws SAXException { contentHandler.endDocument(); } /* (non-Javadoc) * @see org.exist.util.serializer.Receiver#startPrefixMapping(java.lang.String, java.lang.String) */ public void startPrefixMapping(String prefix, String namespaceURI) throws SAXException { contentHandler.startPrefixMapping(prefix, namespaceURI); } /* (non-Javadoc) * @see org.exist.util.serializer.Receiver#endPrefixMapping(java.lang.String) */ public void endPrefixMapping(String prefix) throws SAXException { contentHandler.endPrefixMapping(prefix); } /* (non-Javadoc) * @see org.exist.util.serializer.Receiver#startElement(org.exist.dom.QName, org.exist.util.serializer.AttrList) */ public void startElement(QName qname, AttrList attribs) throws SAXException { AttributesImpl a = new AttributesImpl(); if(attribs != null) { QName attrQName; for(int i = 0; i < attribs.getLength(); i++) { attrQName = attribs.getQName(i); a.addAttribute(attrQName.getNamespaceURI(), attrQName.getLocalName(), attrQName.toString(), "CDATA", attribs.getValue(i)); } } contentHandler.startElement(qname.getNamespaceURI(), qname.getLocalName(), qname.toString(), a); } /* (non-Javadoc) * @see org.exist.util.serializer.Receiver#endElement(org.exist.dom.QName) */ public void endElement(QName qname) throws SAXException { contentHandler.endElement(qname.getNamespaceURI(), qname.getLocalName(), qname.toString()); } /* (non-Javadoc) * @see org.exist.util.serializer.Receiver#characters(java.lang.CharSequence) */ public void characters(CharSequence seq) throws SAXException { contentHandler.characters(seq.toString().toCharArray(), 0, seq.length()); } /* (non-Javadoc) * @see org.exist.util.serializer.Receiver#attribute(org.exist.dom.QName, java.lang.String) */ public void attribute(QName qname, String value) throws SAXException { } /* (non-Javadoc) * @see org.exist.util.serializer.Receiver#comment(char[], int, int) */ public void comment(char[] ch, int start, int length) throws SAXException { if(lexicalHandler != null) lexicalHandler.comment(ch, start, length); } /* (non-Javadoc) * @see org.exist.util.serializer.Receiver#processingInstruction(java.lang.String, java.lang.String) */ public void processingInstruction(String target, String data) throws SAXException { contentHandler.processingInstruction(target, data); } } --- NEW FILE: AttrList.java --- /* * eXist Open Source Native XML Database * Copyright (C) 2001-04 Wolfgang M. Meier (wol...@ex...) * and others (see http://exist-db.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: AttrList.java,v 1.1 2004/09/12 09:25:16 wolfgang_m Exp $ */ package org.exist.util.serializer; import org.exist.dom.QName; /** * Represents a list of attributes. Each attribute is defined by * a {@link org.exist.dom.QName} and a value. Instances * of this class can be passed to * {@link org.exist.util.serializer.Receiver#startElement(QName, AttrList)}. * * @author wolf */ public class AttrList { protected QName names[] = new QName[4]; protected String values[] = new String[4]; protected int size = 0; /** * */ public AttrList() { super(); } public void addAttribute(QName name, String value) { ensureCapacity(); names[size] = name; values[size] = value; size++; } public int getLength() { return size; } public QName getQName(int pos) { return names[pos]; } public String getValue(int pos) { return values[pos]; } public String getValue(QName name) { for(int i = 0; i < size; i++) { if(names[i].equals(name)) return values[i]; } return null; } private void ensureCapacity() { if(size == names.length) { // resize final int newSize = names.length * 3 / 2; QName tnames[] = new QName[newSize]; System.arraycopy(names, 0, tnames, 0, names.length); String tvalues[] = new String[newSize]; System.arraycopy(values, 0, tvalues, 0, values.length); names = tnames; values = tvalues; } } } Index: XMLWriter.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/util/serializer/XMLWriter.java,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** XMLWriter.java 12 Aug 2004 15:48:42 -0000 1.9 --- XMLWriter.java 12 Sep 2004 09:25:16 -0000 1.10 *************** *** 24,32 **** import java.util.Arrays; import java.util.Properties; - import java.util.Stack; import javax.xml.transform.OutputKeys; import javax.xml.transform.TransformerException; import org.exist.util.XMLString; import org.exist.util.serializer.encodings.CharacterSet; --- 24,32 ---- import java.util.Arrays; import java.util.Properties; import javax.xml.transform.OutputKeys; import javax.xml.transform.TransformerException; + import org.exist.dom.QName; import org.exist.util.XMLString; import org.exist.util.serializer.encodings.CharacterSet; *************** *** 47,51 **** protected Writer writer = null; protected CharacterSet charSet = null; - protected Stack elementStack = new Stack(); protected boolean tagIsOpen = false; protected boolean tagIsEmpty = true; --- 47,50 ---- *************** *** 112,116 **** tagIsEmpty = true; declarationWritten = false; - elementStack.clear(); } --- 111,114 ---- *************** *** 119,123 **** tagIsEmpty = true; declarationWritten = false; - elementStack.clear(); } --- 117,120 ---- *************** *** 134,138 **** writer.write(qname); tagIsOpen = true; - elementStack.push(qname); } catch (IOException e) { throw new TransformerException(e.getMessage(), e); --- 131,134 ---- *************** *** 140,146 **** } ! public void endElement() throws TransformerException { try { - String qname = (String) elementStack.pop(); if (tagIsOpen) closeStartTag(true); --- 136,159 ---- } ! public void startElement(QName qname) throws TransformerException { ! if (!declarationWritten) ! writeDeclaration(); ! try { ! if (tagIsOpen) ! closeStartTag(false); ! writer.write('<'); ! if(qname.getPrefix() != null && qname.getPrefix().length() > 0) { ! writer.write(qname.getPrefix()); ! writer.write(':'); ! } ! writer.write(qname.getLocalName()); ! tagIsOpen = true; ! } catch (IOException e) { ! throw new TransformerException(e.getMessage(), e); ! } ! } ! ! public void endElement(String qname) throws TransformerException { try { if (tagIsOpen) closeStartTag(true); *************** *** 155,158 **** --- 168,189 ---- } + public void endElement(QName qname) throws TransformerException { + try { + if (tagIsOpen) + closeStartTag(true); + else { + writer.write("</"); + if(qname.getPrefix() != null && qname.getPrefix().length() > 0) { + writer.write(qname.getPrefix()); + writer.write(':'); + } + writer.write(qname.getLocalName()); + writer.write('>'); + } + } catch (IOException e) { + throw new TransformerException(e.getMessage(), e); + } + } + public void namespace(String prefix, String nsURI) throws TransformerException { *************** *** 180,185 **** throws TransformerException { try { ! if (!tagIsOpen) ! throw new TransformerException("Found an attribute outside an element"); writer.write(' '); writer.write(qname); --- 211,219 ---- throws TransformerException { try { ! if (!tagIsOpen) { ! characters(value); ! return; ! // throw new TransformerException("Found an attribute outside an element"); ! } writer.write(' '); writer.write(qname); *************** *** 192,195 **** --- 226,250 ---- } + public void attribute(QName qname, String value) throws TransformerException { + try { + if (!tagIsOpen) { + characters(value); + return; + // throw new TransformerException("Found an attribute outside an element"); + } + writer.write(' '); + if(qname.getPrefix() != null && qname.getPrefix().length() > 0) { + writer.write(qname.getPrefix()); + writer.write(':'); + } + writer.write(qname.getLocalName()); + writer.write("=\""); + writeChars(value, true); + writer.write('"'); + } catch (IOException e) { + throw new TransformerException(e.getMessage(), e); + } + } + public void characters(CharSequence chars) throws TransformerException { if (!declarationWritten) *************** *** 311,315 **** i++; } ! writer.write(s.subSequence(pos, i).toString()); if(i >= len) return; --- 366,371 ---- i++; } ! writeCharSeq(s, pos, i); ! // writer.write(s.subSequence(pos, i).toString()); if(i >= len) return; *************** *** 343,346 **** --- 399,408 ---- } + private void writeCharSeq(CharSequence ch, int start, int end) throws IOException { + for(int i = start; i < end; i++) { + writer.write(ch.charAt(i)); + } + } + protected void writeCharacterReference(char charval) throws IOException { int o = 0; --- NEW FILE: Receiver.java --- /* * eXist Open Source Native XML Database * Copyright (C) 2001-04 Wolfgang M. Meier (wol...@ex...) * and others (see http://exist-db.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: Receiver.java,v 1.1 2004/09/12 09:25:16 wolfgang_m Exp $ */ package org.exist.util.serializer; import org.exist.dom.QName; import org.xml.sax.SAXException; /** * A receiver is similar to the SAX content handler and lexical handler interfaces, but * uses some higher level types as arguments. For example, element names are internally * stored as QName objects, so startElement and endElement expect a QName. This way, * we avoid copying objects. * * @author wolf */ public interface Receiver { public abstract void startDocument() throws SAXException; public abstract void endDocument() throws SAXException; public void startPrefixMapping(String prefix, String namespaceURI) throws SAXException; public void endPrefixMapping(String prefix) throws SAXException; public abstract void startElement(QName qname, AttrList attribs) throws SAXException; public abstract void endElement(QName qname) throws SAXException; public abstract void characters(CharSequence seq) throws SAXException; public abstract void attribute(QName qname, String value) throws SAXException; public abstract void comment(char[] ch, int start, int length) throws SAXException; public void processingInstruction(String target, String data) throws SAXException; } Index: SAXSerializer.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/util/serializer/SAXSerializer.java,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** SAXSerializer.java 3 May 2004 13:08:45 -0000 1.7 --- SAXSerializer.java 12 Sep 2004 09:25:15 -0000 1.8 *************** *** 29,32 **** --- 29,33 ---- import javax.xml.transform.TransformerException; + import org.exist.dom.QName; import org.exist.util.XMLString; import org.xml.sax.Attributes; *************** *** 37,41 **** import org.xml.sax.helpers.NamespaceSupport; ! public class SAXSerializer implements ContentHandler, LexicalHandler { private final static Properties defaultProperties = new Properties(); --- 38,42 ---- import org.xml.sax.helpers.NamespaceSupport; ! public class SAXSerializer implements ContentHandler, LexicalHandler, Receiver { private final static Properties defaultProperties = new Properties(); *************** *** 215,218 **** --- 216,304 ---- /* (non-Javadoc) + * @see org.exist.util.serializer.Receiver#startElement(org.exist.dom.QName) + */ + public void startElement(QName qname, AttrList attribs) throws SAXException { + try { + namespaceDecls.clear(); + nsSupport.pushContext(); + receiver.startElement(qname); + String prefix = qname.getPrefix(); + String namespaceURI = qname.getNamespaceURI(); + if(prefix == null) + prefix = ""; + if (namespaceURI == null) + namespaceURI = ""; + if (nsSupport.getURI(prefix) == null) { + namespaceDecls.put(prefix, namespaceURI); + nsSupport.declarePrefix(prefix, namespaceURI); + } + // check attributes for required namespace declarations + QName attrQName; + String uri; + if(attribs != null) { + for (int i = 0; i < attribs.getLength(); i++) { + attrQName = attribs.getQName(i); + if (attrQName.getLocalName().equals("xmlns")) { + if (nsSupport.getURI("") == null) { + uri = attribs.getValue(i); + namespaceDecls.put("", uri); + nsSupport.declarePrefix("", uri); + } + } else if (attrQName.getPrefix() != null && attrQName.getPrefix().length() > 0) { + prefix = attrQName.getPrefix(); + if(prefix.equals("xmlns:")) { + if (nsSupport.getURI(prefix) == null) { + uri = attribs.getValue(i); + prefix = attrQName.getLocalName(); + namespaceDecls.put(prefix, uri); + nsSupport.declarePrefix(prefix, uri); + } + } else { + if (nsSupport.getURI(prefix) == null) { + uri = attrQName.getNamespaceURI(); + namespaceDecls.put(prefix, uri); + nsSupport.declarePrefix(prefix, uri); + } + } + } + } + } + Map.Entry nsEntry; + for (Iterator i = optionalNamespaceDecls.entrySet().iterator(); + i.hasNext(); + ) { + nsEntry = (Map.Entry) i.next(); + prefix = (String) nsEntry.getKey(); + uri = (String) nsEntry.getValue(); + receiver.namespace(prefix, uri); + nsSupport.declarePrefix(prefix, uri); + } + // output all namespace declarations + for (Iterator i = namespaceDecls.entrySet().iterator(); + i.hasNext(); + ) { + nsEntry = (Map.Entry) i.next(); + prefix = (String) nsEntry.getKey(); + uri = (String) nsEntry.getValue(); + if(!optionalNamespaceDecls.containsKey(prefix)) { + receiver.namespace(prefix, uri); + } + } + optionalNamespaceDecls.clear(); + if(attribs != null) { + // output attributes + for (int i = 0; i < attribs.getLength(); i++) { + if (!attribs.getQName(i).getLocalName().startsWith("xmlns")) + receiver.attribute( + attribs.getQName(i), + attribs.getValue(i)); + } + } + } catch (TransformerException e) { + throw new SAXException(e.getMessage(), e); + } + } + + /* (non-Javadoc) * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String) */ *************** *** 221,225 **** try { nsSupport.popContext(); ! receiver.endElement(); } catch (TransformerException e) { throw new SAXException(e.getMessage(), e); --- 307,311 ---- try { nsSupport.popContext(); ! receiver.endElement(qname); } catch (TransformerException e) { throw new SAXException(e.getMessage(), e); *************** *** 228,231 **** --- 314,344 ---- /* (non-Javadoc) + * @see org.exist.util.serializer.Receiver#endElement(org.exist.dom.QName) + */ + public void endElement(QName qname) throws SAXException { + try { + nsSupport.popContext(); + receiver.endElement(qname); + } catch (TransformerException e) { + throw new SAXException(e.getMessage(), e); + } + } + + /* (non-Javadoc) + * @see org.exist.util.serializer.Receiver#attribute(org.exist.dom.QName, java.lang.String) + */ + public void attribute(QName qname, String value) throws SAXException { + // ignore namespace declaration attributes + if((qname.getPrefix() != null && qname.getPrefix().equals("xmlns")) || + qname.getLocalName().equals("xmlns")) + return; + try { + receiver.attribute(qname, value); + } catch (TransformerException e) { + throw new SAXException(e.getMessage(), e); + } + } + + /* (non-Javadoc) * @see org.xml.sax.ContentHandler#characters(char[], int, int) */ Index: XMLIndenter.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/util/serializer/XMLIndenter.java,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** XMLIndenter.java 6 Feb 2004 10:00:58 -0000 1.5 --- XMLIndenter.java 12 Sep 2004 09:25:16 -0000 1.6 *************** *** 26,29 **** --- 26,30 ---- import javax.xml.transform.TransformerException; + import org.exist.dom.QName; import org.exist.storage.serializers.EXistOutputKeys; *************** *** 71,80 **** /* (non-Javadoc) * @see org.exist.util.serializer.XMLWriter#endElement() */ ! public void endElement() throws TransformerException { level--; if (afterTag && !sameline) indent(); ! super.endElement(); sameline = false; afterTag = true; --- 72,104 ---- /* (non-Javadoc) + * @see org.exist.util.serializer.XMLWriter#startElement(org.exist.dom.QName) + */ + public void startElement(QName qname) throws TransformerException { + if(afterTag) + indent(); + super.startElement(qname); + level++; + afterTag = true; + sameline = true; + } + + /* (non-Javadoc) * @see org.exist.util.serializer.XMLWriter#endElement() */ ! public void endElement(String qname) throws TransformerException { level--; if (afterTag && !sameline) indent(); ! super.endElement(qname); ! sameline = false; ! afterTag = true; ! } ! ! /* (non-Javadoc) ! * @see org.exist.util.serializer.XMLWriter#endElement(org.exist.dom.QName) ! */ ! public void endElement(QName qname) throws TransformerException { ! level--; ! if (afterTag && !sameline) indent(); ! super.endElement(qname); sameline = false; afterTag = true; Index: DOMSerializer.java =================================================================== RCS file: /cvsroot/exist/eXist-1.0/src/org/exist/util/serializer/DOMSerializer.java,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** DOMSerializer.java 21 Feb 2004 18:24:57 -0000 1.6 --- DOMSerializer.java 12 Sep 2004 09:25:16 -0000 1.7 *************** *** 187,191 **** if (node.getNodeType() == Node.ELEMENT_NODE) { nsSupport.popContext(); ! receiver.endElement(); } } --- 187,191 ---- if (node.getNodeType() == Node.ELEMENT_NODE) { nsSupport.popContext(); ! receiver.endElement(node.getNodeName()); } } |