• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KHTML

  • khtml
  • xpath
predicate.cpp
Go to the documentation of this file.
1/*
2 * predicate.cc - Copyright 2005 Frerich Raabe <raabe@kde.org>
3 * Copyright 2010 Maksim Orlovich <maksim@kde.org>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26#include "predicate.h"
27#include "functions.h"
28
29#include <QString>
30
31#include "xml/dom_nodeimpl.h"
32#include "xml/dom_nodelistimpl.h"
33#include "kjs/operations.h"
34#include "kjs/value.h"
35
36#include <math.h>
37
38using namespace DOM;
39using namespace khtml;
40using namespace khtml::XPath;
41
42Number::Number( double value )
43 : m_value( value )
44{
45}
46
47bool Number::isConstant() const
48{
49 return true;
50}
51
52QString Number::dump() const
53{
54 return "<number>" + QString::number( m_value ) + "</number>";
55}
56
57Value Number::doEvaluate() const
58{
59 return Value( m_value );
60}
61
62String::String( const DOMString &value )
63 : m_value( value )
64{
65}
66
67bool String::isConstant() const
68{
69 return true;
70}
71
72QString String::dump() const
73{
74 return "<string>" + m_value.string() + "</string>";
75}
76
77Value String::doEvaluate() const
78{
79 return Value( m_value );
80}
81
82Value Negative::doEvaluate() const
83{
84 Value p( subExpr( 0 )->evaluate() );
85 return Value( -p.toNumber() );
86}
87
88QString Negative::dump() const
89{
90 return "<negative>" + subExpr( 0 )->dump() + "</number>";
91}
92
93QString BinaryExprBase::dump() const
94{
95 QString s = "<" + opName() + ">";
96 s += "<operand>" + subExpr( 0 )->dump() + "</operand>";
97 s += "<operand>" + subExpr( 1 )->dump() + "</operand>";
98 s += "</" + opName() + ">";
99 return s;
100}
101
102NumericOp::NumericOp( int _opCode, Expression* lhs, Expression* rhs ) :
103 opCode( _opCode )
104{
105 addSubExpression( lhs );
106 addSubExpression( rhs );
107}
108
109Value NumericOp::doEvaluate() const
110{
111 Value lhs( subExpr( 0 )->evaluate() );
112 Value rhs( subExpr( 1 )->evaluate() );
113 double leftVal = lhs.toNumber(), rightVal = rhs.toNumber();
114
115 switch (opCode) {
116 case OP_Add:
117 return Value( leftVal + rightVal );
118 case OP_Sub:
119 return Value( leftVal - rightVal );
120 case OP_Mul:
121 return Value( leftVal * rightVal );
122 case OP_Div:
123 if ( rightVal == 0.0 || rightVal == -0.0 ) {
124 if ( leftVal == 0.0 || leftVal == -0.0) {
125 return Value(); // 0/0 = NaN
126 } else {
127 // +/- Infinity.
128 if (signbit(leftVal) == signbit(rightVal))
129 return Value( KJS::Inf );
130 else
131 return Value( -KJS::Inf );
132 }
133 } else {
134 return Value( leftVal / rightVal );
135 }
136 case OP_Mod:
137 if ( rightVal == 0.0 || rightVal == -0.0 )
138 return Value(); //Divide by 0;
139 else
140 return Value( remainder( leftVal, rightVal ) );
141 default:
142 assert(0);
143 return Value();
144 }
145}
146
147QString NumericOp::opName() const
148{
149 switch (opCode) {
150 case OP_Add:
151 return QLatin1String( "addition" );
152 case OP_Sub:
153 return QLatin1String( "subtraction" );
154 case OP_Mul:
155 return QLatin1String( "multiplication" );
156 case OP_Div:
157 return QLatin1String( "division" );
158 case OP_Mod:
159 return QLatin1String( "modulo" );
160 default:
161 assert(0);
162 return QString();
163 }
164}
165
166RelationOp::RelationOp( int _opCode, Expression* lhs, Expression* rhs ) :
167 opCode( _opCode )
168{
169 addSubExpression( lhs );
170 addSubExpression( rhs );
171}
172
173static void stringify(const Value& val, WTF::Vector<DOMString>* out)
174{
175 if (val.isString()) {
176 out->append(val.toString());
177 } else {
178 assert(val.isNodeset());
179
180 const DomNodeList& set = val.toNodeset();
181 for (unsigned long i = 0; i < set->length(); ++i) {
182 DOM::DOMString stringVal = stringValue(set->item(i));
183 out->append(stringVal);
184 }
185 }
186}
187
188static void numify(const Value& val, WTF::Vector<double>* out)
189{
190 if (val.isNumber()) {
191 out->append(val.toNumber());
192 } else {
193 assert(val.isNodeset());
194
195 const DomNodeList& set = val.toNodeset();
196 for (unsigned long i = 0; i < set->length(); ++i) {
197 DOM::DOMString stringVal = stringValue(set->item(i));
198 out->append(Value(stringVal).toNumber());
199 }
200 }
201}
202
203Value RelationOp::doEvaluate() const
204{
205 Value lhs( subExpr( 0 )->evaluate() );
206 Value rhs( subExpr( 1 )->evaluate() );
207
208 if (lhs.isNodeset() || rhs.isNodeset())
209 {
210 // If both are nodesets, or one is a string our
211 // comparisons are based on strings.
212 if ((lhs.isNodeset() && rhs.isNodeset()) ||
213 (lhs.isString() || rhs.isString())) {
214
215 WTF::Vector<DOM::DOMString> leftStrings;
216 WTF::Vector<DOM::DOMString> rightStrings;
217
218 stringify(lhs, &leftStrings);
219 stringify(rhs, &rightStrings);
220
221 for (unsigned pl = 0; pl < leftStrings.size(); ++pl) {
222 for (unsigned pr = 0; pr < rightStrings.size(); ++pr) {
223 if (compareStrings(leftStrings[pl], rightStrings[pr]))
224 return Value(true);
225 } // pr
226 } // pl
227 return Value(false);
228 }
229
230 // If one is a number, we do a number-based comparison
231 if (lhs.isNumber() || rhs.isNumber()) {
232 WTF::Vector<double> leftNums;
233 WTF::Vector<double> rightNums;
234
235 numify(lhs, &leftNums);
236 numify(rhs, &rightNums);
237
238 for (unsigned pl = 0; pl < leftNums.size(); ++pl) {
239 for (unsigned pr = 0; pr < rightNums.size(); ++pr) {
240 if (compareNumbers(leftNums[pl], rightNums[pr]))
241 return Value(true);
242 } // pr
243 } // pl
244 return Value(false);
245 }
246
247 // Has to be a boolean-based comparison.
248 // These ones are simpler, since we just convert the nodeset to a bool
249 assert(lhs.isBoolean() || rhs.isBoolean());
250
251 if (lhs.isNodeset())
252 lhs = Value(lhs.toBoolean());
253 else
254 rhs = Value(rhs.toBoolean());
255 } // nodeset comparisons
256
257
258 if (opCode == OP_EQ || opCode == OP_NE) {
259 bool equal;
260 if ( lhs.isBoolean() || rhs.isBoolean() ) {
261 equal = ( lhs.toBoolean() == rhs.toBoolean() );
262 } else if ( lhs.isNumber() || rhs.isNumber() ) {
263 equal = ( lhs.toNumber() == rhs.toNumber() );
264 } else {
265 equal = ( lhs.toString() == rhs.toString() );
266 }
267
268 if ( opCode == OP_EQ )
269 return Value( equal );
270 else
271 return Value( !equal );
272
273 }
274
275 // For other ops, we always convert to numbers
276 double leftVal = lhs.toNumber(), rightVal = rhs.toNumber();
277 return Value(compareNumbers(leftVal, rightVal));
278}
279
280
281bool RelationOp::compareNumbers(double leftVal, double rightVal) const
282{
283 switch (opCode) {
284 case OP_GT:
285 return leftVal > rightVal;
286 case OP_GE:
287 return leftVal >= rightVal;
288 case OP_LT:
289 return leftVal < rightVal;
290 case OP_LE:
291 return leftVal <= rightVal;
292 case OP_EQ:
293 return leftVal == rightVal;
294 case OP_NE:
295 return leftVal != rightVal;
296 default:
297 assert(0);
298 return false;
299 }
300}
301
302bool RelationOp::compareStrings(const DOM::DOMString& l, const DOM::DOMString& r) const
303{
304 // String comparisons, as invoked within the nodeset case, are string-based
305 // only for == and !=. Everything else still goes to numbers.
306 if (opCode == OP_EQ)
307 return (l == r);
308 if (opCode == OP_NE)
309 return (l != r);
310
311 return compareNumbers(Value(l).toNumber(), Value(r).toNumber());
312}
313
314QString RelationOp::opName() const
315{
316 switch (opCode) {
317 case OP_GT:
318 return QLatin1String( "relationGT" );
319 case OP_GE:
320 return QLatin1String( "relationGE" );
321 case OP_LT:
322 return QLatin1String( "relationLT" );
323 case OP_LE:
324 return QLatin1String( "relationLE" );
325 case OP_EQ:
326 return QLatin1String( "relationEQ" );
327 case OP_NE:
328 return QLatin1String( "relationNE" );
329 default:
330 assert(0);
331 return QString();
332 }
333}
334
335LogicalOp::LogicalOp( int _opCode, Expression* lhs, Expression* rhs ) :
336 opCode( _opCode )
337{
338 addSubExpression( lhs );
339 addSubExpression( rhs );
340}
341
342bool LogicalOp::shortCircuitOn() const
343{
344 if (opCode == OP_And)
345 return false; //false and foo
346 else
347 return true; //true or bar
348}
349
350bool LogicalOp::isConstant() const
351{
352 return subExpr( 0 )->isConstant() &&
353 subExpr( 0 )->evaluate().toBoolean() == shortCircuitOn();
354}
355
356QString LogicalOp::opName() const
357{
358 if ( opCode == OP_And )
359 return QLatin1String( "conjunction" );
360 else
361 return QLatin1String( "disjunction" );
362}
363
364Value LogicalOp::doEvaluate() const
365{
366 Value lhs( subExpr( 0 )->evaluate() );
367
368 // This is not only an optimization, http://www.w3.org/TR/xpath
369 // dictates that we must do short-circuit evaluation
370 bool lhsBool = lhs.toBoolean();
371 if ( lhsBool == shortCircuitOn() ) {
372 return Value( lhsBool );
373 }
374
375 return Value( subExpr( 1 )->evaluate().toBoolean() );
376}
377
378QString Union::opName() const
379{
380 return QLatin1String("union");
381}
382
383Value Union::doEvaluate() const
384{
385 Value lhs = subExpr( 0 )->evaluate();
386 Value rhs = subExpr( 1 )->evaluate();
387 if ( !lhs.isNodeset() || !rhs.isNodeset() ) {
388 kWarning(6011) << "Union operator '|' works only with nodesets.";
389 Expression::reportInvalidExpressionErr();
390 return Value( new StaticNodeListImpl );
391 }
392
393 DomNodeList lhsNodes = lhs.toNodeset();
394 DomNodeList rhsNodes = rhs.toNodeset();
395 DomNodeList result = new StaticNodeListImpl;
396
397 for ( unsigned long n = 0; n < lhsNodes->length(); ++n )
398 result->append( lhsNodes->item( n ) );
399
400 for ( unsigned long n = 0; n < rhsNodes->length(); ++n )
401 result->append( rhsNodes->item( n ) );
402
403 return Value( result );
404}
405
406Predicate::Predicate( Expression *expr )
407 : m_expr( expr )
408{
409}
410
411Predicate::~Predicate()
412{
413 delete m_expr;
414}
415
416bool Predicate::evaluate() const
417{
418 Q_ASSERT( m_expr != 0 );
419
420 Value result( m_expr->evaluate() );
421
422 // foo[3] really means foo[position()=3]
423 if ( result.isNumber() ) {
424 return double( Expression::evaluationContext().position ) == result.toNumber();
425 }
426
427 return result.toBoolean();
428}
429
430void Predicate::optimize()
431{
432 m_expr->optimize();
433}
434
435QString Predicate::dump() const
436{
437 return QString() + "<predicate>" + m_expr->dump() + "</predicate>";
438}
439
440// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
DOM::DOMString
This class implements the basic string we use in the DOM.
Definition: dom_string.h:44
DOM::DOMString::string
QString string() const
Definition: dom_string.cpp:236
khtml::XPath::BinaryExprBase::dump
virtual QString dump() const
Definition: predicate.cpp:93
khtml::XPath::BinaryExprBase::opName
virtual QString opName() const =0
khtml::XPath::Expression
Definition: expression.h:115
khtml::XPath::Expression::evaluationContext
static EvaluationContext & evaluationContext()
Definition: expression.cpp:212
khtml::XPath::Expression::evaluate
virtual Value evaluate() const
Definition: expression.cpp:229
khtml::XPath::Expression::optimize
void optimize()
Definition: expression.cpp:242
khtml::XPath::Expression::dump
virtual QString dump() const =0
khtml::XPath::Expression::isConstant
virtual bool isConstant() const
Definition: expression.cpp:278
khtml::XPath::Expression::addSubExpression
void addSubExpression(Expression *expr)
Definition: expression.cpp:237
khtml::XPath::Expression::subExpr
Expression * subExpr(unsigned int i)
Definition: expression.cpp:266
khtml::XPath::Expression::reportInvalidExpressionErr
static void reportInvalidExpressionErr()
Definition: expression.cpp:288
khtml::XPath::LogicalOp::isConstant
virtual bool isConstant() const
Definition: predicate.cpp:350
khtml::XPath::LogicalOp::OP_And
@ OP_And
Definition: predicate.h:126
khtml::XPath::LogicalOp::LogicalOp
LogicalOp(int opCode, Expression *lhs, Expression *rhs)
Definition: predicate.cpp:335
khtml::XPath::Negative::dump
virtual QString dump() const
Definition: predicate.cpp:88
khtml::XPath::Number::Number
Number(double value)
Definition: predicate.cpp:42
khtml::XPath::Number::isConstant
bool isConstant() const
Definition: predicate.cpp:47
khtml::XPath::Number::dump
virtual QString dump() const
Definition: predicate.cpp:52
khtml::XPath::NumericOp::OP_Mul
@ OP_Mul
Definition: predicate.h:85
khtml::XPath::NumericOp::OP_Sub
@ OP_Sub
Definition: predicate.h:84
khtml::XPath::NumericOp::OP_Div
@ OP_Div
Definition: predicate.h:86
khtml::XPath::NumericOp::OP_Mod
@ OP_Mod
Definition: predicate.h:87
khtml::XPath::NumericOp::OP_Add
@ OP_Add
Definition: predicate.h:83
khtml::XPath::NumericOp::NumericOp
NumericOp(int opCode, Expression *lhs, Expression *rhs)
Definition: predicate.cpp:102
khtml::XPath::Predicate::dump
QString dump() const
Definition: predicate.cpp:435
khtml::XPath::Predicate::~Predicate
~Predicate()
Definition: predicate.cpp:411
khtml::XPath::Predicate::Predicate
Predicate(Expression *expr)
Definition: predicate.cpp:406
khtml::XPath::Predicate::optimize
void optimize()
Definition: predicate.cpp:430
khtml::XPath::Predicate::evaluate
bool evaluate() const
Definition: predicate.cpp:416
khtml::XPath::RelationOp::OP_GT
@ OP_GT
Definition: predicate.h:102
khtml::XPath::RelationOp::OP_LT
@ OP_LT
Definition: predicate.h:103
khtml::XPath::RelationOp::OP_EQ
@ OP_EQ
Definition: predicate.h:106
khtml::XPath::RelationOp::OP_NE
@ OP_NE
Definition: predicate.h:107
khtml::XPath::RelationOp::OP_LE
@ OP_LE
Definition: predicate.h:105
khtml::XPath::RelationOp::OP_GE
@ OP_GE
Definition: predicate.h:104
khtml::XPath::RelationOp::RelationOp
RelationOp(int opCode, Expression *lhs, Expression *rhs)
Definition: predicate.cpp:166
khtml::XPath::String::isConstant
bool isConstant() const
Definition: predicate.cpp:67
khtml::XPath::String::dump
virtual QString dump() const
Definition: predicate.cpp:72
khtml::XPath::String::String
String(const DOM::DOMString &value)
Definition: predicate.cpp:62
khtml::XPath::Value
Definition: expression.h:76
khtml::XPath::Value::isString
bool isString() const
Definition: expression.cpp:101
khtml::XPath::Value::toString
DOM::DOMString toString() const
Definition: expression.cpp:160
khtml::XPath::Value::isNodeset
bool isNodeset() const
Definition: expression.cpp:86
khtml::XPath::Value::isNumber
bool isNumber() const
Definition: expression.cpp:96
khtml::XPath::Value::toNodeset
DomNodeList & toNodeset()
Definition: expression.cpp:106
khtml::XPath::Value::toBoolean
bool toBoolean() const
Definition: expression.cpp:122
khtml::XPath::Value::toNumber
double toNumber() const
Definition: expression.cpp:137
assert
#define assert(x)
Definition: editor.cpp:43
functions.h
kWarning
#define kWarning
DOM
This library provides a full-featured HTML parser and widget.
Definition: design.h:55
khtml::XPath
Definition: expression.h:45
khtml::XPath::stringValue
DOMString stringValue(NodeImpl *node)
Definition: util.cpp:68
khtml::XPath::DomNodeList
SharedPtr< DOM::StaticNodeListImpl > DomNodeList
Definition: util.h:41
khtml
numify
static void numify(const Value &val, WTF::Vector< double > *out)
Definition: predicate.cpp:188
stringify
static void stringify(const Value &val, WTF::Vector< DOMString > *out)
Definition: predicate.cpp:173
predicate.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KHTML

Skip menu "KHTML"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal