View Javadoc
1   /*
2    * Copyright 2010 Philipp Erlacher
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.exolab.castor.xml;
17  
18  import java.text.MessageFormat;
19  import java.util.Locale;
20  import java.util.ResourceBundle;
21  
22  import org.apache.commons.lang.ArrayUtils;
23  import org.apache.commons.lang.StringUtils;
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.xml.sax.ContentHandler;
27  import org.xml.sax.SAXException;
28  
29  /**
30   * A processor that assists {@link UnmarshalHandler} in dealing with the SAX 2
31   * {@link ContentHandler#characters(char[], int, int)} callback method.
32   * 
33   * @author <a href=" mailto:philipp.erlacher AT gmail DOT com">Philipp
34   *         Erlacher</a>
35   */
36  public class CharactersProcessor {
37  
38      /**
39       * Standard logger to use.
40       */
41      private static final Log LOG = LogFactory.getLog(CharactersProcessor.class);
42  
43      /**
44       * resource bundle
45       */
46      protected static ResourceBundle resourceBundle;
47  
48      /**
49       * Callback {@link UnmarshalHandler} reference to set the actual state on
50       * this instance.
51       */
52      private final UnmarshalHandler _unmarshalHandler;
53  
54      static {
55          resourceBundle = ResourceBundle.getBundle("UnmarshalHandlerMessages",
56                  Locale.getDefault());
57      }
58  
59      /**
60       * Creates an instance of this class, with a reference to the actual
61       * {@link UnmarshalHandler} for which this processor deals with the SAX 2
62       * characters() callback method.
63       * 
64       * @param unmarshalHandler
65       *            The {@link UnmarshalHandler} instance on which the results of
66       *            processing the characters method will be 'persisted'/set.
67       */
68      public CharactersProcessor(final UnmarshalHandler unmarshalHandler) {
69          _unmarshalHandler = unmarshalHandler;
70      }
71  
72      public void compute(char[] ch, int start, int length) throws SAXException {
73      	String string = new String(ch, start, length);
74          if (LOG.isTraceEnabled()) {
75              String trace = MessageFormat.format(resourceBundle
76                      .getString("unmarshalHandler.log.trace.characters"),
77                      new Object[] { string });
78              LOG.trace(trace);
79          }
80  
81          // -- If we are skipping elements that have appeared in the XML but for
82          // -- which we have no mapping, skip the text and return
83          if (_unmarshalHandler.getStrictElementHandler().skipElement()) {
84              return;
85          }
86  
87          if (_unmarshalHandler.getStateStack().isEmpty()) {
88              return;
89          }
90  
91          if (_unmarshalHandler.getAnyNodeHandler().hasAnyUnmarshaller()) {
92              _unmarshalHandler.getAnyNodeHandler().characters(ch, start, length);
93              return;
94          }
95  
96          UnmarshalState state = _unmarshalHandler.getStateStack().getLastState();
97          // -- handle whitespace
98          boolean removedTrailingWhitespace = false;
99          boolean removedLeadingWhitespace = false;
100         if (!state.isWhitespacePreserving() && !ArrayUtils.isEmpty(ch)) {
101         	removedTrailingWhitespace = Character.isWhitespace(ch[start+length-1]);
102         	removedLeadingWhitespace = Character.isWhitespace(ch[start]);
103         	string = string.trim();
104         }
105 
106         if (state.getBuffer() == null) {
107             state.setBuffer(new StringBuffer());
108         } else {
109         	if (state.isWhitespacePreserving()) {
110 				state.setTrailingWhitespaceRemoved(false);
111 				state.getBuffer().append(string);
112 				return;
113 			} else if (StringUtils.isEmpty(string)) {
114 				state.setTrailingWhitespaceRemoved(removedTrailingWhitespace);
115 				return;
116 			} else if (state.isTrailingWhitespaceRemoved()
117 					|| removedLeadingWhitespace) {
118 				state.getBuffer().append(' ');
119 			}
120 		}
121         state.setTrailingWhitespaceRemoved(removedTrailingWhitespace);
122         state.getBuffer().append(string);
123     }
124 }