KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xpath > objects > XStringForFSB


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
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 /*
17  * $Id: XStringForFSB.java,v 1.20 2004/02/17 04:34:38 minchau Exp $
18  */

19 package org.apache.xpath.objects;
20
21 import org.apache.xalan.res.XSLMessages;
22 import org.apache.xml.utils.FastStringBuffer;
23 import org.apache.xml.utils.XMLCharacterRecognizer;
24 import org.apache.xml.utils.XMLString;
25 import org.apache.xml.utils.XMLStringFactory;
26 import org.apache.xpath.res.XPATHErrorResources;
27
28 /**
29  * This class will wrap a FastStringBuffer and allow for
30  */

31 public class XStringForFSB extends XString
32 {
33
34   /** The start position in the fsb. */
35   int m_start;
36
37   /** The length of the string. */
38   int m_length;
39
40   /** If the str() function is called, the string will be cached here. */
41   protected String JavaDoc m_strCache = null;
42
43   /** cached hash code */
44   protected int m_hash = 0;
45
46   /**
47    * Construct a XNodeSet object.
48    *
49    * @param val FastStringBuffer object this will wrap, must be non-null.
50    * @param start The start position in the array.
51    * @param length The number of characters to read from the array.
52    */

53   public XStringForFSB(FastStringBuffer val, int start, int length)
54   {
55
56     super(val);
57
58     m_start = start;
59     m_length = length;
60
61     if (null == val)
62       throw new IllegalArgumentException JavaDoc(
63         XSLMessages.createXPATHMessage(XPATHErrorResources.ER_FASTSTRINGBUFFER_CANNOT_BE_NULL, null));
64   }
65
66   /**
67    * Construct a XNodeSet object.
68    *
69    * @param val String object this will wrap.
70    */

71   private XStringForFSB(String JavaDoc val)
72   {
73
74     super(val);
75
76     throw new IllegalArgumentException JavaDoc(
77       XSLMessages.createXPATHMessage(XPATHErrorResources.ER_FSB_CANNOT_TAKE_STRING, null)); // "XStringForFSB can not take a string for an argument!");
78
}
79
80   /**
81    * Cast result object to a string.
82    *
83    * @return The string this wraps or the empty string if null
84    */

85   public FastStringBuffer fsb()
86   {
87     return ((FastStringBuffer) m_obj);
88   }
89   
90   /**
91    * Cast result object to a string.
92    *
93    * @return The string this wraps or the empty string if null
94    */

95   public void appendToFsb(org.apache.xml.utils.FastStringBuffer fsb)
96   {
97     // %OPT% !!! FSB has to be updated to take partial fsb's for append.
98
fsb.append(str());
99   }
100
101   /**
102    * Tell if this object contains a java String object.
103    *
104    * @return true if this XMLString can return a string without creating one.
105    */

106   public boolean hasString()
107   {
108     return (null != m_strCache);
109   }
110
111 // /** NEEDSDOC Field strCount */
112
// public static int strCount = 0;
113
//
114
// /** NEEDSDOC Field xtable */
115
// static java.util.Hashtable xtable = new java.util.Hashtable();
116

117   /**
118    * Since this object is incomplete without the length and the offset, we
119    * have to convert to a string when this function is called.
120    *
121    * @return The java String representation of this object.
122    */

123   public Object JavaDoc object()
124   {
125     return str();
126   }
127
128   /**
129    * Cast result object to a string.
130    *
131    * @return The string this wraps or the empty string if null
132    */

133   public String JavaDoc str()
134   {
135
136     if (null == m_strCache)
137     {
138       m_strCache = fsb().getString(m_start, m_length);
139
140 // strCount++;
141
//
142
// RuntimeException e = new RuntimeException("Bad! Bad!");
143
// java.io.CharArrayWriter writer = new java.io.CharArrayWriter();
144
// java.io.PrintWriter pw = new java.io.PrintWriter(writer);
145
//
146
// e.printStackTrace(pw);
147
//
148
// String str = writer.toString();
149
//
150
// str = str.substring(0, 600);
151
//
152
// if (null == xtable.get(str))
153
// {
154
// xtable.put(str, str);
155
// System.out.println(str);
156
// }
157
// System.out.println("strCount: " + strCount);
158

159 // throw e;
160
// e.printStackTrace();
161
// System.exit(-1);
162
}
163
164     return m_strCache;
165   }
166
167   /**
168    * Directly call the
169    * characters method on the passed ContentHandler for the
170    * string-value. Multiple calls to the
171    * ContentHandler's characters methods may well occur for a single call to
172    * this method.
173    *
174    * @param ch A non-null reference to a ContentHandler.
175    *
176    * @throws org.xml.sax.SAXException
177    */

178   public void dispatchCharactersEvents(org.xml.sax.ContentHandler JavaDoc ch)
179           throws org.xml.sax.SAXException JavaDoc
180   {
181     fsb().sendSAXcharacters(ch, m_start, m_length);
182   }
183
184   /**
185    * Directly call the
186    * comment method on the passed LexicalHandler for the
187    * string-value.
188    *
189    * @param lh A non-null reference to a LexicalHandler.
190    *
191    * @throws org.xml.sax.SAXException
192    */

193   public void dispatchAsComment(org.xml.sax.ext.LexicalHandler JavaDoc lh)
194           throws org.xml.sax.SAXException JavaDoc
195   {
196     fsb().sendSAXComment(lh, m_start, m_length);
197   }
198
199   /**
200    * Returns the length of this string.
201    *
202    * @return the length of the sequence of characters represented by this
203    * object.
204    */

205   public int length()
206   {
207     return m_length;
208   }
209
210   /**
211    * Returns the character at the specified index. An index ranges
212    * from <code>0</code> to <code>length() - 1</code>. The first character
213    * of the sequence is at index <code>0</code>, the next at index
214    * <code>1</code>, and so on, as for array indexing.
215    *
216    * @param index the index of the character.
217    * @return the character at the specified index of this string.
218    * The first character is at index <code>0</code>.
219    * @exception IndexOutOfBoundsException if the <code>index</code>
220    * argument is negative or not less than the length of this
221    * string.
222    */

223   public char charAt(int index)
224   {
225     return fsb().charAt(m_start + index);
226   }
227
228   /**
229    * Copies characters from this string into the destination character
230    * array.
231    *
232    * @param srcBegin index of the first character in the string
233    * to copy.
234    * @param srcEnd index after the last character in the string
235    * to copy.
236    * @param dst the destination array.
237    * @param dstBegin the start offset in the destination array.
238    * @exception IndexOutOfBoundsException If any of the following
239    * is true:
240    * <ul><li><code>srcBegin</code> is negative.
241    * <li><code>srcBegin</code> is greater than <code>srcEnd</code>
242    * <li><code>srcEnd</code> is greater than the length of this
243    * string
244    * <li><code>dstBegin</code> is negative
245    * <li><code>dstBegin+(srcEnd-srcBegin)</code> is larger than
246    * <code>dst.length</code></ul>
247    * @exception NullPointerException if <code>dst</code> is <code>null</code>
248    */

249   public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)
250   {
251
252     // %OPT% Need to call this on FSB when it is implemented.
253
// %UNTESTED% (I don't think anyone calls this yet?)
254
int n = srcEnd - srcBegin;
255
256     if (n > m_length)
257       n = m_length;
258
259     if (n > (dst.length - dstBegin))
260       n = (dst.length - dstBegin);
261
262     int end = srcBegin + m_start + n;
263     int d = dstBegin;
264     FastStringBuffer fsb = fsb();
265
266     for (int i = srcBegin + m_start; i < end; i++)
267     {
268       dst[d++] = fsb.charAt(i);
269     }
270   }
271
272   /**
273    * Compares this string to the specified object.
274    * The result is <code>true</code> if and only if the argument is not
275    * <code>null</code> and is a <code>String</code> object that represents
276    * the same sequence of characters as this object.
277    *
278    * @param anObject the object to compare this <code>String</code>
279    * against.
280    *
281    * NEEDSDOC @param obj2
282    * @return <code>true</code> if the <code>String </code>are equal;
283    * <code>false</code> otherwise.
284    * @see java.lang.String#compareTo(java.lang.String)
285    * @see java.lang.String#equalsIgnoreCase(java.lang.String)
286    */

287   public boolean equals(XMLString obj2)
288   {
289
290     if (this == obj2)
291     {
292       return true;
293     }
294
295     int n = m_length;
296
297     if (n == obj2.length())
298     {
299       FastStringBuffer fsb = fsb();
300       int i = m_start;
301       int j = 0;
302
303       while (n-- != 0)
304       {
305         if (fsb.charAt(i) != obj2.charAt(j))
306         {
307           return false;
308         }
309
310         i++;
311         j++;
312       }
313
314       return true;
315     }
316
317     return false;
318   }
319
320   /**
321    * Tell if two objects are functionally equal.
322    *
323    * @param obj2 Object to compare this to
324    *
325    * @return true if the two objects are equal
326    *
327    * @throws javax.xml.transform.TransformerException
328    */

329   public boolean equals(XObject obj2)
330   {
331
332     if (this == obj2)
333     {
334       return true;
335     }
336     if(obj2.getType() == XObject.CLASS_NUMBER)
337         return obj2.equals(this);
338
339     String JavaDoc str = obj2.str();
340     int n = m_length;
341
342     if (n == str.length())
343     {
344       FastStringBuffer fsb = fsb();
345       int i = m_start;
346       int j = 0;
347
348       while (n-- != 0)
349       {
350         if (fsb.charAt(i) != str.charAt(j))
351         {
352           return false;
353         }
354
355         i++;
356         j++;
357       }
358
359       return true;
360     }
361
362     return false;
363   }
364
365   /**
366    * Tell if two objects are functionally equal.
367    *
368    * @param obj2 Object to compare this to
369    *
370    * NEEDSDOC @param anotherString
371    *
372    * @return true if the two objects are equal
373    *
374    * @throws javax.xml.transform.TransformerException
375    */

376   public boolean equals(String JavaDoc anotherString)
377   {
378
379     int n = m_length;
380
381     if (n == anotherString.length())
382     {
383       FastStringBuffer fsb = fsb();
384       int i = m_start;
385       int j = 0;
386
387       while (n-- != 0)
388       {
389         if (fsb.charAt(i) != anotherString.charAt(j))
390         {
391           return false;
392         }
393
394         i++;
395         j++;
396       }
397
398       return true;
399     }
400
401     return false;
402   }
403
404   /**
405    * Compares this string to the specified object.
406    * The result is <code>true</code> if and only if the argument is not
407    * <code>null</code> and is a <code>String</code> object that represents
408    * the same sequence of characters as this object.
409    *
410    * @param anObject the object to compare this <code>String</code>
411    * against.
412    *
413    * NEEDSDOC @param obj2
414    * @return <code>true</code> if the <code>String </code>are equal;
415    * <code>false</code> otherwise.
416    * @see java.lang.String#compareTo(java.lang.String)
417    * @see java.lang.String#equalsIgnoreCase(java.lang.String)
418    */

419   public boolean equals(Object JavaDoc obj2)
420   {
421
422     if (null == obj2)
423       return false;
424       
425     if(obj2 instanceof XNumber)
426         return obj2.equals(this);
427
428       // In order to handle the 'all' semantics of
429
// nodeset comparisons, we always call the
430
// nodeset function.
431
else if (obj2 instanceof XNodeSet)
432       return obj2.equals(this);
433     else if (obj2 instanceof XStringForFSB)
434       return equals((XMLString) this);
435     else
436       return equals(obj2.toString());
437   }
438
439   /**
440    * Compares this <code>String</code> to another <code>String</code>,
441    * ignoring case considerations. Two strings are considered equal
442    * ignoring case if they are of the same length, and corresponding
443    * characters in the two strings are equal ignoring case.
444    *
445    * @param anotherString the <code>String</code> to compare this
446    * <code>String</code> against.
447    * @return <code>true</code> if the argument is not <code>null</code>
448    * and the <code>String</code>s are equal,
449    * ignoring case; <code>false</code> otherwise.
450    * @see #equals(Object)
451    * @see java.lang.Character#toLowerCase(char)
452    * @see java.lang.Character#toUpperCase(char)
453    */

454   public boolean equalsIgnoreCase(String JavaDoc anotherString)
455   {
456     return (m_length == anotherString.length())
457            ? str().equalsIgnoreCase(anotherString) : false;
458   }
459
460   /**
461    * Compares two strings lexicographically.
462    *
463    * @param anotherString the <code>String</code> to be compared.
464    *
465    * NEEDSDOC @param xstr
466    * @return the value <code>0</code> if the argument string is equal to
467    * this string; a value less than <code>0</code> if this string
468    * is lexicographically less than the string argument; and a
469    * value greater than <code>0</code> if this string is
470    * lexicographically greater than the string argument.
471    * @exception java.lang.NullPointerException if <code>anotherString</code>
472    * is <code>null</code>.
473    */

474   public int compareTo(XMLString xstr)
475   {
476
477     int len1 = m_length;
478     int len2 = xstr.length();
479     int n = Math.min(len1, len2);
480     FastStringBuffer fsb = fsb();
481     int i = m_start;
482     int j = 0;
483
484     while (n-- != 0)
485     {
486       char c1 = fsb.charAt(i);
487       char c2 = xstr.charAt(j);
488
489       if (c1 != c2)
490       {
491         return c1 - c2;
492       }
493
494       i++;
495       j++;
496     }
497
498     return len1 - len2;
499   }
500
501   /**
502    * Compares two strings lexicographically, ignoring case considerations.
503    * This method returns an integer whose sign is that of
504    * <code>this.toUpperCase().toLowerCase().compareTo(
505    * str.toUpperCase().toLowerCase())</code>.
506    * <p>
507    * Note that this method does <em>not</em> take locale into account,
508    * and will result in an unsatisfactory ordering for certain locales.
509    * The java.text package provides <em>collators</em> to allow
510    * locale-sensitive ordering.
511    *
512    * @param str the <code>String</code> to be compared.
513    *
514    * NEEDSDOC @param xstr
515    * @return a negative integer, zero, or a positive integer as the
516    * the specified String is greater than, equal to, or less
517    * than this String, ignoring case considerations.
518    * @see java.text.Collator#compare(String, String)
519    * @since 1.2
520    */

521   public int compareToIgnoreCase(XMLString xstr)
522   {
523
524     int len1 = m_length;
525     int len2 = xstr.length();
526     int n = Math.min(len1, len2);
527     FastStringBuffer fsb = fsb();
528     int i = m_start;
529     int j = 0;
530
531     while (n-- != 0)
532     {
533       char c1 = Character.toLowerCase(fsb.charAt(i));
534       char c2 = Character.toLowerCase(xstr.charAt(j));
535
536       if (c1 != c2)
537       {
538         return c1 - c2;
539       }
540
541       i++;
542       j++;
543     }
544
545     return len1 - len2;
546   }
547
548   /**
549    * Returns a hashcode for this string. The hashcode for a
550    * <code>String</code> object is computed as
551    * <blockquote><pre>
552    * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
553    * </pre></blockquote>
554    * using <code>int</code> arithmetic, where <code>s[i]</code> is the
555    * <i>i</i>th character of the string, <code>n</code> is the length of
556    * the string, and <code>^</code> indicates exponentiation.
557    * (The hash value of the empty string is zero.)
558    *
559    * @return a hash code value for this object.
560    */

561   public int hashCode()
562   {
563     // Commenting this out because in JDK1.1.8 and VJ++
564
// we don't match XMLStrings. Defaulting to the super
565
// causes us to create a string, but at this point
566
// this only seems to get called in key processing.
567
// Maybe we can live with it?
568

569 /*
570     int h = m_hash;
571
572     if (h == 0)
573     {
574       int off = m_start;
575       int len = m_length;
576       FastStringBuffer fsb = fsb();
577
578       for (int i = 0; i < len; i++)
579       {
580         h = 31 * h + fsb.charAt(off);
581
582         off++;
583       }
584
585       m_hash = h;
586     }
587     */

588
589     return super.hashCode(); // h;
590
}
591
592   /**
593    * Tests if this string starts with the specified prefix beginning
594    * a specified index.
595    *
596    * @param prefix the prefix.
597    * @param toffset where to begin looking in the string.
598    * @return <code>true</code> if the character sequence represented by the
599    * argument is a prefix of the substring of this object starting
600    * at index <code>toffset</code>; <code>false</code> otherwise.
601    * The result is <code>false</code> if <code>toffset</code> is
602    * negative or greater than the length of this
603    * <code>String</code> object; otherwise the result is the same
604    * as the result of the expression
605    * <pre>
606    * this.subString(toffset).startsWith(prefix)
607    * </pre>
608    * @exception java.lang.NullPointerException if <code>prefix</code> is
609    * <code>null</code>.
610    */

611   public boolean startsWith(XMLString prefix, int toffset)
612   {
613
614     FastStringBuffer fsb = fsb();
615     int to = m_start + toffset;
616     int tlim = m_start + m_length;
617     int po = 0;
618     int pc = prefix.length();
619
620     // Note: toffset might be near -1>>>1.
621
if ((toffset < 0) || (toffset > m_length - pc))
622     {
623       return false;
624     }
625
626     while (--pc >= 0)
627     {
628       if (fsb.charAt(to) != prefix.charAt(po))
629       {
630         return false;
631       }
632
633       to++;
634       po++;
635     }
636
637     return true;
638   }
639
640   /**
641    * Tests if this string starts with the specified prefix.
642    *
643    * @param prefix the prefix.
644    * @return <code>true</code> if the character sequence represented by the
645    * argument is a prefix of the character sequence represented by
646    * this string; <code>false</code> otherwise.
647    * Note also that <code>true</code> will be returned if the
648    * argument is an empty string or is equal to this
649    * <code>String</code> object as determined by the
650    * {@link #equals(Object)} method.
651    * @exception java.lang.NullPointerException if <code>prefix</code> is
652    * <code>null</code>.
653    * @since JDK1. 0
654    */

655   public boolean startsWith(XMLString prefix)
656   {
657     return startsWith(prefix, 0);
658   }
659
660   /**
661    * Returns the index within this string of the first occurrence of the
662    * specified character. If a character with value <code>ch</code> occurs
663    * in the character sequence represented by this <code>String</code>
664    * object, then the index of the first such occurrence is returned --
665    * that is, the smallest value <i>k</i> such that:
666    * <blockquote><pre>
667    * this.charAt(<i>k</i>) == ch
668    * </pre></blockquote>
669    * is <code>true</code>. If no such character occurs in this string,
670    * then <code>-1</code> is returned.
671    *
672    * @param ch a character.
673    * @return the index of the first occurrence of the character in the
674    * character sequence represented by this object, or
675    * <code>-1</code> if the character does not occur.
676    */

677   public int indexOf(int ch)
678   {
679     return indexOf(ch, 0);
680   }
681
682   /**
683    * Returns the index within this string of the first occurrence of the
684    * specified character, starting the search at the specified index.
685    * <p>
686    * If a character with value <code>ch</code> occurs in the character
687    * sequence represented by this <code>String</code> object at an index
688    * no smaller than <code>fromIndex</code>, then the index of the first
689    * such occurrence is returned--that is, the smallest value <i>k</i>
690    * such that:
691    * <blockquote><pre>
692    * (this.charAt(<i>k</i>) == ch) && (<i>k</i> >= fromIndex)
693    * </pre></blockquote>
694    * is true. If no such character occurs in this string at or after
695    * position <code>fromIndex</code>, then <code>-1</code> is returned.
696    * <p>
697    * There is no restriction on the value of <code>fromIndex</code>. If it
698    * is negative, it has the same effect as if it were zero: this entire
699    * string may be searched. If it is greater than the length of this
700    * string, it has the same effect as if it were equal to the length of
701    * this string: <code>-1</code> is returned.
702    *
703    * @param ch a character.
704    * @param fromIndex the index to start the search from.
705    * @return the index of the first occurrence of the character in the
706    * character sequence represented by this object that is greater
707    * than or equal to <code>fromIndex</code>, or <code>-1</code>
708    * if the character does not occur.
709    */

710   public int indexOf(int ch, int fromIndex)
711   {
712
713     int max = m_start + m_length;
714     FastStringBuffer fsb = fsb();
715
716     if (fromIndex < 0)
717     {
718       fromIndex = 0;
719     }
720     else if (fromIndex >= m_length)
721     {
722
723       // Note: fromIndex might be near -1>>>1.
724
return -1;
725     }
726
727     for (int i = m_start + fromIndex; i < max; i++)
728     {
729       if (fsb.charAt(i) == ch)
730       {
731         return i - m_start;
732       }
733     }
734
735     return -1;
736   }
737
738   /**
739    * Returns a new string that is a substring of this string. The
740    * substring begins with the character at the specified index and
741    * extends to the end of this string. <p>
742    * Examples:
743    * <blockquote><pre>
744    * "unhappy".substring(2) returns "happy"
745    * "Harbison".substring(3) returns "bison"
746    * "emptiness".substring(9) returns "" (an empty string)
747    * </pre></blockquote>
748    *
749    * @param beginIndex the beginning index, inclusive.
750    * @return the specified substring.
751    * @exception IndexOutOfBoundsException if
752    * <code>beginIndex</code> is negative or larger than the
753    * length of this <code>String</code> object.
754    */

755   public XMLString substring(int beginIndex)
756   {
757
758     int len = m_length - beginIndex;
759
760     if (len <= 0)
761       return XString.EMPTYSTRING;
762     else
763     {
764       int start = m_start + beginIndex;
765
766       return new XStringForFSB(fsb(), start, len);
767     }
768   }
769
770   /**
771    * Returns a new string that is a substring of this string. The
772    * substring begins at the specified <code>beginIndex</code> and
773    * extends to the character at index <code>endIndex - 1</code>.
774    * Thus the length of the substring is <code>endIndex-beginIndex</code>.
775    *
776    * @param beginIndex the beginning index, inclusive.
777    * @param endIndex the ending index, exclusive.
778    * @return the specified substring.
779    * @exception IndexOutOfBoundsException if the
780    * <code>beginIndex</code> is negative, or
781    * <code>endIndex</code> is larger than the length of
782    * this <code>String</code> object, or
783    * <code>beginIndex</code> is larger than
784    * <code>endIndex</code>.
785    */

786   public XMLString substring(int beginIndex, int endIndex)
787   {
788
789     int len = endIndex - beginIndex;
790
791     if (len > m_length)
792       len = m_length;
793
794     if (len <= 0)
795       return XString.EMPTYSTRING;
796     else
797     {
798       int start = m_start + beginIndex;
799
800       return new XStringForFSB(fsb(), start, len);
801     }
802   }
803
804   /**
805    * Concatenates the specified string to the end of this string.
806    *
807    * @param str the <code>String</code> that is concatenated to the end
808    * of this <code>String</code>.
809    * @return a string that represents the concatenation of this object's
810    * characters followed by the string argument's characters.
811    * @exception java.lang.NullPointerException if <code>str</code> is
812    * <code>null</code>.
813    */

814   public XMLString concat(String JavaDoc str)
815   {
816
817     // %OPT% Make an FSB here?
818
return new XString(str().concat(str));
819   }
820
821   /**
822    * Removes white space from both ends of this string.
823    *
824    * @return this string, with white space removed from the front and end.
825    */

826   public XMLString trim()
827   {
828     return fixWhiteSpace(true, true, false);
829   }
830
831   /**
832    * Returns whether the specified <var>ch</var> conforms to the XML 1.0 definition
833    * of whitespace. Refer to <A HREF="http://www.w3.org/TR/1998/REC-xml-19980210#NT-S">
834    * the definition of <CODE>S</CODE></A> for details.
835    * @param ch Character to check as XML whitespace.
836    * @return =true if <var>ch</var> is XML whitespace; otherwise =false.
837    */

838   private static boolean isSpace(char ch)
839   {
840     return XMLCharacterRecognizer.isWhiteSpace(ch); // Take the easy way out for now.
841
}
842
843   /**
844    * Conditionally trim all leading and trailing whitespace in the specified String.
845    * All strings of white space are
846    * replaced by a single space character (#x20), except spaces after punctuation which
847    * receive double spaces if doublePunctuationSpaces is true.
848    * This function may be useful to a formatter, but to get first class
849    * results, the formatter should probably do it's own white space handling
850    * based on the semantics of the formatting object.
851    *
852    * @param trimHead Trim leading whitespace?
853    * @param trimTail Trim trailing whitespace?
854    * @param doublePunctuationSpaces Use double spaces for punctuation?
855    * @return The trimmed string.
856    */

857   public XMLString fixWhiteSpace(boolean trimHead, boolean trimTail,
858                                  boolean doublePunctuationSpaces)
859   {
860
861     int end = m_length + m_start;
862     char[] buf = new char[m_length];
863     FastStringBuffer fsb = fsb();
864     boolean edit = false;
865
866     /* replace S to ' '. and ' '+ -> single ' '. */
867     int d = 0;
868     boolean pres = false;
869
870     for (int s = m_start; s < end; s++)
871     {
872       char c = fsb.charAt(s);
873
874       if (isSpace(c))
875       {
876         if (!pres)
877         {
878           if (' ' != c)
879           {
880             edit = true;
881           }
882
883           buf[d++] = ' ';
884
885           if (doublePunctuationSpaces && (d != 0))
886           {
887             char prevChar = buf[d - 1];
888
889             if (!((prevChar == '.') || (prevChar == '!')
890                   || (prevChar == '?')))
891             {
892               pres = true;
893             }
894           }
895           else
896           {
897             pres = true;
898           }
899         }
900         else
901         {
902           edit = true;
903           pres = true;
904         }
905       }
906       else
907       {
908         buf[d++] = c;
909         pres = false;
910       }
911     }
912
913     if (trimTail && 1 <= d && ' ' == buf[d - 1])
914     {
915       edit = true;
916
917       d--;
918     }
919
920     int start = 0;
921
922     if (trimHead && 0 < d && ' ' == buf[0])
923     {
924       edit = true;
925
926       start++;
927     }
928
929     XMLStringFactory xsf = XMLStringFactoryImpl.getFactory();
930
931     return edit ? xsf.newstr(buf, start, d - start) : this;
932   }
933
934   /**
935    * Convert a string to a double -- Allowed input is in fixed
936    * notation ddd.fff.
937    *
938    * %OPT% CHECK PERFORMANCE against generating a Java String and
939    * converting it to double. The advantage of running in native
940    * machine code -- perhaps even microcode, on some systems -- may
941    * more than make up for the cost of allocating and discarding the
942    * additional object. We need to benchmark this.
943    *
944    * %OPT% More importantly, we need to decide whether we _care_ about
945    * the performance of this operation. Does XString.toDouble constitute
946    * any measurable percentage of our typical runtime? I suspect not!
947    *
948    * @return A double value representation of the string, or return Double.NaN
949    * if the string can not be converted. */

950   public double toDouble()
951   {
952     if(m_length == 0)
953       return Double.NaN;
954     int i;
955     char c;
956     String JavaDoc valueString = fsb().getString(m_start,m_length);
957     
958     // The following are permitted in the Double.valueOf, but not by the XPath spec:
959
// - a plus sign
960
// - The use of e or E to indicate exponents
961
// - trailing f, F, d, or D
962
// See function comments; not sure if this is slower than actually doing the
963
// conversion ourselves (as was before).
964

965     for (i=0;i<m_length;i++)
966       if (!XMLCharacterRecognizer.isWhiteSpace(valueString.charAt(i)))
967         break;
968     if (valueString.charAt(i) == '-')
969       i++;
970     for (;i<m_length;i++) {
971       c = valueString.charAt(i);
972       if (c != '.' && (c < '0' || c > '9'))
973         break;
974     }
975     for (;i<m_length;i++)
976       if (!XMLCharacterRecognizer.isWhiteSpace(valueString.charAt(i)))
977         break;
978     if (i != m_length)
979       return Double.NaN;
980         
981     try {
982       return new Double JavaDoc(valueString).doubleValue();
983     } catch (NumberFormatException JavaDoc nfe) {
984       // This should catch double periods, empty strings.
985
return Double.NaN;
986     }
987   }
988 }
989
Popular Tags