1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 package org.jaxen.function;
50
51 import java.util.List;
52
53 import org.jaxen.Context;
54 import org.jaxen.Function;
55 import org.jaxen.FunctionCallException;
56 import org.jaxen.Navigator;
57
58 /***
59 * <p>
60 * <b>4.2</b> <code><i>string</i> normalize-space(<i>string</i>)</code>
61 * </p>
62 *
63 * <blockquote src="http://www.w3.org/TR/xpath#function-normalize-space">
64 * The <b>normalize-space</b> function
65 * returns the argument string with whitespace normalized by stripping
66 * leading and trailing whitespace and replacing sequences of whitespace
67 * characters by a single space. Whitespace characters are the same as
68 * those allowed by the <a href="http://www.w3.org/TR/REC-xml#NT-S" target="_top">S</a>
69 * production in XML. If the argument is omitted, it defaults to the
70 * context node converted to a string, in other words the <a
71 * href="http://www.w3.org/TR/xpath#dt-string-value"
72 * target="_top">string-value</a> of the context node.
73 * </blockquote>
74 *
75 * @author James Strachan (james@metastuff.com)
76 * @see <a href="http://www.w3.org/TR/xpath#function-normalize-space"
77 * target="_top">Section 4.2 of the XPath Specification</a>
78 */
79 public class NormalizeSpaceFunction implements Function
80 {
81
82
83 /***
84 * Create a new <code>NormalizeSpaceFunction</code> object.
85 */
86 public NormalizeSpaceFunction() {}
87
88 /***
89 * Returns the string-value of the first item in <code>args</code>
90 * after removing all leading and trailing white space, and
91 * replacing each other sequence of whitespace by a single space.
92 * Whitespace consists of the characters space (0x32), carriage return (0x0D),
93 * linefeed (0x0A), and tab (0x09).
94 *
95 * @param context the context at the point in the
96 * expression when the function is called
97 * @param args a list that contains exactly one item
98 *
99 * @return a normalized <code>String</code>
100 *
101 * @throws FunctionCallException if <code>args</code> does not have length one
102 */
103 public Object call(Context context,
104 List args) throws FunctionCallException
105 {
106
107 if (args.size() == 0) {
108 return evaluate( context.getNodeSet(),
109 context.getNavigator() );
110 }
111 else if (args.size() == 1)
112 {
113 return evaluate( args.get(0),
114 context.getNavigator() );
115 }
116
117 throw new FunctionCallException( "normalize-space() cannot have more than one argument" );
118 }
119
120 /***
121 * Returns the string-value of <code>strArg</code> after removing
122 * all leading and trailing white space, and
123 * replacing each other sequence of whitespace by a single space.
124 * Whitespace consists of the characters space (0x32), carriage return (0x0D),
125 * linefeed (0x0A), and tab (0x09).
126 *
127 * @param strArg the object whose string-value is normalized
128 * @param nav the context at the point in the
129 * expression when the function is called
130 *
131 * @return the normalized string-value
132 */
133 public static String evaluate(Object strArg,
134 Navigator nav)
135 {
136 String str = StringFunction.evaluate( strArg,
137 nav );
138
139 char[] buffer = str.toCharArray();
140 int write = 0;
141 int lastWrite = 0;
142 boolean wroteOne = false;
143 int read = 0;
144 while (read < buffer.length)
145 {
146 if (isXMLSpace(buffer[read]))
147 {
148 if (wroteOne)
149 {
150 buffer[write++] = ' ';
151 }
152 do
153 {
154 read++;
155 }
156 while(read < buffer.length && isXMLSpace(buffer[read]));
157 }
158 else
159 {
160 buffer[write++] = buffer[read++];
161 wroteOne = true;
162 lastWrite = write;
163 }
164 }
165
166 return new String(buffer, 0, lastWrite);
167 }
168
169
170 private static boolean isXMLSpace(char c) {
171 return c == ' ' || c == '\n' || c == '\r' || c == '\t';
172 }
173
174 }