コード例 #1
0
  /**
   * Get simple node number. This is defined as one plus the number of previous siblings of the same
   * node type and name. It is not accessible directly in XSL.
   *
   * @param node The node whose number is required
   * @param controller Used for remembering previous result, for performance
   * @exception XPathException if any error occurs
   * @return the node number, as defined above
   */
  public static int getNumberSimple(NodeInfo node, Controller controller) throws XPathException {

    // checkNumberable(node);

    int fingerprint = node.getFingerprint();
    NodeTest same;

    if (fingerprint == -1) {
      same = NodeKindTest.makeNodeKindTest(node.getNodeKind());
    } else {
      same = new NameTest(node);
    }

    SequenceIterator preceding = node.iterateAxis(Axis.PRECEDING_SIBLING, same);

    int i = 1;
    while (true) {
      NodeInfo prev = (NodeInfo) preceding.next();
      if (prev == null) {
        break;
      }

      int memo = controller.getRememberedNumber(prev);
      if (memo > 0) {
        memo += i;
        controller.setRememberedNumber(node, memo);
        return memo;
      }

      i++;
    }

    controller.setRememberedNumber(node, i);
    return i;
  }
コード例 #2
0
ファイル: XQueryExpression.java プロジェクト: orbeon/saxon
 /**
  * Execute the compiled Query, returning the first item in the result. This is useful where it is
  * known that the expression will only return a singleton value (for example, a single node, or a
  * boolean).
  *
  * @param env Provides the dynamic query evaluation context
  * @return The first item in the sequence returned by the expression. If the expression returns an
  *     empty sequence, this method returns null. Otherwise, it returns the first item in the
  *     result sequence, represented as a Java object using the same mapping as for the {@link
  *     XQueryExpression#evaluate evaluate} method
  */
 public Object evaluateSingle(DynamicQueryContext env) throws XPathException {
   if (isUpdating) {
     throw new XPathException("Cannot call evaluateSingle() on an updating query");
   }
   SequenceIterator iterator = iterator(env);
   Item item = iterator.next();
   if (item == null) {
     return null;
   }
   return Value.convertToJava(item);
 }
コード例 #3
0
ファイル: XQueryExpression.java プロジェクト: orbeon/saxon
 public Item next() throws XPathException {
   try {
     return base.next();
   } catch (XPathException e1) {
     e1.maybeSetLocation(expression);
     try {
       listener.fatalError(e1);
     } catch (TransformerException e2) {
       //
     }
     e1.setHasBeenReported();
     throw e1;
   }
 }
コード例 #4
0
ファイル: XQueryExpression.java プロジェクト: orbeon/saxon
 /**
  * Execute a the compiled Query, returning the results as a List.
  *
  * @param env Provides the dynamic query evaluation context
  * @return The results of the expression, as a List. The List represents the sequence of items
  *     returned by the expression. Each item in the list will either be an object representing a
  *     node, or an object representing an atomic value. For the types of Java object that may be
  *     returned, see the description of the {@link org.orbeon.saxon.xpath.XPathEvaluator#evaluate
  *     evaluate} method of class XPathProcessor
  */
 public List evaluate(DynamicQueryContext env) throws XPathException {
   if (isUpdating) {
     throw new XPathException("Cannot call evaluate() on an updating query");
   }
   SequenceIterator iterator = iterator(env);
   ArrayList list = new ArrayList(100);
   while (true) {
     Item item = iterator.next();
     if (item == null) {
       return list;
     }
     list.add(Value.convertToJava(item));
   }
 }
コード例 #5
0
ファイル: QueryAPIExamples.java プロジェクト: jchalex/xcat
  /**
   * Show a query producing a sequence as its result and returning the sequence to the Java
   * application in the form of an iterator. For each item in the result, its string value is
   * output.
   */
  public static void exampleToSequence() throws XPathException {
    final Configuration config = new Configuration();
    final StaticQueryContext sqc = config.newStaticQueryContext();
    final XQueryExpression exp = sqc.compileQuery("for $i in 1 to 10 return ($i * $i)");

    final DynamicQueryContext dynamicContext = new DynamicQueryContext(config);
    final SequenceIterator iter = exp.iterator(dynamicContext);
    while (true) {
      Item item = iter.next();
      if (item == null) {
        break;
      }
      System.out.println(item.getStringValue());
    }
  }
コード例 #6
0
  /**
   * Get node number (level="single"). If the current node matches the supplied pattern, the
   * returned number is one plus the number of previous siblings that match the pattern. Otherwise,
   * return the element number of the nearest ancestor that matches the supplied pattern.
   *
   * @param node the current node, the one whose node number is required
   * @param count Pattern that identifies which nodes should be counted. Default (null) is the
   *     element name if the current node is an element, or "node()" otherwise.
   * @param from Pattern that specifies where counting starts from. Default (null) is the root node.
   *     (This parameter does not seem useful but is included for the sake of XSLT conformance.)
   * @param controller the controller of the transformation, used if the patterns reference context
   *     values (e.g. variables)
   * @exception XPathException when any error occurs in processing
   * @return the node number established as follows: go to the nearest ancestor-or-self that matches
   *     the 'count' pattern and that is a descendant of the nearest ancestor that matches the
   *     'from' pattern. Return one plus the nunber of preceding siblings of that ancestor that
   *     match the 'count' pattern. If there is no such ancestor, return 0.
   */
  public static int getNumberSingle(
      NodeInfo node, Pattern count, Pattern from, Controller controller) throws XPathException {

    //        checkNumberable(node);

    if (count == null && from == null) {
      return getNumberSimple(node, controller);
    }

    boolean knownToMatch = false;
    if (count == null) {
      if (node.getFingerprint() == -1) { // unnamed node
        count = NodeKindTest.makeNodeKindTest(node.getNodeKind());
      } else {
        count = new NameTest(node);
      }
      knownToMatch = true;
    }

    NodeInfo target = node;
    while (!(knownToMatch || count.matches(target, controller))) {
      target = target.getParent();
      if (target == null) {
        return 0;
      }
      if (from != null && from.matches(target, controller)) {
        return 0;
      }
    }

    // we've found the ancestor to count from

    SequenceIterator preceding = target.iterateAxis(Axis.PRECEDING_SIBLING, count.getNodeTest());
    // pass the filter condition down to the axis enumeration where possible
    boolean alreadyChecked = (count instanceof NodeTest);
    int i = 1;
    while (true) {
      NodeInfo p = (NodeInfo) preceding.next();
      if (p == null) {
        return i;
      }
      if (alreadyChecked || count.matches(p, controller)) {
        i++;
      }
    }
  }
  /**
   * Convert an XPath value to an object in this object model. If the supplied value can be
   * converted to an object in this model, of the specified class, then the conversion should be
   * done and the resulting object returned. If the value cannot be converted, the method should
   * return null. Note that the supplied class might be a List, in which case the method should
   * inspect the contents of the Value to see whether they belong to this object model.
   *
   * @throws XPathException if the target class is explicitly associated with this object model, but
   *     the supplied value cannot be converted to the appropriate class
   */
  public Object convertXPathValueToObject(Value value, Class target, XPathContext context)
      throws XPathException {
    // We accept the object if (a) the target class is Node, Node[], or NodeList,
    // or (b) the supplied object is a node, or sequence of nodes, that wrap DOM nodes,
    // provided that the target class is Object or a collection class
    boolean requireDOM =
        (Node.class.isAssignableFrom(target)
            || (target == NodeList.class)
            || (target.isArray() && Node.class.isAssignableFrom(target.getComponentType())));

    // Note: we allow the declared type of the method argument to be a subclass of Node. If the
    // actual
    // node supplied is the wrong kind of node, this will result in a Java exception.

    boolean allowDOM =
        (target == Object.class
            || target.isAssignableFrom(ArrayList.class)
            || target.isAssignableFrom(HashSet.class)
            || (target.isArray() && target.getComponentType() == Object.class));
    if (!(requireDOM || allowDOM)) {
      return null;
    }
    List nodes = new ArrayList(20);

    SequenceIterator iter = value.iterate(context);
    while (true) {
      Item item = iter.next();
      if (item == null) {
        break;
      }
      if (item instanceof VirtualNode) {
        Object o = ((VirtualNode) item).getUnderlyingNode();
        if (o instanceof Node) {
          nodes.add(o);
        } else {
          if (requireDOM) {
            DynamicError err =
                new DynamicError(
                    "Extension function required class "
                        + target.getName()
                        + "; supplied value of class "
                        + item.getClass().getName()
                        + " could not be converted");
            throw err;
          }
          ;
        }
      } else if (requireDOM) {
        if (item instanceof NodeInfo) {
          nodes.add(NodeOverNodeInfo.wrap((NodeInfo) item));
        } else {
          DynamicError err =
              new DynamicError(
                  "Extension function required class "
                      + target.getName()
                      + "; supplied value of class "
                      + item.getClass().getName()
                      + " could not be converted");
          throw err;
        }
      } else {
        return null; // DOM Nodes are not actually required; let someone else try the conversion
      }
    }

    if (nodes.size() == 0 && !requireDOM) {
      return null; // empty sequence supplied - try a different mapping
    }
    if (Node.class.isAssignableFrom(target)) {
      if (nodes.size() != 1) {
        DynamicError err =
            new DynamicError(
                "Extension function requires a single DOM Node"
                    + "; supplied value contains "
                    + nodes.size()
                    + " nodes");
        throw err;
      }
      return nodes.get(0);
      // could fail if the node is of the wrong kind
    } else if (target == NodeList.class) {
      return new DOMNodeList(nodes);
    } else if (target.isArray() && target.getComponentType() == Node.class) {
      Node[] array = new Node[nodes.size()];
      nodes.toArray(array);
      return array;
    } else if (target.isAssignableFrom(ArrayList.class)) {
      return nodes;
    } else if (target.isAssignableFrom(HashSet.class)) {
      return new HashSet(nodes);
    } else {
      // after all this work, give up
      return null;
    }
  }
コード例 #8
0
ファイル: DocumentInstr.java プロジェクト: orbeon/saxon
  /** Evaluate as an expression. */
  public Item evaluateItem(XPathContext context) throws XPathException {
    if (isLazyConstruction()
        && (context.getConfiguration().areAllNodesUntyped()
            || (validation == Validation.PRESERVE && getSchemaType() == null))) {
      return new UnconstructedDocument(this, context);
    } else {
      Controller controller = context.getController();
      DocumentInfo root;
      if (textOnly) {
        CharSequence textValue;
        if (constantText != null) {
          textValue = constantText;
        } else {
          FastStringBuffer sb = new FastStringBuffer(100);
          SequenceIterator iter = content.iterate(context);
          while (true) {
            Item item = iter.next();
            if (item == null) break;
            sb.append(item.getStringValueCS());
          }
          textValue = sb.condense();
        }
        root = new TextFragmentValue(textValue, getBaseURI());
        ((TextFragmentValue) root).setConfiguration(controller.getConfiguration());
      } else {
        try {
          XPathContext c2 = context.newMinorContext();
          c2.setOrigin(this);

          Builder builder = controller.makeBuilder();
          // builder.setSizeParameters(treeSizeParameters);
          builder.setLineNumbering(controller.getConfiguration().isLineNumbering());

          // receiver.setSystemId(getBaseURI());
          builder.setBaseURI(getBaseURI());
          builder.setTiming(false);

          PipelineConfiguration pipe = controller.makePipelineConfiguration();
          pipe.setHostLanguage(getHostLanguage());
          // pipe.setBaseURI(baseURI);
          builder.setPipelineConfiguration(pipe);

          c2.changeOutputDestination(
              null, builder, false, getHostLanguage(), validation, getSchemaType());
          Receiver out = c2.getReceiver();
          out.open();
          out.startDocument(0);

          content.process(c2);

          out.endDocument();
          out.close();

          root = (DocumentInfo) builder.getCurrentRoot();
        } catch (XPathException e) {
          e.maybeSetLocation(this);
          e.maybeSetContext(context);
          throw e;
        }
      }
      return root;
    }
  }
コード例 #9
0
  /**
   * Get node number (level="any"). Return one plus the number of previous nodes in the document
   * that match the supplied pattern
   *
   * @exception XPathException
   * @param inst Identifies the xsl:number instruction; this is relevant when the function is
   *     memoised to support repeated use of the same instruction to number modulple nodes
   * @param node Identifies the xsl:number instruction; this is relevant when the function is
   *     memoised to support repeated use of the same instruction to number modulple nodes
   * @param count Pattern that identifies which nodes should be counted. Default (null) is the
   *     element name if the current node is an element, or "node()" otherwise.
   * @param from Pattern that specifies where counting starts from. Default (null) is the root node.
   *     Only nodes after the first (most recent) node that matches the 'from' pattern are counted.
   * @param controller The controller
   * @param hasVariablesInPatterns if the count or from patterns contain variables, then it's not
   *     safe to get the answer by adding one to the number of the most recent node that matches
   * @return one plus the number of nodes that precede the current node, that match the count
   *     pattern, and that follow the first node that matches the from pattern if specified.
   */
  public static int getNumberAny(
      Instruction inst,
      NodeInfo node,
      Pattern count,
      Pattern from,
      Controller controller,
      boolean hasVariablesInPatterns)
      throws XPathException {

    NodeInfo memoNode = null;
    int memoNumber = 0;
    boolean memoise = (!hasVariablesInPatterns && count != null);
    if (memoise) {
      Object[] memo = (Object[]) controller.getUserData(inst, "xsl:number");
      if (memo != null) {
        memoNode = (NodeInfo) memo[0];
        memoNumber = ((Integer) memo[1]).intValue();
      }
    }

    int num = 0;
    if (count == null) {
      if (node.getFingerprint() == -1) { // unnamed node
        count = NodeKindTest.makeNodeKindTest(node.getNodeKind());
      } else {
        count = new NameTest(node);
      }
      num = 1;
    } else if (count.matches(node, controller)) {
      num = 1;
    }

    // We use a special axis invented for the purpose: the union of the preceding and
    // ancestor axes, but in reverse document order

    // Pass part of the filtering down to the axis iterator if possible
    NodeTest filter;
    if (from == null) {
      filter = count.getNodeTest();
    } else if (from.getNodeKind() == Type.ELEMENT && count.getNodeKind() == Type.ELEMENT) {
      filter = NodeKindTest.ELEMENT;
    } else {
      filter = AnyNodeTest.getInstance();
    }

    SequenceIterator preceding = node.iterateAxis(Axis.PRECEDING_OR_ANCESTOR, filter);

    while (true) {
      NodeInfo prev = (NodeInfo) preceding.next();
      if (prev == null) {
        break;
      }
      if (from != null && from.matches(prev, controller)) {
        return num;
      }
      if (count.matches(prev, controller)) {
        if (num == 1 && memoNode != null && prev.isSameNode(memoNode)) {
          num = memoNumber + 1;
          break;
        }
        num++;
      }
    }
    if (memoise) {
      Object[] memo = new Object[2];
      memo[0] = node;
      memo[1] = new Integer(num);
      controller.setUserData(inst, "xsl:number", memo);
    }
    return num;
  }