예제 #1
0
  /**
   * Compile a topLevel() method into the output class. This method is called from transform() to
   * handle all non-template top-level elements. Returns the signature of the topLevel() method.
   *
   * <p>Global variables/params and keys are first sorted to resolve dependencies between them. The
   * XSLT 1.0 spec does not allow a key to depend on a variable. However, for compatibility with
   * Xalan interpretive, that type of dependency is allowed. Note also that the buildKeys() method
   * is still generated as it is used by the LoadDocument class, but it no longer called from
   * transform().
   */
  private String compileTopLevel(ClassGenerator classGen) {

    final ConstantPoolGen cpg = classGen.getConstantPool();

    final com.sun.org.apache.bcel.internal.generic.Type[] argTypes = {
      Util.getJCRefType(DOM_INTF_SIG),
      Util.getJCRefType(NODE_ITERATOR_SIG),
      Util.getJCRefType(TRANSLET_OUTPUT_SIG)
    };

    final String[] argNames = {DOCUMENT_PNAME, ITERATOR_PNAME, TRANSLET_OUTPUT_PNAME};

    final InstructionList il = new InstructionList();

    final MethodGenerator toplevel =
        new MethodGenerator(
            ACC_PUBLIC,
            com.sun.org.apache.bcel.internal.generic.Type.VOID,
            argTypes,
            argNames,
            "topLevel",
            _className,
            il,
            classGen.getConstantPool());

    toplevel.addException("com.sun.org.apache.xalan.internal.xsltc.TransletException");

    // Define and initialize 'current' variable with the root node
    final LocalVariableGen current =
        toplevel.addLocalVariable(
            "current", com.sun.org.apache.bcel.internal.generic.Type.INT, null, null);

    final int setFilter =
        cpg.addInterfaceMethodref(
            DOM_INTF, "setFilter", "(Lcom/sun/org/apache/xalan/internal/xsltc/StripFilter;)V");

    final int gitr = cpg.addInterfaceMethodref(DOM_INTF, "getIterator", "()" + NODE_ITERATOR_SIG);
    il.append(toplevel.loadDOM());
    il.append(new INVOKEINTERFACE(gitr, 1));
    il.append(toplevel.nextNode());
    current.setStart(il.append(new ISTORE(current.getIndex())));

    // Create a new list containing variables/params + keys
    Vector varDepElements = new Vector(_globals);
    Enumeration elements = elements();
    while (elements.hasMoreElements()) {
      final Object element = elements.nextElement();
      if (element instanceof Key) {
        varDepElements.add(element);
      }
    }

    // Determine a partial order for the variables/params and keys
    varDepElements = resolveDependencies(varDepElements);

    // Translate vars/params and keys in the right order
    final int count = varDepElements.size();
    for (int i = 0; i < count; i++) {
      final TopLevelElement tle = (TopLevelElement) varDepElements.elementAt(i);
      tle.translate(classGen, toplevel);
      if (tle instanceof Key) {
        final Key key = (Key) tle;
        _keys.put(key.getName(), key);
      }
    }

    // Compile code for other top-level elements
    Vector whitespaceRules = new Vector();
    elements = elements();
    while (elements.hasMoreElements()) {
      final Object element = elements.nextElement();
      // xsl:decimal-format
      if (element instanceof DecimalFormatting) {
        ((DecimalFormatting) element).translate(classGen, toplevel);
      }
      // xsl:strip/preserve-space
      else if (element instanceof Whitespace) {
        whitespaceRules.addAll(((Whitespace) element).getRules());
      }
    }

    // Translate all whitespace strip/preserve rules
    if (whitespaceRules.size() > 0) {
      Whitespace.translateRules(whitespaceRules, classGen);
    }

    if (classGen.containsMethod(STRIP_SPACE, STRIP_SPACE_PARAMS) != null) {
      il.append(toplevel.loadDOM());
      il.append(classGen.loadTranslet());
      il.append(new INVOKEINTERFACE(setFilter, 2));
    }

    il.append(RETURN);

    // Compute max locals + stack and add method to class
    classGen.addMethod(toplevel);

    return ("(" + DOM_INTF_SIG + NODE_ITERATOR_SIG + TRANSLET_OUTPUT_SIG + ")V");
  }
예제 #2
0
  /**
   * Factory method: create a dateTime value from a supplied string, in ISO 8601 format
   *
   * @param s a string in the lexical space of xs:dateTime
   * @return either a DateTimeValue representing the xs:dateTime supplied, or a ValidationFailure if
   *     the lexical value was invalid
   */
  public static ConversionResult makeDateTimeValue(CharSequence s) {
    // input must have format [-]yyyy-mm-ddThh:mm:ss[.fff*][([+|-]hh:mm | Z)]
    DateTimeValue dt = new DateTimeValue();
    StringTokenizer tok =
        new StringTokenizer(Whitespace.trimWhitespace(s).toString(), "-:.+TZ", true);

    if (!tok.hasMoreElements()) {
      return badDate("too short", s);
    }
    String part = (String) tok.nextElement();
    int era = +1;
    if ("+".equals(part)) {
      return badDate("Date must not start with '+' sign", s);
    } else if ("-".equals(part)) {
      era = -1;
      if (!tok.hasMoreElements()) {
        return badDate("No year after '-'", s);
      }
      part = (String) tok.nextElement();
    }
    int value = DurationValue.simpleInteger(part);
    if (value < 0) {
      return badDate("Non-numeric year component", s);
    }
    dt.year = value * era;
    if (part.length() < 4) {
      return badDate("Year is less than four digits", s);
    }
    if (part.length() > 4 && part.charAt(0) == '0') {
      return badDate("When year exceeds 4 digits, leading zeroes are not allowed", s);
    }
    if (dt.year == 0) {
      return badDate("Year zero is not allowed", s);
    }
    if (era < 0) {
      dt.year++; // internal representation allows a year zero.
    }
    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    if (!"-".equals(tok.nextElement())) {
      return badDate("Wrong delimiter after year", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    part = (String) tok.nextElement();
    if (part.length() != 2) {
      return badDate("Month must be two digits", s);
    }
    value = DurationValue.simpleInteger(part);
    if (value < 0) {
      return badDate("Non-numeric month component", s);
    }
    dt.month = (byte) value;
    if (dt.month < 1 || dt.month > 12) {
      return badDate("Month is out of range", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    if (!"-".equals(tok.nextElement())) {
      return badDate("Wrong delimiter after month", s);
    }
    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    part = (String) tok.nextElement();
    if (part.length() != 2) {
      return badDate("Day must be two digits", s);
    }
    value = DurationValue.simpleInteger(part);
    if (value < 0) {
      return badDate("Non-numeric day component", s);
    }
    dt.day = (byte) value;
    if (dt.day < 1 || dt.day > 31) {
      return badDate("Day is out of range", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    if (!"T".equals(tok.nextElement())) {
      return badDate("Wrong delimiter after day", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    part = (String) tok.nextElement();
    if (part.length() != 2) {
      return badDate("Hour must be two digits", s);
    }
    value = DurationValue.simpleInteger(part);
    if (value < 0) {
      return badDate("Non-numeric hour component", s);
    }
    dt.hour = (byte) value;
    if (dt.hour > 24) {
      return badDate("Hour is out of range", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    if (!":".equals(tok.nextElement())) {
      return badDate("Wrong delimiter after hour", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    part = (String) tok.nextElement();
    if (part.length() != 2) {
      return badDate("Minute must be two digits", s);
    }
    value = DurationValue.simpleInteger(part);
    if (value < 0) {
      return badDate("Non-numeric minute component", s);
    }
    dt.minute = (byte) value;
    if (dt.minute > 59) {
      return badDate("Minute is out of range", s);
    }
    if (dt.hour == 24 && dt.minute != 0) {
      return badDate("If hour is 24, minute must be 00", s);
    }
    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    if (!":".equals(tok.nextElement())) {
      return badDate("Wrong delimiter after minute", s);
    }

    if (!tok.hasMoreElements()) {
      return badDate("Too short", s);
    }
    part = (String) tok.nextElement();
    if (part.length() != 2) {
      return badDate("Second must be two digits", s);
    }
    value = DurationValue.simpleInteger(part);
    if (value < 0) {
      return badDate("Non-numeric second component", s);
    }
    dt.second = (byte) value;

    if (dt.second > 59) {
      return badDate("Second is out of range", s);
    }
    if (dt.hour == 24 && dt.second != 0) {
      return badDate("If hour is 24, second must be 00", s);
    }

    int tz = 0;

    int state = 0;
    while (tok.hasMoreElements()) {
      if (state == 9) {
        return badDate("Characters after the end", s);
      }
      String delim = (String) tok.nextElement();
      if (".".equals(delim)) {
        if (state != 0) {
          return badDate("Decimal separator occurs twice", s);
        }
        if (!tok.hasMoreElements()) {
          return badDate("Decimal point must be followed by digits", s);
        }
        part = (String) tok.nextElement();
        value = DurationValue.simpleInteger(part);
        if (value < 0) {
          return badDate("Non-numeric fractional seconds component", s);
        }
        double fractionalSeconds = Double.parseDouble('.' + part);
        dt.microsecond = (int) (Math.round(fractionalSeconds * 1000000));
        if (dt.hour == 24 && dt.microsecond != 0) {
          return badDate("If hour is 24, fractional seconds must be 0", s);
        }
        state = 1;
      } else if ("Z".equals(delim)) {
        if (state > 1) {
          return badDate("Z cannot occur here", s);
        }
        tz = 0;
        state = 9; // we've finished
        dt.setTimezoneInMinutes(0);
      } else if ("+".equals(delim) || "-".equals(delim)) {
        if (state > 1) {
          return badDate(delim + " cannot occur here", s);
        }
        state = 2;
        if (!tok.hasMoreElements()) {
          return badDate("Missing timezone", s);
        }
        part = (String) tok.nextElement();
        if (part.length() != 2) {
          return badDate("Timezone hour must be two digits", s);
        }
        value = DurationValue.simpleInteger(part);
        if (value < 0) {
          return badDate("Non-numeric timezone hour component", s);
        }
        tz = value;
        if (tz > 14) {
          return badDate("Timezone is out of range (-14:00 to +14:00)", s);
        }
        tz *= 60;

        if ("-".equals(delim)) {
          tz = -tz;
        }

      } else if (":".equals(delim)) {
        if (state != 2) {
          return badDate("Misplaced ':'", s);
        }
        state = 9;
        part = (String) tok.nextElement();
        value = DurationValue.simpleInteger(part);
        if (value < 0) {
          return badDate("Non-numeric timezone minute component", s);
        }
        int tzminute = value;
        if (part.length() != 2) {
          return badDate("Timezone minute must be two digits", s);
        }
        if (tzminute > 59) {
          return badDate("Timezone minute is out of range", s);
        }
        if (tz < 0) {
          tzminute = -tzminute;
        }
        if (Math.abs(tz) == 14 * 60 && tzminute != 0) {
          return badDate("Timezone is out of range (-14:00 to +14:00)", s);
        }
        tz += tzminute;
        dt.setTimezoneInMinutes(tz);
      } else {
        return badDate("Timezone format is incorrect", s);
      }
    }

    if (state == 2 || state == 3) {
      return badDate("Timezone incomplete", s);
    }

    boolean midnight = false;
    if (dt.hour == 24) {
      dt.hour = 0;
      midnight = true;
    }

    // Check that this is a valid calendar date
    if (!DateValue.isValidDate(dt.year, dt.month, dt.day)) {
      return badDate("Non-existent date", s);
    }

    // Adjust midnight to 00:00:00 on the next day
    if (midnight) {
      DateValue t = DateValue.tomorrow(dt.year, dt.month, dt.day);
      dt.year = t.getYear();
      dt.month = t.getMonth();
      dt.day = t.getDay();
    }

    dt.typeLabel = BuiltInAtomicType.DATE_TIME;
    return dt;
  }