All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.exolab.castor.xml.BaseSax2EventFromStaxProducer Maven / Gradle / Ivy

package org.exolab.castor.xml;

import java.util.List;
import java.util.Stack;

import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamReader;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.ErrorHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

/**
 * This provides shared code for {@link Sax2EventFromStaxEventProducer} and
 * {@link Sax2EventFromStaxStreamProducer}. It consumes StAX events and produces SAX2 events.
 * 
 * @author Philipp Erlacher
 * 
 */
public abstract class BaseSax2EventFromStaxProducer implements SAX2EventAndErrorProducer {

  /**
   * Logger from commons-logging.
   */
  private static final Log LOG = LogFactory.getLog(BaseSax2EventFromStaxProducer.class);

  /**
   * A stack to keep track when it's time to invoke endPrefixMapping
   */
  private Stack> prefixes = new Stack>();


  /**
   * On this interface the SAX methods get invoked
   */
  private ContentHandler contentHandler;

  /**
   * Callback Interface to handle errors
   */
  private ErrorHandler errorHandler;

  public static SAX2EventAndErrorProducer createSax2EventFromStax(XMLStreamReader streamReader) {
    return new Sax2EventFromStaxStreamProducer(streamReader);
  }

  public static SAX2EventAndErrorProducer createSax2EventFromStax(XMLEventReader eventReader) {
    return new Sax2EventFromStaxEventProducer(eventReader);
  }

  public void setContentHandler(ContentHandler contentHandler) {
    this.contentHandler = contentHandler;
  }

  public void setErrorHandler(ErrorHandler errorHandler) {
    this.errorHandler = errorHandler;
  }

  public Stack> getPrefixes() {
    return prefixes;
  }

  public ContentHandler getContentHandler() {
    return contentHandler;
  }

  public ErrorHandler getErrorHandler() {
    return errorHandler;
  }

  /**
   * This method takes an eventType and invokes a method to handle that event.
   * 
   * 

* It also takes information about the depth of the read element. Maybe depth changes due to * handling that event. *

* * @param eventType The event type * @param depth The current depth of the element * @return depth The updated depth * @throws SAXException */ int handleEventType(int eventType, int depth) throws SAXException { switch (eventType) { case XMLStreamConstants.START_ELEMENT: handleStartElement(); return ++depth; case XMLStreamConstants.END_ELEMENT: handleEndElement(); return --depth; case XMLStreamConstants.START_DOCUMENT: handleStartDocument(); return ++depth; case XMLStreamConstants.END_DOCUMENT: handleEndDocument(); return --depth; case XMLStreamConstants.CHARACTERS: handleCharacters(); return depth; case XMLStreamConstants.SPACE: handleSpace(); return depth; default: return depth; } } /** * Invoke {@link #handleDocumentLocator()} and {@link getContentHandler().startDocument()}; * * @throws SAXException */ void handleStartDocument() throws SAXException { LOG.info("< handleStartDocument >"); handleDocumentLocator(); contentHandler.startDocument(); } /** * Handles a end document event. *

* Invoke {@link getContentHandler().endDocument()}; *

* * @throws SAXException */ void handleEndDocument() throws SAXException { LOG.info("< handleEndDocument >"); contentHandler.endDocument(); } /** * Handles a start element event. *

* Invoke {@link #doStartPrefixMapping()} and {@link getContentHandler().startElement()}; *

* * @throws SAXException */ void handleStartElement() throws SAXException { LOG.info("< handleStartElement >"); QName qName = getQName(); String localName = qName.getLocalPart(); String uri = qName.getNamespaceURI(); String prefix = qName.getPrefix(); String qNameString = getQName(prefix, localName); Attributes atts = getAttributes(); doStartPrefixMapping(); contentHandler.startElement(uri, localName, qNameString, atts); } /** * Handles an end element event. *

* Invoke {@link getContentHandler().endElement()} and {@link #doEndPrefixMapping()}; *

* * @throws SAXException */ void handleEndElement() throws SAXException { LOG.info("< handleEndElement >"); QName qName = getQName(); String localName = qName.getLocalPart(); String uri = qName.getNamespaceURI(); String prefix = qName.getPrefix(); String qNameString = getQName(prefix, localName); contentHandler.endElement(uri, localName, qNameString); doEndPrefixMapping(); } /** * Handles a space event. * * @throws SAXException */ void handleSpace() throws SAXException { } /** * Handles a character event. *

* If chars is ignorable whitespace {@link getContentHandler().ignorableWhitespace will be called. * Otherwise {@link getContentHandler().characters()} will be called with characters(char[], 0, * length) * *

* * @throws SAXException */ void handleCharacters() throws SAXException { LOG.info("< handleCharacters >"); char[] chars; chars = getCharacters(); if (isIgnorableWhitespace(chars, 0, chars.length)) contentHandler.ignorableWhitespace(chars, 0, chars.length); else contentHandler.characters(chars, 0, chars.length); } /** * @param prefix * @param localPart * @return qName. If prefix length >=1 then it's like prefix:localPart, otherwise it's just the * localPart */ String getQName(String prefix, String localPart) { return getNonEmpty(prefix).length() >= 1 ? prefix + ":" + localPart : localPart; } /** * If a chars without leading and trailing whitespaces would be empty, this method returns true, * otherwise false, * * @param chars * @param start the offset * @param length * @return */ boolean isIgnorableWhitespace(char[] chars, int start, int length) { String string = new String(chars, start, length); return string.trim().length() == 0; } /** * If string equals null this returns an empty string, otherwise it returns the string * * @param string the string to check * @return a string. If string equals null this returns an empty string, otherwise it returns the * string */ String getNonEmpty(String string) { return string == null ? "" : string; } /** * @return a Location */ abstract Location getLocation(); /** * @return characters of the current event. */ abstract char[] getCharacters(); /** * For every declared namespace in the current event * {@link getContentHandler().startPrefixMapping()} gets invoked. * * @throws SAXException */ abstract void doStartPrefixMapping() throws SAXException; /** * * @throws SAXException */ abstract void doEndPrefixMapping() throws SAXException; /** * @return attributes of the current event */ abstract Attributes getAttributes(); /** * @return QName of the current event */ abstract QName getQName(); /** * If {@link #getLocation()} gets a location {@link getContentHandler().setDocumentLocator()} will * be called, otherwise not. */ private void handleDocumentLocator() { Locator locator = getSAXLocator(getLocation()); contentHandler.setDocumentLocator(locator); } /** * Gets a {@link org.xml.sax.Locator} to a given {@link Location}. * * @param location A {@link Location} * @return A {@link Locator} */ protected Locator getSAXLocator(Location location) { return new Locator() { public String getSystemId() { return getLocation().getSystemId(); } public String getPublicId() { return getLocation().getPublicId(); } public int getLineNumber() { return getLocation().getLineNumber(); } public int getColumnNumber() { return getLocation().getColumnNumber(); } }; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy