blob: 9c0e7f58f2928441814afc07c79a8c89fdd0956f [file] [log] [blame]
/*
* Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
* Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "third_party/blink/renderer/core/xml/xpath_result.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/xml/xpath_evaluator.h"
#include "third_party/blink/renderer/core/xml/xpath_expression_node.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
XPathResult::XPathResult(xpath::EvaluationContext& context,
const xpath::Value& value)
: value_(value), node_set_position_(0), dom_tree_version_(0) {
switch (value_.GetType()) {
case xpath::Value::kBooleanValue:
result_type_ = kBooleanType;
return;
case xpath::Value::kNumberValue:
result_type_ = kNumberType;
return;
case xpath::Value::kStringValue:
result_type_ = kStringType;
return;
case xpath::Value::kNodeSetValue:
result_type_ = kUnorderedNodeIteratorType;
node_set_position_ = 0;
node_set_ = xpath::NodeSet::Create(value_.ToNodeSet(&context));
document_ = &context.node->GetDocument();
dom_tree_version_ = document_->DomTreeVersion();
return;
}
NOTREACHED();
}
void XPathResult::Trace(Visitor* visitor) const {
visitor->Trace(value_);
visitor->Trace(node_set_);
visitor->Trace(document_);
ScriptWrappable::Trace(visitor);
}
void XPathResult::ConvertTo(uint16_t type, ExceptionState& exception_state) {
switch (type) {
case kAnyType:
break;
case kNumberType:
result_type_ = type;
value_ = value_.ToNumber();
break;
case kStringType:
result_type_ = type;
value_ = value_.ToString();
break;
case kBooleanType:
result_type_ = type;
value_ = value_.ToBoolean();
break;
case kUnorderedNodeIteratorType:
case kUnorderedNodeSnapshotType:
case kAnyUnorderedNodeType:
// This is correct - singleNodeValue() will take care of ordering.
case kFirstOrderedNodeType:
if (!value_.IsNodeSet()) {
exception_state.ThrowTypeError(
"The result is not a node set, and therefore cannot be converted "
"to the desired type.");
return;
}
result_type_ = type;
break;
case kOrderedNodeIteratorType:
if (!value_.IsNodeSet()) {
exception_state.ThrowTypeError(
"The result is not a node set, and therefore cannot be converted "
"to the desired type.");
return;
}
GetNodeSet().Sort();
result_type_ = type;
break;
case kOrderedNodeSnapshotType:
if (!value_.IsNodeSet()) {
exception_state.ThrowTypeError(
"The result is not a node set, and therefore cannot be converted "
"to the desired type.");
return;
}
value_.ToNodeSet(nullptr).Sort();
result_type_ = type;
break;
}
}
uint16_t XPathResult::resultType() const {
return result_type_;
}
double XPathResult::numberValue(ExceptionState& exception_state) const {
if (resultType() != kNumberType) {
exception_state.ThrowTypeError("The result type is not a number.");
return 0.0;
}
return value_.ToNumber();
}
String XPathResult::stringValue(ExceptionState& exception_state) const {
if (resultType() != kStringType) {
exception_state.ThrowTypeError("The result type is not a string.");
return String();
}
return value_.ToString();
}
bool XPathResult::booleanValue(ExceptionState& exception_state) const {
if (resultType() != kBooleanType) {
exception_state.ThrowTypeError("The result type is not a boolean.");
return false;
}
return value_.ToBoolean();
}
Node* XPathResult::singleNodeValue(ExceptionState& exception_state) const {
if (resultType() != kAnyUnorderedNodeType &&
resultType() != kFirstOrderedNodeType) {
exception_state.ThrowTypeError("The result type is not a single node.");
return nullptr;
}
const xpath::NodeSet& nodes = value_.ToNodeSet(nullptr);
if (resultType() == kFirstOrderedNodeType)
return nodes.FirstNode();
return nodes.AnyNode();
}
bool XPathResult::invalidIteratorState() const {
if (resultType() != kUnorderedNodeIteratorType &&
resultType() != kOrderedNodeIteratorType)
return false;
DCHECK(document_);
return document_->DomTreeVersion() != dom_tree_version_;
}
unsigned XPathResult::snapshotLength(ExceptionState& exception_state) const {
if (resultType() != kUnorderedNodeSnapshotType &&
resultType() != kOrderedNodeSnapshotType) {
exception_state.ThrowTypeError("The result type is not a snapshot.");
return 0;
}
return value_.ToNodeSet(nullptr).size();
}
Node* XPathResult::iterateNext(ExceptionState& exception_state) {
if (resultType() != kUnorderedNodeIteratorType &&
resultType() != kOrderedNodeIteratorType) {
exception_state.ThrowTypeError("The result type is not an iterator.");
return nullptr;
}
if (invalidIteratorState()) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"The document has mutated since the result was returned.");
return nullptr;
}
if (node_set_position_ + 1 > GetNodeSet().size())
return nullptr;
Node* node = GetNodeSet()[node_set_position_];
node_set_position_++;
return node;
}
Node* XPathResult::snapshotItem(unsigned index,
ExceptionState& exception_state) {
if (resultType() != kUnorderedNodeSnapshotType &&
resultType() != kOrderedNodeSnapshotType) {
exception_state.ThrowTypeError("The result type is not a snapshot.");
return nullptr;
}
const xpath::NodeSet& nodes = value_.ToNodeSet(nullptr);
if (index >= nodes.size())
return nullptr;
return nodes[index];
}
} // namespace blink