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

net.sf.xolite.impl.BaseXMLEventParser Maven / Gradle / Ivy

Go to download

This project provides a lightweight framework to serialize/deserialize (or marshall/unmarshall) java objects into XML. The implementation is based on standard SAX (Simple Api for Xml) but it follows a original approach based on the strong data encapsulation paradigm of Object Oriented (OO) programming.

The newest version!
/*-------------------------------------------------------------------------
 Copyright 2006 Olivier Berlanger

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 -------------------------------------------------------------------------*/
package net.sf.xolite.impl;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.namespace.NamespaceContext;

import net.sf.xolite.NamespacedName;
import net.sf.xolite.XMLEventParser;
import net.sf.xolite.XMLObjectFactory;
import net.sf.xolite.XMLParseException;
import net.sf.xolite.XMLSerializable;


/**
 * A base XMLEventParser implementation common to many parsers.
 * 
 * @author Olivier Berlanger
 */
public abstract class BaseXMLEventParser implements XMLEventParser {


    /** Handler to where the simplified SAX parse events are forwarded. */
    private XMLSerializable currentHandler;
    /** the last object that called endParsing(..) method on the parser. */
    private XMLSerializable lastParsed;
    /** Stack of all the XMLSerializable handlers parent of the current one. */
    private List levels;
    /** current level in the 'levels' list. */
    private int currentLevel = -1;
    /** Flag telling if we are currently in a startElement or a endElement notification. */
    private boolean currentlyInTagEnd;
    /** Flag telling if we are notifying the first or last event to a handler (to be combined with currentlyInTagEnd). */
    private boolean currentlyInFirstOrLast;
    /** A factory which can be used to instantiate objects from XML elements. */
    private XMLObjectFactory factory;
    /** Map to hold custom objects. */
    private Map customObjects;


    public BaseXMLEventParser() {
        levels = new ArrayList();
    }


    /**
     * Set the factory to be used by this parser.
     * 
     * @param newFactory
     *            a factory able to instantiate objects corresponding to XML elements.
     */
    public void setFactory(XMLObjectFactory newFactory) {
        factory = newFactory;
    }


    /**
     * Get namespace URI corresponding to the given prefix. 
* Note: the mapped namespace set depends on the currently parsed node. * * @see javax.xml.namespace.NamespaceContext#getPrefix(java.lang.String) */ public String getNamespaceURI(String prefix) { for (int i = currentLevel; i >= 0; i--) { String uri = levels.get(i).getPrefixMappings().getNamespaceURI(prefix); if (uri != null) return uri; } return null; } /** * Get the first prefix mapped to the given namespace. * * @see javax.xml.namespace.NamespaceContext#getPrefix(java.lang.String) */ public String getPrefix(String namespaceURI) { for (int i = currentLevel; i >= 0; i--) { String prefix = levels.get(i).getPrefixMappings().getPrefix(namespaceURI); if (prefix != null) return prefix; } return null; } /** * Get all the prefixes mapped to the given namespace. * * @see javax.xml.namespace.NamespaceContext#getPrefixes(java.lang.String) */ public Iterator getPrefixes(String namespaceURI) { Set prefixes = new HashSet(); for (int i = currentLevel; i >= 0; i--) { MapPrefixResolver prefixMappings = levels.get(i).getPrefixMappings(); for (Iterator levelPrefixes = prefixMappings.getPrefixes(namespaceURI); levelPrefixes.hasNext();) { prefixes.add(levelPrefixes.next()); } } return prefixes.iterator(); } // ------------------------ XMLEventParser interface implementation ----------------------------------------------- public NamespacedName getCurrentElementName() { LevelInfo level = getCurrentLevel(); return new NamespacedName(level.getCurrentURI(), level.getCurrentElementName()); } public NamespaceContext getCurrentDefinedNamespaces() { MapPrefixResolver context = new MapPrefixResolver(); for (int i = 0; i <= currentLevel; i++) { MapPrefixResolver prefixMappings = levels.get(i).getPrefixMappings(); context.addAll(prefixMappings); } return context; } public void delegateParsingTo(XMLSerializable handlerOfSubElements) throws XMLParseException { if (currentHandler == null) throw new IllegalStateException("The currentHandler is null"); LevelInfo level = getCurrentLevel(); if (level == null) throw new IllegalStateException("The delegateParsingTo(..) method can only be called from startElement(..)"); if (currentlyInTagEnd) throw new IllegalStateException("The delegateParsingTo(..) method can only be called from startElement(..)"); level.addHandler(handlerOfSubElements); currentHandler = handlerOfSubElements; currentlyInFirstOrLast = true; handlerOfSubElements.startElement(level.getCurrentURI(), level.getCurrentElementName(), this); currentlyInFirstOrLast = false; } public XMLSerializable parseElement(String uri, String localName) throws XMLParseException { XMLSerializable child = getFactory().createObject(uri, localName, this); delegateParsingTo(child); return child; } public boolean isFirstEvent() { return currentlyInFirstOrLast && !currentlyInTagEnd; } public boolean isLastEvent() { return currentlyInFirstOrLast && currentlyInTagEnd; } public XMLSerializable getLastParsedObject() throws XMLParseException { return lastParsed; } public NamespacedName getQualifiedName(String qName) throws XMLParseException { int colonIndex = qName.indexOf(':'); String prefix = (colonIndex < 0) ? "" : qName.substring(0, colonIndex); String uri = getNamespaceURI(prefix); if ((uri == null) && !prefix.equals("")) throwParseException("Unbound prefix for '" + qName + "'", null); String name = (colonIndex < 0) ? qName : qName.substring(colonIndex + 1); NamespacedName qualified = new NamespacedName(uri, name); return qualified; } public XMLObjectFactory getFactory() throws XMLParseException { if (factory == null) throw new XMLParseException("XmlObjectFactory is not defined"); return factory; } public Object getCustomObject(Object key) { return (customObjects == null) ? null : customObjects.get(key); } public void putCustomObject(Object key, Object value) { if (customObjects == null) customObjects = new HashMap(); customObjects.put(key, value); } // --------------------------------- Exception management ----------------------------------- public void throwUnexpectedNamespaceException(String expected) throws XMLParseException { StringBuffer sb = new StringBuffer("Unexpected namespace: "); LevelInfo level = getCurrentLevel(); if (level != null) { sb.append("'"); sb.append(level.getCurrentURI()); if (expected != null) { sb.append("', expected: '"); sb.append(expected); sb.append("'"); } } throwParseException(sb.toString(), null, true); } public void throwUnexpectedElementException(String expectedTags) throws XMLParseException { StringBuilder sb = new StringBuilder("Unexpected element "); appendCurrentElement(sb); if (expectedTags != null) { sb.append(" (expected= "); sb.append(expectedTags); sb.append(")"); } throwParseException(sb.toString(), null, false); } public void throwParseException(String message, Throwable cause) throws XMLParseException { throwParseException(message, cause, true); } private void throwParseException(String message, Throwable cause, boolean addLocation) throws XMLParseException { StringBuilder sb = new StringBuilder(message); if (addLocation) { sb.append(" in element "); appendCurrentElement(sb); } XMLParseException pe = new XMLParseException(sb.toString()); if (cause != null) pe.initCause(cause); addLocationInfo(pe); throw pe; } private void appendCurrentElement(StringBuilder sb) { sb.append("<"); if (currentlyInTagEnd) sb.append("/"); LevelInfo level = getCurrentLevel(); if (level != null) { if ((level.getCurrentURI() != null) && !level.getCurrentURI().equals("")) { sb.append(level.getCurrentURI()); sb.append(":"); } sb.append(level.getCurrentElementName()); } else { sb.append("???"); } sb.append(">"); } protected void transformAndThrowException(Exception source) throws XMLParseException { if (source instanceof XMLParseException) { throw (XMLParseException) source; } else { XMLParseException xpe = new XMLParseException(source.getMessage(), source); addLocationInfo(xpe); throw xpe; } } protected abstract void addLocationInfo(XMLParseException xpe); // ------------------------ Implementation ----------------------------------------------- protected void setup(XMLSerializable rootHandler) { clearState(); setupRootHandler(rootHandler); currentlyInFirstOrLast = true; } protected void tearDown() { clearState(); } /** * Clean state and avoid keeping dangling references to internal objects. */ private void clearState() { for (LevelInfo level : levels) { level.clear(); } currentHandler = null; lastParsed = null; currentLevel = -1; } LevelInfo getCurrentLevel() { if (currentLevel < 0) return null; return levels.get(currentLevel); } void increaseLevel(String uri, String localName) { currentLevel++; LevelInfo newLevel; if (currentLevel < levels.size()) { newLevel = levels.get(currentLevel); } else if (currentLevel == levels.size()) { newLevel = new LevelInfo(); levels.add(newLevel); } else { // should never happen throw new IllegalStateException("Level mismatch"); } newLevel.init(uri, localName); } void decreaseLevel(String uri, String localName) throws XMLParseException { assert (currentLevel >= 0); LevelInfo level = getCurrentLevel(); int handlerCount = level.getHandlerCount(); if (handlerCount > 0) { for (int i = handlerCount - 1; i >= 0; i--) { XMLSerializable nextHandler = null; if (i > 0) nextHandler = level.getHandlers().get(i - 1); else nextHandler = getNextHandler(currentLevel - 1); // notify next handler lastParsed = currentHandler; currentHandler = nextHandler; currentlyInFirstOrLast = (i > 0); if (currentHandler != null) { currentHandler.endElement(level.getCurrentURI(), level.getCurrentElementName(), this); } } } level.clear(); currentLevel--; } private void setupRootHandler(XMLSerializable root) { assert (currentLevel == -1); increaseLevel(null, null); levels.get(0).addHandler(root); currentLevel--; currentHandler = root; } protected void pushPrefixMappingInNextLevel(String prefix, String namespaceURI) { increaseLevel(null, null); levels.get(currentLevel).getPrefixMappings().addPrefixMapping(prefix, namespaceURI); currentLevel--; } private XMLSerializable getNextHandler(int fromLevel) { for (int i = fromLevel; i >= 0; i--) { LevelInfo level = levels.get(i); int handlerCount = level.getHandlerCount(); if (handlerCount > 0) { return level.getHandlers().get(handlerCount - 1); } } return null; } protected void startElementImpl(String uri, String localName) throws Exception { increaseLevel(uri, localName); currentlyInTagEnd = false; currentHandler.startElement(uri, localName, BaseXMLEventParser.this); currentlyInFirstOrLast = false; } protected void endElementImpl(String uri, String localName) throws Exception { currentlyInTagEnd = true; currentlyInFirstOrLast = getCurrentLevel().getHandlerCount() > 0; currentHandler.endElement(uri, localName, BaseXMLEventParser.this); decreaseLevel(uri, localName); } // --------------------- Level inner class ------------------------------- /** * Info put in a stack while opening XML elements. */ static class LevelInfo { private List handlers; /** Defined prefix mappings. */ private MapPrefixResolver prefixMappings; /** The namespace URI of this level element. */ private String currentElementURI; /** The local name of this level element. */ private String currentElementName; LevelInfo() { handlers = new ArrayList(); prefixMappings = new MapPrefixResolver(); } public int getHandlerCount() { return handlers.size(); } void addHandler(XMLSerializable handler) { handlers.add(handler); } List getHandlers() { return handlers; } void init(String uri, String localName) { currentElementURI = uri; currentElementName = localName; } void clear() { handlers.clear(); prefixMappings.clear(); currentElementURI = null; currentElementName = null; } String getCurrentURI() { return currentElementURI; } String getCurrentElementName() { return currentElementName; } MapPrefixResolver getPrefixMappings() { return prefixMappings; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy