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

org.htmlunit.xpath.objects.XString Maven / Gradle / Ivy

There is a newer version: 4.7.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.htmlunit.xpath.objects;

import org.htmlunit.xpath.XPathVisitor;
import org.htmlunit.xpath.xml.utils.XMLCharacterRecognizer;

/**
 * This class represents an XPath string object, and is capable of converting the string to other
 * types, such as a number.
 */
public class XString extends XObject {

  /** Empty string XString object */
  public static final XString EMPTYSTRING = new XString("");

  /**
   * Construct a XNodeSet object.
   *
   * @param val String object this will wrap.
   */
  public XString(final String val) {
    super(val);
  }

  /** {@inheritDoc} */
  @Override
  public int getType() {
    return CLASS_STRING;
  }

  /** {@inheritDoc} */
  @Override
  public String getTypeString() {
    return "#STRING";
  }

  /**
   * Tell if this object contains a java String object.
   *
   * @return true if this XMLString can return a string without creating one.
   */
  public boolean hasString() {
    return true;
  }

  /** {@inheritDoc} */
  @Override
  public double num() {
    return toDouble();
  }

  /**
   * Convert a string to a double -- Allowed input is in fixed notation ddd.fff.
   *
   * @return A double value representation of the string, or return Double.NaN if the string can not
   *     be converted.
   */
  public double toDouble() {
    /*
     * XMLCharacterRecognizer.isWhiteSpace(char c) methods treats the following
     * characters as white space characters. ht - horizontal tab, nl - newline , cr
     * - carriage return and sp - space trim() methods by default also takes care of
     * these white space characters So trim() method is used to remove leading and
     * trailing white spaces.
     */
    final XString s = trim();
    double result = Double.NaN;
    for (int i = 0; i < s.length(); i++) {
      final char c = s.charAt(i);
      if (c != '-' && c != '.' && (c < 0X30 || c > 0x39)) {
        // The character is not a '-' or a '.' or a digit
        // then return NaN because something is wrong.
        return result;
      }
    }
    try {
      result = Double.parseDouble(s.toString());
    }
    catch (final NumberFormatException e) {
      // ignore
    }

    return result;
  }

  /** {@inheritDoc} */
  @Override
  public boolean bool() {
    return str().length() > 0;
  }

  /** {@inheritDoc} */
  @Override
  public XString xstr() {
    return this;
  }

  /** {@inheritDoc} */
  @Override
  public String str() {
    return (null != m_obj) ? ((String) m_obj) : "";
  }

  /**
   * Returns the length of this string.
   *
   * @return the length of the sequence of characters represented by this object.
   */
  public int length() {
    return str().length();
  }

  /**
   * Returns the character at the specified index. An index ranges from 0 to 
   * length() - 1. The first character of the sequence is at index 0, the next
   * at index 1, and so on, as for array indexing.
   *
   * @param index the index of the character.
   * @return the character at the specified index of this string. The first character is at index
   *     0.
   * @exception IndexOutOfBoundsException if the index argument is negative or not less
   *     than the length of this string.
   */
  public char charAt(final int index) {
    return str().charAt(index);
  }

  /**
   * Copies characters from this string into the destination character array.
   *
   * @param srcBegin index of the first character in the string to copy.
   * @param srcEnd index after the last character in the string to copy.
   * @param dst the destination array.
   * @param dstBegin the start offset in the destination array.
   * @exception IndexOutOfBoundsException If any of the following is true:
   *     
    *
  • srcBegin is negative. *
  • srcBegin is greater than srcEnd *
  • srcEnd is greater than the length of this string *
  • dstBegin is negative *
  • dstBegin+(srcEnd-srcBegin) is larger than dst.length *
* * @exception NullPointerException if dst is null */ public void getChars(final int srcBegin, final int srcEnd, final char[] dst, final int dstBegin) { str().getChars(srcBegin, srcEnd, dst, dstBegin); } /** {@inheritDoc} */ @Override public boolean equals(final XObject obj2) { // In order to handle the 'all' semantics of // nodeset comparisons, we always call the // nodeset function. final int t = obj2.getType(); try { if (XObject.CLASS_NODESET == t) { return obj2.equals(this); } // If at least one object to be compared is a boolean, then each object // to be compared is converted to a boolean as if by applying the // boolean function. else if (XObject.CLASS_BOOLEAN == t) { return obj2.bool() == bool(); } // Otherwise, if at least one object to be compared is a number, then each // object // to be compared is converted to a number as if by applying the number // function. else if (XObject.CLASS_NUMBER == t) { return obj2.num() == num(); } } catch (final javax.xml.transform.TransformerException te) { throw new org.htmlunit.xpath.xml.utils.WrappedRuntimeException(te); } // Otherwise, both objects to be compared are converted to strings as // if by applying the string function. return xstr().equals(obj2.xstr()); } /** * Compares this string to the specified String. The result is true if * and only if the argument is not null and is a String object that * represents the same sequence of characters as this object. * * @param obj2 the object to compare this String against. * @return true if the Strings are equal; false otherwise. * @see java.lang.String#compareTo(java.lang.String) * @see java.lang.String#equalsIgnoreCase(java.lang.String) */ public boolean equals(final String obj2) { return str().equals(obj2); } /** * Compares this string to the specified object. The result is true if and only if * the argument is not null and is a String object that represents the * same sequence of characters as this object. * * @param obj2 the object to compare this String against. * @return true if the String are equal; false otherwise. * @see java.lang.String#compareTo(java.lang.String) * @see java.lang.String#equalsIgnoreCase(java.lang.String) */ public boolean equals(final XString obj2) { if (obj2 != null) { if (!obj2.hasString()) { return obj2.equals(str()); } return str().equals(obj2.toString()); } return false; } /** {@inheritDoc} */ @Override public boolean equals(final Object obj2) { if (null == obj2) { return false; } // In order to handle the 'all' semantics of // nodeset comparisons, we always call the // nodeset function. else if (obj2 instanceof XNodeSet) { return obj2.equals(this); } else if (obj2 instanceof XNumber) { return obj2.equals(this); } else { return str().equals(obj2.toString()); } } /** * Tests if this string starts with the specified prefix beginning a specified index. * * @param prefix the prefix. * @param toffset where to begin looking in the string. * @return true if the character sequence represented by the argument is a prefix of * the substring of this object starting at index toffset; false * otherwise. The result is false if toffset is negative or * greater than the length of this String object; otherwise the result is the * same as the result of the expression *
   *         this.subString(toffset).startsWith(prefix)
   *         
* * @exception java.lang.NullPointerException if prefix is null. */ public boolean startsWith(final XString prefix, final int toffset) { int to = toffset; final int tlim = this.length(); int po = 0; int pc = prefix.length(); // Note: toffset might be near -1>>>1. if ((toffset < 0) || (toffset > tlim - pc)) { return false; } while (--pc >= 0) { if (this.charAt(to) != prefix.charAt(po)) { return false; } to++; po++; } return true; } /** * Tests if this string starts with the specified prefix. * * @param prefix the prefix. * @return true if the character sequence represented by the argument is a prefix of * the character sequence represented by this string; false otherwise. Note also * that true will be returned if the argument is an empty string or is equal to * this String object as determined by the {@link #equals(Object)} method. * @exception java.lang.NullPointerException if prefix is null. */ public boolean startsWith(final XString prefix) { return startsWith(prefix, 0); } /** * Returns the index within this string of the first occurrence of the specified substring. The * integer returned is the smallest value k such that: * *
* *
   * this.startsWith(str, k)
   * 
* *
* * is true. * * @param str any string. * @return if the string argument occurs as a substring within this object, then the index of the * first character of the first such substring is returned; if it does not occur as a * substring, -1 is returned. * @exception java.lang.NullPointerException if str is null. */ public int indexOf(final XString str) { return str().indexOf(str.toString()); } /** * Returns a new string that is a substring of this string. The substring begins with the * character at the specified index and extends to the end of this string. * *

Examples: * *

* *
   * "unhappy".substring(2) returns "happy"
   * "Harbison".substring(3) returns "bison"
   * "emptiness".substring(9) returns "" (an empty string)
   * 
* *
* * @param beginIndex the beginning index, inclusive. * @return the specified substring. * @exception IndexOutOfBoundsException if beginIndex is negative or larger than the * length of this String object. */ public XString substring(final int beginIndex) { return new XString(str().substring(beginIndex)); } /** * Returns a new string that is a substring of this string. The substring begins at the specified * beginIndex and extends to the character at index endIndex - 1 * . Thus the length of the substring is endIndex-beginIndex. * * @param beginIndex the beginning index, inclusive. * @param endIndex the ending index, exclusive. * @return the specified substring. * @exception IndexOutOfBoundsException if the beginIndex is negative, or * endIndex is larger than the length of this String object, or * beginIndex is larger than endIndex. */ public XString substring(final int beginIndex, final int endIndex) { return new XString(str().substring(beginIndex, endIndex)); } /** * Removes white space from both ends of this string. * * @return this string, with white space removed from the front and end. */ public XString trim() { return new XString(str().trim()); } /** * Returns whether the specified ch conforms to the XML 1.0 definition of whitespace. * Refer to the definition of S * for details. * * @param ch Character to check as XML whitespace. * @return =true if ch is XML whitespace; otherwise =false. */ private static boolean isSpace(final char ch) { return XMLCharacterRecognizer.isWhiteSpace(ch); // Take the easy way out for now. } /** * Conditionally trim all leading and trailing whitespace in the specified String. All strings of * white space are replaced by a single space character (#x20), except spaces after punctuation * which receive double spaces if doublePunctuationSpaces is true. This function may be useful to * a formatter, but to get first class results, the formatter should probably do it's own white * space handling based on the semantics of the formatting object. * * @param trimHead Trim leading whitespace? * @param trimTail Trim trailing whitespace? * @param doublePunctuationSpaces Use double spaces for punctuation? * @return The trimmed string. */ public XString fixWhiteSpace( final boolean trimHead, final boolean trimTail, final boolean doublePunctuationSpaces) { // %OPT% !!!!!!! final int len = this.length(); final char[] buf = new char[len]; this.getChars(0, len, buf, 0); boolean edit = false; int s; for (s = 0; s < len; s++) { if (isSpace(buf[s])) { break; } } /* replace S to ' '. and ' '+ -> single ' '. */ int d = s; boolean pres = false; for ( ; s < len; s++) { final char c = buf[s]; if (isSpace(c)) { if (!pres) { if (' ' != c) { edit = true; } buf[d++] = ' '; if (doublePunctuationSpaces && (s != 0)) { final char prevChar = buf[s - 1]; if (!((prevChar == '.') || (prevChar == '!') || (prevChar == '?'))) { pres = true; } } else { pres = true; } } else { edit = true; pres = true; } } else { buf[d++] = c; pres = false; } } if (trimTail && 1 <= d && ' ' == buf[d - 1]) { edit = true; d--; } int start = 0; if (trimHead && 0 < d && ' ' == buf[0]) { edit = true; start++; } return edit ? new XString(new String(buf, start, d - start)) : this; } /** {@inheritDoc} */ @Override public void callVisitors(final XPathVisitor visitor) { visitor.visitStringLiteral(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy