You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by co...@apache.org on 2003/04/13 23:53:37 UTC

cvs commit: cocoon-2.1/src/scratchpad/src/org/apache/cocoon/generation JXPathTemplate.java

coliver     2003/04/13 14:53:37

  Added:       src/scratchpad/src/org/apache/cocoon/generation
                        JXPathTemplate.java
  Log:
  optimized JXPath template processor
  
  Revision  Changes    Path
  1.1                  cocoon-2.1/src/scratchpad/src/org/apache/cocoon/generation/JXPathTemplate.java
  
  Index: JXPathTemplate.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, 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 "Apache Cocoon" 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 (INCLU-
   DING, 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 created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.generation;
  
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.environment.SourceResolver;
  import org.apache.cocoon.xml.AbstractXMLProducer;
  import java.io.*;
  import java.util.*;
  import org.xml.sax.*;
  import org.xml.sax.helpers.*;
  import org.apache.commons.jxpath.*;
  
  public class JXPathTemplate extends AbstractGenerator {
  
      private static final JXPathContextFactory 
          jxpathContextFactory = JXPathContextFactory.newInstance();
  
      final static String JXPATH_NS = 
          "http://cocoon.apache.org/transformation/jxpath/1.0";
  
      final static String FOR_EACH = "for-each";
      final static String IF = "if";
      final static String CHOOSE = "choose";
      final static String WHEN = "when";
      final static String OTHERWISE = "otherwise";
      final static String VALUE_OF = "value-of";
  
      class Event {
  	final Locator location;
  	Event next;
  	Event(Locator location) {
  	    this.location = new LocatorImpl(location);
  	}
      }
  
      class TextEvent extends Event {
  	TextEvent(Locator location, 
  		  char[] chars, int start, int length) {
  	    super(location);
  	    this.chars = new char[this.length = length];
  	    System.arraycopy(chars, start, this.chars, 
  			     this.start = 0, length);
  	}
  	final char[] chars;
  	final int start;
  	final int length;
      }
  
      class Characters extends TextEvent {
  	Characters(Locator location, 
  		  char[] chars, int start, int length) {
  	    super(location, chars, start, length);
  	}
      }
  
      class StartDocument extends Event {
  	long compileTime;
  	StartDocument(Locator location, long compileTime) {
  	    super(location);
  	    this.compileTime = compileTime;
  	}
      }
  
      class EndDocument extends Event {
  	EndDocument(Locator location) {
  	    super(location);
  	}
      }
  
      class EndPrefixMapping extends Event {
  	EndPrefixMapping(Locator location, String prefix) {
  	    super(location);
  	    this.prefix = prefix;
  	}
  	final String prefix;
      }
      
      class IgnorableWhitespace extends TextEvent {
  	IgnorableWhitespace(Locator location, 
  			    char[] chars, int start, int length) {
  	    super(location, chars, start, length);
  	}
      }
  
      class SkippedEntity extends Event {
  	SkippedEntity(Locator location, String name) {
  	    super(location);
  	    this.name = name;
  	}
  	final String name;
      }
  
      abstract class AttributeEvent {
  	AttributeEvent(String name, String namespaceURI,
  		       String type) {
  	    this.name = name;
  	    this.namespaceURI = namespaceURI;
  	    this.type = type;
  	}
  	final String name;
  	final String namespaceURI;
  	final String type;
      }
      
      class CopyAttribute extends AttributeEvent {
  	CopyAttribute(String name, String namespaceURI,
  		      String type, String value) {
  	    super(name, namespaceURI, type);
  	    this.value = value;
  	}
  	final String value;
      }
      
      class Subst {
      }
      
      class Literal extends Subst {
  	Literal(String val) {
  	    this.value = val;
  	}
  	String value;
      }
      
      class Expression extends Subst {
  	Expression(CompiledExpression expr) {
  	    this.expr = expr;
  	}
  	CompiledExpression expr;
      }
  
      class SubstituteAttribute extends AttributeEvent {
  	List substitutions = new LinkedList();
      }
  
      class StartElement extends Event {
  	StartElement(Locator location, String namespaceURI,
  		     String localName, String raw,
  		     Attributes attrs) throws SAXException {
  	    super(location);
  	    this.namespaceURI = namespaceURI;
  	    this.localName = localName;
  	    this.raw = raw;
  	    StringBuffer buf = new StringBuffer();
  	    for (int i = 0, len = attrs.getLength();
  		 i < len; i++) {
  		String uri = attrs.getURI(i);
  		String localName = attrs.getLocalName(i);
  		String raw = attrs.getQName(i);
  		String type = attrs.getType(i);
  		String value = attrs.getValue(i);
  		StringReader in = new StringReader(value);
  		int ch;
  		buf.setLength(0);
  		boolean inExpr = false;
  		while ((ch = in.read()) != -1) {
  		    char c = (char)ch;
  		    if (inExpr) {
  			if (c == '}') {
  			    String str = buf.toString();
  			    buf.setLength(0);
  			    CompiledExpression compiledExpression = 
  				JXPathContext.compile(str);
  			    attributeEvents.add(new Expression(compiledExpression));
  			    inExpr = false;
  			} else if (c == '\\') {
  			    ch = in.read();
  			    if (ch == -1) {
  				buf.append('\\');
  			    } else {
  				buf.append((char)ch);
  			    }
  			} else {
  			    buf.append(c);
  			}
  		    } else {
  			if (c == '\\') {
  			    ch = in.read();
  			    if (ch == -1) {
  				buf.append('\\');
  			    } else {
  				buf.append((char)ch);
  			    }
  			} else {
  			    if (c == '{') {
  				ch = in.read();
  				if (ch != -1) {
  				    if (buf.getLength() > 0) {
  					attributeEvents.add(new Literal(buf.toString()));
  					buf.setLength(0);
  				    }
  				    buf.append((char)ch);
  				    inExpr = true;
  				    continue;
  				}
  				buf.append('{');
  			    }
  			    if (ch != -1) {
  				buf.append((char)ch);
  			    }
  			}
  		    }
  		}
  		if (buf.getLength() > 0) {
  		    attributeEvents.add(new Literal(buf.toString()));
  		}
  	    }
  	}
  	final String namespaceURI;
  	final String localName;
  	final String raw;
  	final List attributeEvents = new LinkedList();
      }
  
      class StartForEach extends Event {
  	StartForEach(Locator location, CompiledExpression select) {
  	    super(location);
  	    this.select = select;
  	}
  	CompiledExpression select;
  	EndForEach endForEach;
      }
      
      class EndForEach extends Event {
  	EndForEach(Locator location) {
  	    super(location);
  	}
      }
  
      class StartIf extends Event {
  	StartIf(Locator location, CompiledExpression test) {
  	    super(location);
  	    this.test = test;
  	}
  	final CompiledExpression test;
  	EndIf endIf;
      }
  
      class EndIf extends Event {
  	EndIf(Locator location) {
  	    super(location);
  	}
      }
  
      class StartChoose extends Event {
  	StartChoose(Locator location) {
  	    super(location);
  	}
  	StartWhen firstChoice;
  	StartOtherwise otherwise;
  	EndChoose endChoose;
      }
  
      class EndChoose extends Event {
  	EndChoose(Locator location) {
  	    super(location);
  	}
      }
  
      class StartWhen extends Event {
  	StartWhen(Locator location, CompiledExpression test) {
  	    super(location);
  	    this.test = test;
  	}
  	final CompiledExpression test;
  	StartWhen nextChoice;
  	EndWhen endWhen;
      }
  
      class EndWhen extends Event {
  	EndWhen(Locator location) {
  	    super(location);
  	}
      }
  
      class StartOtherwise extends Event {
  	StartOtherwise(Locator location) {
  	    super(location);
  	}
  	EndOtherwise endOtherwise;
      }
  
      class EndOtherwise extends Event {
  	EndOtherwise(Locator location) {
  	    super(location);
  	}
      }
  
      class StartPrefixMapping extends Event {
  	StartPrefixMapping(Locator location, String prefix,
  			   String uri) {
  	    super(location);
  	    this.prefix = prefix;
  	    this.uri = uri;
  	}
  	String prefix;
  	String uri;
      }
  
      class Comment extends TextEvent {
  	Comment(Locator location, char[] chars,
  		int start, int length) {
  	    super(location, chars, start, length);
  	}
      }
  
      class EndCDATA extends Event {
  	EndCDATA(Locator location) {
  	    super(location);
  	}
      }
  
      class EndDTD extends Event {
  	EndDTD(Locator location) {
  	    super(location);
  	}
      }
  
      class EndEntity extends Event {
  	EndEntity(Locator location, String name) {
  	    super(location);
  	    this.name = name;
  	}
  	final String name;
      }
  
      class StartDTD extends Event {
  	StartDTD(Locator location, String name, 
  		 String publicId, String systemId) {
  	    super(location);
  	    this.name = name;
  	    this.publicId = publicId;
  	    this.systemId = systemId;
  	}
  	final String name;
  	final String publicId;
  	final String SystemId;
      }
      
      class StartEntity extends Event {
  	public StartEntity(Locator location, String name) {
  	    super(location);
  	    this.name = name;
  	}
  	final String name;
      }
  
  
      class Parser implements LexicalHandler, ContentHandler {
  
  	Event lastEvent;
  	Stack stack = new Stack();
  	Locator locator;
  
  	private void addEvent(Event ev) {
  	    lastEvent.next = ev;
  	    lastEvent = ev;
  	}
  
  	public void characters(char[] ch, int start, int length) {
  	    Characters chars = new Characters(locator,
  					      ch, start, length);
  	    addEvent(chars);
  	}
  
  	public void endDocument() {
  	    StartDocument startDoc = (StartDocument)stack.pop();
  	    EndDocument endDoc = new EndDocument(locator);
  	    addEvent(endDoc);
  	}
  
  	public void endElement(String namespaceURI,
  			       String localName,
  			       String raw) 
  	    throws SAXException {
  	    Event start = (Event)stack.pop();
  	    Event newEvent = null;
  	    if (JXPATH_NS.equals(namespaceURI)) {
  		if (start instanceof StartForEach) {
  		    StartForeach startForEach = 
  			(StartForEach)start;
  		    newEvent = startForEach.endForEach = 
  			new EndForEach(locator);
  		    
  		} else if (start instanceof StartIf) {
  		    StartIf startIf = (StartIf)start;
  		    newEvent = startIf.endIf = 
  			new EndIf(locator);
  		} else if (start instanceof StartWhen) {
  		    StartWhen startWhen = (StartWhen)start;
  		    StartChoose startChoose = (StartChoose)stack.peek();
  		    if (startChoose.firstWhen != null) {
  			StartWhen w = startChoose.firstWhen;
  			while (w.nextWhen != null) {
  			    w = w.nextWhen;
  			}
  			w.nextWhen = startWhen;
  		    } else {
  			startChoose.firstWhen = startWhen;
  		    }
  		    newEvent = startWhen.endWhen = 
  			new EndWhen(locator);
  		} else if (start instanceof StartOtherwise) {
  		    StartOtherwise startOtherwise = 
  			(StartOtherwise)start;
  		    StartChoose startChoose = (StartChoose)stack.peek();
  		    newEvent = startOtherwise.endOtherwise = 
  			new EndOtherwise(locator);
  		    startChoose.otherwise = startOtherwise;
  		}
  	    } else {
  		StartElement startElement = (StartElement)start;
  		newEvent = new EndElement(locator, startElement);
  	    }
  	    addEvent(newEvent);
  	}
  	
  	public void endPrefixMapping(String prefix) {
  	    EndPrefixMapping endPrefixMapping = 
  		new EndPrefixMapping(locator, prefix);
  	    addEvent(endPrefixMapping);
  	}
  
  	public void ignorableWhitespace(char[] ch, int start, int length) {
  	    Event chars = new IgnorableWhitespace(locator,
  						  ch, start, length);
  	    addEvent(chars);
  	}
  
  	public void processingInstruction(String target,
  					  String data) {
  	    Event pi = new ProcessingInstruction(locator, target,
  						 data);
  	    addEvent(pi);
  	}
  
  	public void setDocumentLocator(Locator locator) {
  	    this.locator = locator;
  	}
  
  	public void skippedEntity(String name) {
  	    addEvent(new SkippedEntity(locator, name));
  	}
  
  
  	public void startDocument() {
  	    startEvent = new StartDocument(locator);
  	    lastEvent = startEvent;
  	    stack.push(lastEvent);
  	}
  
  	public void startElement(String namespaceURI,
  				 String localName,
  				 String raw,
  				 Attributes attrs) 
  	    throws SAXException {
  	    Event newEvent = null;
  	    if (JXPATH_NS.equals(namespaceURI)) {
  		if (localName.equals(FOR_EACH)) {
  		    String select = attrs.getValue("select");
  		    if (select == null) {
  			throw new SAXParseException("for-each: \"select\" is rrequired", locator, null);
  		    }
  		    CompiledExpression expr = 
  			JXPathContext.compile(select);
  		    StartForEach startForEach = 
  			new StartForEach(locator, expr);
  		    newEvent = startForEach;
  		} else if (localName.equals(CHOOSE)) {
  		} else if (localName.equals(WHEN)) {
  		} else if (localName.equals(OTHERWISE)) {
  		} else if (localName.equals(IF)) {
  		    String test = attrs.getValue("test");
  		    if (test == null) {
  			throw new SAXParseException("if: \"test\" is rrequired", locator, null);
  		    }
  		    CompiledExpression expr = 
  			JXPathContext.compile(test);
  		    StartIf startIf = 
  			new StartIf(locator, expr);
  		    newEvent = startIf;
  		} else if (localName.equals(VALUE_OF)) {
  		}
  	    } else {
  		StartElement startElem = 
  		    new StartElement(locator, namespaceURI,
  				     localName, raw, attrs);
  		newEvent = startElem;
  		stack.push(startElem);
  	    }
  	    addEvent(newEvent);
  	}
  	
  	void startPrefixMapping(String prefix, String uri) {
  	    addEvent(new StartPrefixMapping(locator, prefix, uri));
  	}
      }
  
      private StartDocument startEvent;
      private XMLConsumer consumer;
      private JXPathContext rootContext;
      private Variables variables;
      private static Map cache = new HashMap();
      private Source inputSource;
  
      public void setup(SourceResolver resolver, Map objectModel,
                        String src, Parameters parameters)
          throws ProcessingException, SAXException, IOException {
  
          super.setup(resolver, objectModel, src, parameters);
          if (src != null) {
              try {
                  this.inputSource = resolver.resolveURI(src);
              } catch (SourceException se) {
                  throw SourceUtil.handle("Error during resolving of '" + src + "'.", se);
              }
          }
  	String uri = inputSource.getURI();
  	int lastMod = inputSource.getLastModified();
  	synchronized (cache) {
  	    StartDocument startEvent = (StartDocument)cache.get(uri);
  	    if (startEvent != null &&
  		lastMod > startEvent.compileTime) {
  		cache.remove(uri);
  	    }
  	}
          // FIX ME: When we decide proper way to pass "bean" and "kont"
          Object bean = ((Environment)resolver).getAttribute("bean-dict");
          kont =
              (WebContinuation)((Environment)resolver).getAttribute("kont");
          variables = new MyVariables(bean, 
                                      kont,
                                      ObjectModelHelper.getRequest(objectModel),
                                      ObjectModelHelper.getResponse(objectModel),
                                      ObjectModelHelper.getContext(objectModel),
                                      parameters);
  	rootContext = jxpathContextFactory.newContext(null, bean);
  	rootContext.setVariables(variables);
      }
  
      public void setConsumer(XMLConsumer consumer) {
  	this.consumer = consumer;
      }
  
      public void generate() 
          throws IOException, SAXException, ProcessingException {
  	StartDocument startEvent;
  	synchronized (cache) {
  	    startEvent = cache.get(inputSource.getURI());
  	}
  	if (startEvent == null) {
  	    long compileTime = inputSource.getLastModified();
  	    Parser parser = new Parser();
  	    this.resolver.toSAX(this.inputSource, parser);
  	    startEvent = parser.startEvent;
  	    startEvent.compileTime = compileTime;
  	    synchronized (cache) {
  		cache.put(inputSource.getURI(), startEvent);
  	    }
  	}
  	execute(rootContext, startEvent, null);
      }
  
      private void execute(JXPathContext context,
  			 Event startEvent, Event endEvent) 
  	throws SAXException {
  	Event ev = startEvent;
  	while (ev != endEvent) {
  	    consumer.setDocumentLocator(ev.location);
  	    if (ev instanceof Characters) {
  		TextEvent text = (Text)ev;
  		consumer.characters(text.chars, text.start,
  				    text.length);
  	    } else if (ev instanceof EndDocument) {
  		consumer.startDocument();
  	    } else if (ev instanceof EndElement) {
  		EndElement endElement = (EndElement)ev;
  		StartElement startElement = (StartElement)endElement.startElement;
  		consumer.endElement(startElement.namespaceURI,
  				    startElement.localName,
  				    startElement.raw);
  	    } else if (ev instanceof EndPrefixMapping) {
  		EndPrefixMapping endPrefixMapping = 
  		    (EndPrefixMapping)ev;
  		consumer.endPrefixMapping(endPrefixMapping.prefix);
  	    } else if (ev instanceof IgnorableWhitespace) {
  		TextEvent text = (Text)ev;
  		consumer.ignorableWhitespace(text.chars, text.start,
  					     text.length);
  	    } else if (ev instanceof ProcessingInstruction) {
  		ProcessingInstruction pi = (ProcessingInstruction)ev;
  		consumer.processingInstruction(pi.target, pi.data);
  	    } else if (ev instanceof SkippedEntity) {
  		SkippedEntity skippedEntity = (SkippedEntity)event;
  		consumer.skippedEntity(skippedEntity.name);
  	    } else if (ev instanceof StartDocument) {
  		consumer.startDocument();
  	    } else if (ev instanceof StartIf) {
  		StartIf startIf = (StartIf)ev;
  		Object val = startIf.test.getValue(context);
  		boolean result = false;
  		if (val instanceof Boolean) {
  		    result = ((Boolean)val).booleanValue();
  		}
  		if (!result) {
  		    ev = startIf.endIf.next;
  		    continue;
  		}
  	    } else if (ev instanceof StartForeach) {
  		StartForEach startForEach = (StartForEach)ev;
  		Iterator iter = 
  		    startForEach.select.iteratePointers(context);
  		while (iter.hasNext()) {
  		    Object contextObject = iter.next();
  		    JXPathContext newContext = 
  			jxpathContextFactory.newContext(null, 
  							contextObject);
  		    newContext.setVariables(variables);
  		    execute(newContext,
  			    startForEach.startEvent,
  			    startForEach.endForEach);
  		}
  		ev = startForEach.endForEach.next;
  		continue;
  	    } else if (ev instanceof StartChoose) {
  		StartChoose choose = (StartChoose)ev;
  		StartWhen when = choose.firstWhen; 
  		for (;when != null; when = when.nextChoice) {
  		    Object val = when.test.getValue(context);
  		    boolean result = false;
  		    if (val instanceof Boolean) {
  			result = ((Boolean)val).booleanValue();
  		    }
  		    if (result) {
  			execute(context, when.next, when.endWhen);
  			break;
  		    }
  		}
  		if (when == null) {
  		    if (startChoose.otherwise != null) {
  			execute(context, startChoose.otherwise.next,
  				startChoose.otherwise.endOtherwise);
  		    }
  		}
  		ev = choose.endChoose.next;
  		continue;
  	    } else if (ev instanceof StartElement) {
  		StartElement startElement = (StartElement)ev;
  		Iterator i = startElement.attributeEvents.iterator();
  		AttributesImpl attrs = new AttributesImpl();
  		while (i.hasNext()) {
  		    AttributeEvent attrEvent = (AttributeEvent)
  			i.next();
  		    if (attrEvent instanceof CopyAttribute) {
  			CopyAttribute copy =
  			    (CopyAttribute)attrEvent;
  			attrs.addAttribute(copy.name,
  					   copy.namespaceURI,
  					   copy.type,
  					   copy.value);
  		    } else if (attrEvent instanceof 
  			       SubstituteAttribute) {
  			StringBuffer buf = new StringBuffer();
  			SubstituteAttribute substEvent =
  			    (SubstituteAttribute)attrEvent;
  			Iterator ii = substEvent.substitutions.iterator();
  			while (ii.hasNext()) {
  			    Subst subst = (Subst)ii.next();
  			    if (subst instanceof Literal) {
  				Literal lit = (Literal)subst;
  				buf.append(lit);
  			    } else if (subst instanceof Expression) {
  				Expression expr = (Expression)subst;
  				Object val = 
  				    expr.compiledExpression.getValue(getContext());
  				if (val == null) {
  				    val = "";
  				}
  				buf.append(val.toString());
  			    }
  			}
  			attrs.addAttribute(subst.name,
  					   subst.namespaceURI,
  					   subst.type,
  					   buf.toString());
  		    }
  		}
  		consumer.startElement(startElement.namespaceURI,
  				      startElement.localName,
  				      startElement.raw,
  				      attrs); 
  	    } else if (ev instanceof StartPrefixMapping) {
  		StartPrefixMapping startPrefixMapping = 
  		    (StartPrefixMapping)ev;
  		consumer.startPrefixMapping(ev.prefix, ev.uri);
  	    } else if (ev instanceof Comment) {
  		TextEvent text = (Text)ev;
  		consumer.comment(text.chars, text.start,
  				 text.length);
  	    } else if (ev instanceof EndCDATA) {
  		consumer.endCDATA();
  	    } else if (ev instanceof EndDTD) {
  		consumer.endDTD();
  	    } else if (ev instanceof EndEntity) {
  		consumer.endEntity(((EndEntity)ev).name);
  	    } else if (ev instanceof startCDATA) {
  		consumer.startCDATA();
  	    } else if (ev instanceof StartDTD) {
  		StartDTD startDTD = (StartDTD)ev;
  		consumer.startDTD(startDTD.name,
  				  startDTD.publicId,
  				  startDTD.systemId);
  	    } else if (ev instanceof StartEntity) {
  		consumer.startEntity(((StartEntity)ev).name);
  	    }
  	    ev = ev.next;
  	}
      }
  
  }