/* * Copyright 2010 Philipp Erlacher * * 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 org.exolab.castor.xml; import java.text.MessageFormat; import java.util.Locale; import java.util.ResourceBundle; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; /** * A processor that assists {@link UnmarshalHandler} in dealing with the SAX 2 * {@link ContentHandler#characters(char[], int, int)} callback method. * * @author <a href=" mailto:philipp.erlacher AT gmail DOT com">Philipp * Erlacher</a> */ public class CharactersProcessor { /** * Standard logger to use. */ private static final Log LOG = LogFactory.getLog(CharactersProcessor.class); /** * resource bundle */ protected static ResourceBundle resourceBundle; /** * Callback {@link UnmarshalHandler} reference to set the actual state on * this instance. */ private final UnmarshalHandler _unmarshalHandler; static { resourceBundle = ResourceBundle.getBundle("UnmarshalHandlerMessages", Locale.getDefault()); } /** * Creates an instance of this class, with a reference to the actual * {@link UnmarshalHandler} for which this processor deals with the SAX 2 * characters() callback method. * * @param unmarshalHandler * The {@link UnmarshalHandler} instance on which the results of * processing the characters method will be 'persisted'/set. */ public CharactersProcessor(final UnmarshalHandler unmarshalHandler) { _unmarshalHandler = unmarshalHandler; } public void compute(char[] ch, int start, int length) throws SAXException { if (LOG.isTraceEnabled()) { String trace = MessageFormat.format(resourceBundle .getString("unmarshalHandler.log.trace.characters"), new Object[] { new String(ch, start, length) }); LOG.trace(trace); } // -- If we are skipping elements that have appeared in the XML but for // -- which we have no mapping, skip the text and return if (_unmarshalHandler.getStrictElementHandler().skipElement()) { return; } if (_unmarshalHandler.getStateStack().isEmpty()) { return; } if (_unmarshalHandler.getAnyNodeHandler().hasAnyUnmarshaller()) { _unmarshalHandler.getAnyNodeHandler().characters(ch, start, length); return; } UnmarshalState state = _unmarshalHandler.getStateStack().getLastState(); // -- handle whitespace boolean removedTrailingWhitespace = false; boolean removedLeadingWhitespace = false; if (!state.isWhitespacePreserving()) { // -- trim leading whitespace characters while (length > 0) { boolean whitespace = false; switch (ch[start]) { case ' ': case '\r': case '\n': case '\t': whitespace = true; break; default: break; } if (!whitespace) break; removedLeadingWhitespace = true; ++start; --length; } if (length == 0) { // -- we also need to mark trailing whitespace removed // -- when we received only whitespace characters removedTrailingWhitespace = removedLeadingWhitespace; } else { // -- trim trailing whitespace characters while (length > 0) { boolean whitespace = false; switch (ch[start + length - 1]) { case ' ': case '\r': case '\n': case '\t': whitespace = true; break; default: break; } if (!whitespace) break; removedTrailingWhitespace = true; --length; } } } if (state.getBuffer() == null) { state.setBuffer(new StringBuffer()); } else { // -- non-whitespace content exists, add a space if ((!state.isWhitespacePreserving()) && (length > 0)) { if (state.isTrailingWhitespaceRemoved() || removedLeadingWhitespace) { state.getBuffer().append(' '); } } } state.setTrailingWhitespaceRemoved(removedTrailingWhitespace); state.getBuffer().append(ch, start, length); } }