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

org.htmlunit.javascript.host.dom.XPathResult Maven / Gradle / Ivy

Go to download

XLT (Xceptance LoadTest) is an extensive load and performance test tool developed and maintained by Xceptance.

There is a newer version: 8.4.1
Show newest version
/*
 * Copyright (c) 2002-2024 Gargoyle Software Inc.
 *
 * Licensed 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
 * https://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.javascript.host.dom;

import static org.htmlunit.javascript.configuration.SupportedBrowser.CHROME;
import static org.htmlunit.javascript.configuration.SupportedBrowser.EDGE;
import static org.htmlunit.javascript.configuration.SupportedBrowser.FF;
import static org.htmlunit.javascript.configuration.SupportedBrowser.FF_ESR;

import java.util.List;

import org.htmlunit.html.DomAttr;
import org.htmlunit.html.DomNode;
import org.htmlunit.javascript.HtmlUnitScriptable;
import org.htmlunit.javascript.JavaScriptEngine;
import org.htmlunit.javascript.configuration.JsxClass;
import org.htmlunit.javascript.configuration.JsxConstant;
import org.htmlunit.javascript.configuration.JsxConstructor;
import org.htmlunit.javascript.configuration.JsxFunction;
import org.htmlunit.javascript.configuration.JsxGetter;

/**
 * A JavaScript object for {@code XPathResult}.
 *
 * @author Ahmed Ashour
 * @author Chuck Dumont
 * @author Ronald Brill
 */
@JsxClass({CHROME, EDGE, FF, FF_ESR})
public class XPathResult extends HtmlUnitScriptable {

    /**
     * This code does not represent a specific type.
     * An evaluation of an XPath expression will never produce this type. If this type is requested,
     * then the evaluation returns whatever type naturally results from evaluation of the expression.
     */
    @JsxConstant
    public static final int ANY_TYPE = 0;

    /**
     * The result is a number.
     */
    @JsxConstant
    public static final int NUMBER_TYPE = 1;

    /**
     * The result is a string.
     */
    @JsxConstant
    public static final int STRING_TYPE = 2;

    /**
     * The result is a boolean.
     */
    @JsxConstant
    public static final int BOOLEAN_TYPE = 3;

    /**
     * The result is a node set that will be accessed iteratively, which may not produce nodes in a particular order.
     * This is the default type returned if the result is a node set and {@link #ANY_TYPE} is requested.
     */
    @JsxConstant
    public static final int UNORDERED_NODE_ITERATOR_TYPE = 4;

    /**
     * The result is a node set that will be accessed iteratively, which will produce document-ordered nodes.
     */
    @JsxConstant
    public static final int ORDERED_NODE_ITERATOR_TYPE = 5;

    /**
     * The result is a node set that will be accessed as a snapshot list of nodes
     * that may not be in a particular order.
     */
    @JsxConstant
    public static final int UNORDERED_NODE_SNAPSHOT_TYPE = 6;

    /**
     * The result is a node set that will be accessed as a snapshot list of nodes
     * that will be in original document order.
     */
    @JsxConstant
    public static final int ORDERED_NODE_SNAPSHOT_TYPE = 7;

    /**
     * The result is a node set and will be accessed as a single node, which may be null if the node set is empty.
     * If there is more than one node in the actual result,
     * the single node returned might not be the first in document order.
     */
    @JsxConstant
    public static final int ANY_UNORDERED_NODE_TYPE = 8;

    /**
     * The result is a node set and will be accessed as a single node, which may be null if the node set is empty.
     * If there are more than one node in the actual result,
     * the single node returned will be the first in document order.
     */
    @JsxConstant
    public static final int FIRST_ORDERED_NODE_TYPE = 9;

    private List result_;
    private int resultType_;

    /**
     * The index of the next result.
     */
    private int iteratorIndex_;

    /**
     * Creates an instance.
     */
    public XPathResult() {
    }

    /**
     * Creates an instance.
     */
    @JsxConstructor
    public void jsConstructor() {
        throw JavaScriptEngine.reportRuntimeError("Illegal constructor.");
    }

    /**
     * @param result the evaluation result
     * @param type If a specific type is specified, then the result will be returned as the corresponding type
     */
    void init(final List result, final int type) {
        result_ = result;
        resultType_ = type;

        if (type == ANY_TYPE) {
            resultType_ = UNORDERED_NODE_ITERATOR_TYPE;

            if (result_.size() == 1) {
                final Object o = result_.get(0);
                if (o instanceof Number) {
                    resultType_ = NUMBER_TYPE;
                }
                else if (o instanceof String) {
                    resultType_ = STRING_TYPE;
                }
                else if (o instanceof Boolean) {
                    resultType_ = BOOLEAN_TYPE;
                }
            }
        }

        iteratorIndex_ = 0;
    }

    /**
     * The code representing the type of this result, as defined by the type constants.
     * @return the code representing the type of this result
     */
    @JsxGetter
    public int getResultType() {
        return resultType_;
    }

    /**
     * The number of nodes in the result snapshot.
     * @return the number of nodes in the result snapshot
     */
    @JsxGetter
    public int getSnapshotLength() {
        if (resultType_ != UNORDERED_NODE_SNAPSHOT_TYPE && resultType_ != ORDERED_NODE_SNAPSHOT_TYPE) {
            throw JavaScriptEngine.reportRuntimeError("Cannot get snapshotLength for type: " + resultType_);
        }
        return result_.size();
    }

    /**
     * The value of this single node result, which may be null.
     * @return the value of this single node result, which may be null
     */
    @JsxGetter
    public Node getSingleNodeValue() {
        if (resultType_ != ANY_UNORDERED_NODE_TYPE && resultType_ != FIRST_ORDERED_NODE_TYPE) {
            throw JavaScriptEngine.reportRuntimeError("Cannot get singleNodeValue for type: " + resultType_);
        }
        if (!result_.isEmpty()) {
            return ((DomNode) result_.get(0)).getScriptableObject();
        }
        return null;
    }

    /**
     * @return signifies that the iterator has become invalid.
     * It is true if XPathResult.resultType is UNORDERED_NODE_ITERATOR_TYPE or
     * ORDERED_NODE_ITERATOR_TYPE and the document has been modified since this result was returned.
     */
    @JsxGetter
    public boolean getInvalidIteratorState() {
        return false;
    }

    /**
     * Iterates and returns the next node from the node set or {@code null} if there are no more nodes.
     * @return the next node
     */
    @JsxFunction
    public Node iterateNext() {
        if (resultType_ != UNORDERED_NODE_ITERATOR_TYPE && resultType_ != ORDERED_NODE_ITERATOR_TYPE) {
            throw JavaScriptEngine.reportRuntimeError("Cannot get iterateNext for type: " + resultType_);
        }
        if (iteratorIndex_ < result_.size()) {
            return ((DomNode) result_.get(iteratorIndex_++)).getScriptableObject();
        }
        return null;
    }

    /**
     * Returns the indexth item in the snapshot collection.
     * If index is greater than or equal to the number of nodes in the list, this method returns null.
     * @param index Index into the snapshot collection
     * @return the node at the indexth position in the NodeList, or null if that is not a valid index
     */
    @JsxFunction
    public Node snapshotItem(final int index) {
        if (resultType_ != UNORDERED_NODE_SNAPSHOT_TYPE && resultType_ != ORDERED_NODE_SNAPSHOT_TYPE) {
            throw JavaScriptEngine.reportRuntimeError("Cannot get snapshotLength for type: " + resultType_);
        }
        if (index >= 0 && index < result_.size()) {
            return ((DomNode) result_.get(index)).getScriptableObject();
        }
        return null;
    }

    /**
     * Returns the value of this number result.
     * @return the value of this number result
     */
    @JsxGetter
    public double getNumberValue() {
        if (resultType_ != NUMBER_TYPE) {
            throw JavaScriptEngine.reportRuntimeError("Cannot get numberValue for type: " + resultType_);
        }

        if (result_.size() == 1) {
            final Object o = result_.get(0);
            if (o instanceof Number) {
                return ((Double) o).doubleValue();
            }
            if (o instanceof Boolean) {
                return ((Boolean) o).booleanValue() ? 1 : 0;
            }
        }

        final String asString = asString();
        double answer;
        try {
            answer = Double.parseDouble(asString);
        }
        catch (final NumberFormatException e) {
            answer = Double.NaN;
        }
        return answer;
    }

    /**
     * Returns the value of this boolean result.
     * @return the value of this boolean result
     */
    @JsxGetter
    public boolean getBooleanValue() {
        if (resultType_ != BOOLEAN_TYPE) {
            throw JavaScriptEngine.reportRuntimeError("Cannot get booleanValue for type: " + resultType_);
        }

        if (result_.size() == 1) {
            final Object o = result_.get(0);
            if (o instanceof Number) {
                final double d = ((Double) o).doubleValue();
                if (Double.isNaN(d) || Double.isInfinite(d)) {
                    return true;
                }

                return 0.0 != d;
            }
            if (o instanceof String) {
                return !((String) o).isEmpty();
            }
            if (o instanceof Boolean) {
                return ((Boolean) o).booleanValue();
            }
        }

        return result_.size() > 0;
    }

    /**
     * Returns the value of this string result.
     * @return the value of this string result
     */
    @JsxGetter
    public String getStringValue() {
        if (resultType_ != STRING_TYPE) {
            throw JavaScriptEngine.reportRuntimeError("Cannot get stringValue for type: " + resultType_);
        }
        return asString();
    }

    private String asString() {
        if (result_.size() < 1) {
            return "";
        }

        final Object resultObj = result_.get(0);
        if (resultObj instanceof DomAttr) {
            return ((DomAttr) resultObj).getValue();
        }
        if (resultObj instanceof DomNode) {
            return ((DomNode) resultObj).asNormalizedText();
        }
        return resultObj.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy