mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-25 03:12:49 +00:00
900 lines
19 KiB
C++
900 lines
19 KiB
C++
/*
|
|
* functions.cc - Copyright 2005 Frerich Raabe <raabe@kde.org>
|
|
*
|
|
* 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 "functions.h"
|
|
|
|
#include "xml/dom_docimpl.h"
|
|
#include "xml/dom_nodeimpl.h"
|
|
#include "xml/dom_nodelistimpl.h"
|
|
#include "xml/dom_elementimpl.h"
|
|
#include "kjs/operations.h"
|
|
|
|
#include <QtCore/qdebug.h>
|
|
|
|
#include <math.h>
|
|
|
|
using namespace DOM;
|
|
|
|
namespace khtml {
|
|
namespace XPath {
|
|
|
|
#define DEFINE_FUNCTION_CREATOR(Class) \
|
|
static Function *create##Class() { return new Class; }
|
|
|
|
class Interval
|
|
{
|
|
public:
|
|
static const int Inf =-1;
|
|
|
|
Interval();
|
|
Interval( int value );
|
|
Interval( int min, int max );
|
|
|
|
bool contains( int value ) const;
|
|
|
|
QString asString() const;
|
|
|
|
private:
|
|
int m_min;
|
|
int m_max;
|
|
};
|
|
|
|
class FunLast : public Function
|
|
{
|
|
public:
|
|
virtual bool isConstant() const;
|
|
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunPosition : public Function
|
|
{
|
|
public:
|
|
virtual bool isConstant() const;
|
|
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunCount : public Function
|
|
{
|
|
public:
|
|
virtual bool isConstant() const;
|
|
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
// Base for various node-property functions, that have
|
|
// the same node picking logic. It passes the proper node,
|
|
// if any, or otherwise returns an empty string by itself
|
|
class NodeFunction : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
virtual Value evaluateOnNode( DOM::NodeImpl* node ) const = 0;
|
|
};
|
|
|
|
class FunLocalName : public NodeFunction
|
|
{
|
|
public:
|
|
virtual bool isConstant() const;
|
|
|
|
private:
|
|
virtual Value evaluateOnNode( DOM::NodeImpl* node ) const;
|
|
};
|
|
|
|
class FunNamespaceURI : public NodeFunction
|
|
{
|
|
public:
|
|
virtual bool isConstant() const;
|
|
|
|
private:
|
|
virtual Value evaluateOnNode( DOM::NodeImpl* node ) const;
|
|
};
|
|
|
|
class FunName : public NodeFunction
|
|
{
|
|
public:
|
|
virtual bool isConstant() const;
|
|
|
|
private:
|
|
virtual Value evaluateOnNode( DOM::NodeImpl* node ) const;
|
|
};
|
|
|
|
class FunId : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunString : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunConcat : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunStartsWith : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunContains : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunSubstringBefore : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunSubstringAfter : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunSubstring : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunStringLength : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunNormalizeSpace : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunTranslate : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunBoolean : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunNot : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunTrue : public Function
|
|
{
|
|
public:
|
|
virtual bool isConstant() const;
|
|
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunFalse : public Function
|
|
{
|
|
public:
|
|
virtual bool isConstant() const;
|
|
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunLang : public Function
|
|
{
|
|
public:
|
|
virtual bool isConstant() const;
|
|
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunNumber : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunSum : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunFloor : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunCeiling : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
class FunRound : public Function
|
|
{
|
|
private:
|
|
virtual Value doEvaluate() const;
|
|
};
|
|
|
|
DEFINE_FUNCTION_CREATOR( FunLast )
|
|
DEFINE_FUNCTION_CREATOR( FunPosition )
|
|
DEFINE_FUNCTION_CREATOR( FunCount )
|
|
DEFINE_FUNCTION_CREATOR( FunLocalName )
|
|
DEFINE_FUNCTION_CREATOR( FunNamespaceURI )
|
|
DEFINE_FUNCTION_CREATOR( FunName )
|
|
DEFINE_FUNCTION_CREATOR( FunId )
|
|
|
|
DEFINE_FUNCTION_CREATOR( FunString )
|
|
DEFINE_FUNCTION_CREATOR( FunConcat )
|
|
DEFINE_FUNCTION_CREATOR( FunStartsWith )
|
|
DEFINE_FUNCTION_CREATOR( FunContains )
|
|
DEFINE_FUNCTION_CREATOR( FunSubstringBefore )
|
|
DEFINE_FUNCTION_CREATOR( FunSubstringAfter )
|
|
DEFINE_FUNCTION_CREATOR( FunSubstring )
|
|
DEFINE_FUNCTION_CREATOR( FunStringLength )
|
|
DEFINE_FUNCTION_CREATOR( FunNormalizeSpace )
|
|
DEFINE_FUNCTION_CREATOR( FunTranslate )
|
|
|
|
DEFINE_FUNCTION_CREATOR( FunBoolean )
|
|
DEFINE_FUNCTION_CREATOR( FunNot )
|
|
DEFINE_FUNCTION_CREATOR( FunTrue )
|
|
DEFINE_FUNCTION_CREATOR( FunFalse )
|
|
DEFINE_FUNCTION_CREATOR( FunLang )
|
|
|
|
DEFINE_FUNCTION_CREATOR( FunNumber )
|
|
DEFINE_FUNCTION_CREATOR( FunSum )
|
|
DEFINE_FUNCTION_CREATOR( FunFloor )
|
|
DEFINE_FUNCTION_CREATOR( FunCeiling )
|
|
DEFINE_FUNCTION_CREATOR( FunRound )
|
|
|
|
#undef DEFINE_FUNCTION_CREATOR
|
|
|
|
Interval::Interval()
|
|
: m_min( Inf ),
|
|
m_max( Inf )
|
|
{
|
|
}
|
|
|
|
Interval::Interval( int value )
|
|
: m_min( value ),
|
|
m_max( value )
|
|
{
|
|
}
|
|
|
|
Interval::Interval( int min, int max )
|
|
: m_min( min ),
|
|
m_max( max )
|
|
{
|
|
}
|
|
|
|
bool Interval::contains( int value ) const
|
|
{
|
|
if ( m_min == Inf && m_max == Inf ) {
|
|
return true;
|
|
}
|
|
|
|
if ( m_min == Inf ) {
|
|
return value <= m_max;
|
|
}
|
|
|
|
if ( m_max == Inf ) {
|
|
return value >= m_min;
|
|
}
|
|
|
|
return value >= m_min && value <= m_max;
|
|
}
|
|
|
|
QString Interval::asString() const
|
|
{
|
|
QString s = "[";
|
|
|
|
if ( m_min == Inf ) {
|
|
s += "-Infinity";
|
|
} else {
|
|
s += QString::number( m_min );
|
|
}
|
|
|
|
s += "..";
|
|
|
|
if ( m_max == Inf ) {
|
|
s += "Infinity";
|
|
} else {
|
|
s += QString::number( m_max );
|
|
}
|
|
|
|
s += "]";
|
|
|
|
return s;
|
|
}
|
|
|
|
void Function::setArguments( const QList<Expression *> &args )
|
|
{
|
|
foreach( Expression *arg, args ) {
|
|
addSubExpression( arg );
|
|
}
|
|
}
|
|
|
|
void Function::setName( const DOM::DOMString &name )
|
|
{
|
|
m_name = name;
|
|
}
|
|
|
|
QString Function::dump() const
|
|
{
|
|
if ( argCount() == 0 ) {
|
|
return QString( "<function name=\"%1\"/>" ).arg( name().string() );
|
|
}
|
|
|
|
QString s = QString( "<function name=\"%1\">" ).arg( name().string() );
|
|
for ( unsigned int i = 0; i < argCount(); ++i ) {
|
|
s += "<operand>" + arg( i )->dump() + "</operand>";
|
|
}
|
|
s += "</function>";
|
|
return s;
|
|
}
|
|
|
|
|
|
Expression *Function::arg( int i )
|
|
{
|
|
return subExpr( i );
|
|
}
|
|
|
|
const Expression *Function::arg( int i ) const
|
|
{
|
|
return subExpr( i );
|
|
}
|
|
|
|
unsigned int Function::argCount() const
|
|
{
|
|
return subExprCount();
|
|
}
|
|
|
|
DOM::DOMString Function::name() const
|
|
{
|
|
return m_name;
|
|
}
|
|
|
|
Value FunLast::doEvaluate() const
|
|
{
|
|
return Value( double( Expression::evaluationContext().size ) );
|
|
}
|
|
|
|
bool FunLast::isConstant() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Value FunPosition::doEvaluate() const
|
|
{
|
|
return Value( double( Expression::evaluationContext().position ) );
|
|
}
|
|
|
|
bool FunPosition::isConstant() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Value NodeFunction::doEvaluate() const
|
|
{
|
|
NodeImpl *node = 0;
|
|
if ( argCount() > 0 ) {
|
|
Value a = arg( 0 )->evaluate();
|
|
if ( a.isNodeset() && a.toNodeset()->length() ) {
|
|
node = a.toNodeset()->first();
|
|
}
|
|
} else {
|
|
// no argument -> default to context node
|
|
node = evaluationContext().node;
|
|
}
|
|
|
|
if ( !node )
|
|
return Value( DOMString() );
|
|
|
|
return evaluateOnNode( node );
|
|
}
|
|
|
|
bool FunLocalName::isConstant() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Value FunLocalName::evaluateOnNode( DOM::NodeImpl* node ) const
|
|
{
|
|
DOM::DOMString n;
|
|
switch ( node->nodeType() ) {
|
|
case Node::PROCESSING_INSTRUCTION_NODE:
|
|
n = node->nodeName(); // target name
|
|
break;
|
|
default:
|
|
n = node->localName();
|
|
}
|
|
return Value( n );
|
|
}
|
|
|
|
bool FunNamespaceURI::isConstant() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Value FunNamespaceURI::evaluateOnNode( DOM::NodeImpl* node ) const
|
|
{
|
|
return Value( node->namespaceURI() );
|
|
}
|
|
|
|
Value FunId::doEvaluate() const
|
|
{
|
|
Value a = arg( 0 )->evaluate();
|
|
|
|
WTF::Vector<DOM::DOMString> ids;
|
|
|
|
QString queryString; // whitespace-separated IDs
|
|
if ( a.isNodeset() ) {
|
|
DomNodeList set = a.toNodeset();
|
|
for ( unsigned long i = 0; i < set->length(); ++i)
|
|
queryString += stringValue( set->item(i) ).string() + QLatin1Char(' ');
|
|
} else {
|
|
queryString = a.toString().string();
|
|
}
|
|
|
|
QStringList qids = queryString.simplified().split(' ');
|
|
for ( int i = 0; i < qids.size(); ++i)
|
|
ids.append( DOM::DOMString( qids[i] ) );
|
|
|
|
DomNodeList out = new StaticNodeListImpl();
|
|
DOM::DocumentImpl* doc = Expression::evaluationContext().node->document();
|
|
|
|
for ( unsigned i = 0; i < ids.size(); ++i ) {
|
|
DOM::ElementImpl* e = doc->getElementById( ids[i] );
|
|
|
|
if ( e )
|
|
out->append( e );
|
|
}
|
|
|
|
return Value( out );
|
|
}
|
|
|
|
bool FunName::isConstant() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Value FunName::evaluateOnNode( DOM::NodeImpl* node ) const
|
|
{
|
|
DOM::DOMString n;
|
|
switch ( node->nodeType() ) {
|
|
case Node::TEXT_NODE:
|
|
case Node::CDATA_SECTION_NODE:
|
|
case Node::COMMENT_NODE:
|
|
case Node::DOCUMENT_NODE:
|
|
// All of these have an empty XPath name
|
|
break;
|
|
case Node::ELEMENT_NODE: {
|
|
n = static_cast<DOM::ElementImpl*>( node )->nonCaseFoldedTagName();
|
|
break;
|
|
}
|
|
default:
|
|
n = node->nodeName();
|
|
}
|
|
return Value( n );
|
|
}
|
|
|
|
Value FunCount::doEvaluate() const
|
|
{
|
|
Value a = arg( 0 )->evaluate();
|
|
if ( !a.isNodeset() ) {
|
|
Expression::reportInvalidExpressionErr();
|
|
kWarning() << "count() expects <nodeset>";
|
|
return Value( );
|
|
}
|
|
a.toNodeset()->normalizeUpto(StaticNodeListImpl::AxisOrder);
|
|
|
|
return Value( double( a.toNodeset()->length() ) );
|
|
}
|
|
|
|
bool FunCount::isConstant() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Value FunString::doEvaluate() const
|
|
{
|
|
if ( argCount() == 0 ) {
|
|
DOMString s = Value( Expression::evaluationContext().node ).toString();
|
|
return Value( s );
|
|
}
|
|
return Value( arg( 0 )->evaluate().toString() );
|
|
}
|
|
|
|
Value FunConcat::doEvaluate() const
|
|
{
|
|
QString str;
|
|
for ( unsigned int i = 0; i < argCount(); ++i ) {
|
|
str.append( arg( i )->evaluate().toString().string() );
|
|
}
|
|
return Value( DOMString( str ) );
|
|
}
|
|
|
|
Value FunStartsWith::doEvaluate() const
|
|
{
|
|
DOMString s1 = arg( 0 )->evaluate().toString();
|
|
DOMString s2 = arg( 1 )->evaluate().toString();
|
|
|
|
if ( s2.isEmpty() ) {
|
|
return Value( true );
|
|
}
|
|
|
|
return Value( s1.startsWith( s2 ) );
|
|
}
|
|
|
|
Value FunContains::doEvaluate() const
|
|
{
|
|
QString s1 = arg( 0 )->evaluate().toString().string();
|
|
QString s2 = arg( 1 )->evaluate().toString().string();
|
|
|
|
if ( s2.isEmpty() ) {
|
|
return Value( true );
|
|
}
|
|
|
|
return Value( s1.contains( s2 ) );
|
|
}
|
|
|
|
Value FunSubstringBefore::doEvaluate() const
|
|
{
|
|
QString s1 = arg( 0 )->evaluate().toString().string();
|
|
QString s2 = arg( 1 )->evaluate().toString().string();
|
|
|
|
if ( s2.isEmpty() ) {
|
|
return Value( DOMString() );
|
|
}
|
|
|
|
int i = s1.indexOf( s2 );
|
|
if ( i == -1 ) {
|
|
return Value( DOMString() );
|
|
}
|
|
|
|
return Value( DOMString( s1.left( i ) ) );
|
|
}
|
|
|
|
Value FunSubstringAfter::doEvaluate() const
|
|
{
|
|
QString s1 = arg( 0 )->evaluate().toString().string();
|
|
QString s2 = arg( 1 )->evaluate().toString().string();
|
|
|
|
if ( s2.isEmpty() ) {
|
|
return Value( s1 );
|
|
}
|
|
|
|
int i = s1.indexOf( s2 );
|
|
if ( i == -1 ) {
|
|
return Value( DOMString() );
|
|
}
|
|
|
|
return Value( DOMString( s1.mid( i + s2.length() ) ) );
|
|
}
|
|
|
|
Value FunSubstring::doEvaluate() const
|
|
{
|
|
QString s = arg( 0 )->evaluate().toString().string();
|
|
long pos = long( qRound( arg( 1 )->evaluate().toNumber() ) );
|
|
bool haveLength = argCount() == 3;
|
|
long len = -1;
|
|
if ( haveLength ) {
|
|
len = long( qRound( arg( 2 )->evaluate().toNumber() ) );
|
|
}
|
|
|
|
if ( pos > long( s.length() ) ) {
|
|
return Value( DOMString() );
|
|
}
|
|
|
|
if ( haveLength && pos < 1 ) {
|
|
len -= 1 - pos;
|
|
pos = 1;
|
|
if ( len < 1 ) {
|
|
return Value( DOMString() );
|
|
}
|
|
}
|
|
|
|
return Value( DOMString( s.mid( pos - 1, len ) ) );
|
|
}
|
|
|
|
Value FunStringLength::doEvaluate() const
|
|
{
|
|
if ( argCount() == 0 ) {
|
|
DOMString s = Value( Expression::evaluationContext().node ).toString();
|
|
return Value( double( s.length() ) );
|
|
}
|
|
|
|
return Value( double( arg( 0 )->evaluate().toString().length() ) );
|
|
}
|
|
|
|
Value FunNormalizeSpace::doEvaluate() const
|
|
{
|
|
if ( argCount() == 0 ) {
|
|
DOMString s = Value( Expression::evaluationContext().node ).toString();
|
|
return Value( DOMString( s.string().simplified() ) );
|
|
}
|
|
|
|
QString s = arg( 0 )->evaluate().toString().string();
|
|
s = s.simplified();
|
|
return Value( DOMString( s ) );
|
|
}
|
|
|
|
Value FunTranslate::doEvaluate() const
|
|
{
|
|
QString s1 = arg( 0 )->evaluate().toString().string();
|
|
QString s2 = arg( 1 )->evaluate().toString().string();
|
|
QString s3 = arg( 2 )->evaluate().toString().string();
|
|
QString newString;
|
|
|
|
for ( int i1 = 0; i1 < s1.length(); ++i1 ) {
|
|
QChar ch = s1[ i1 ];
|
|
int i2 = s2.indexOf( ch );
|
|
if ( i2 == -1 ) {
|
|
newString += ch;
|
|
} else if ( i2 < s3.length() ) {
|
|
newString += s3[ i2 ];
|
|
}
|
|
}
|
|
|
|
return Value( DOMString( newString ) );
|
|
}
|
|
|
|
Value FunBoolean::doEvaluate() const
|
|
{
|
|
return Value( arg( 0 )->evaluate().toBoolean() );
|
|
}
|
|
|
|
Value FunNot::doEvaluate() const
|
|
{
|
|
return Value( !arg( 0 )->evaluate().toBoolean() );
|
|
}
|
|
|
|
Value FunTrue::doEvaluate() const
|
|
{
|
|
return Value( true );
|
|
}
|
|
|
|
bool FunTrue::isConstant() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
#ifdef __GNUC__
|
|
#warning "This looks bogus"
|
|
#endif
|
|
|
|
Value FunLang::doEvaluate() const
|
|
{
|
|
QString lang = arg( 0 )->evaluate().toString().string();
|
|
|
|
NodeImpl* node = evaluationContext().node;
|
|
|
|
DOMString langNodeValue;
|
|
|
|
while ( node ) {
|
|
if (node->isElementNode()) {
|
|
langNodeValue = static_cast<ElementImpl*>(node)->getAttribute("xml:lang");
|
|
if ( !langNodeValue.isNull() )
|
|
break;
|
|
}
|
|
node = xpathParentNode( node );
|
|
}
|
|
|
|
if ( langNodeValue.isNull() ) {
|
|
return Value( false );
|
|
}
|
|
|
|
// extract 'en' out of 'en-us'
|
|
QString langNodeValueString = langNodeValue.string();
|
|
QString langNodeBaseString = langNodeValueString.left( langNodeValueString.indexOf( '-' ) );
|
|
|
|
return Value( langNodeValueString.toLower() == lang.toLower() ||
|
|
langNodeBaseString.toLower() == lang.toLower() );
|
|
}
|
|
|
|
bool FunLang::isConstant() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Value FunFalse::doEvaluate() const
|
|
{
|
|
return Value( false );
|
|
}
|
|
|
|
bool FunFalse::isConstant() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
Value FunNumber::doEvaluate() const
|
|
{
|
|
Value vi;
|
|
if ( argCount() == 0 ) {
|
|
// Spec'd: convert context node to singleton nodeset, call
|
|
// string on that --> that's just stringValue on that node.
|
|
// then we call number on that string
|
|
vi = Value(stringValue(evaluationContext().node));
|
|
} else {
|
|
vi = arg( 0 )->evaluate();
|
|
}
|
|
|
|
return Value( vi.toNumber() );
|
|
}
|
|
|
|
Value FunSum::doEvaluate() const
|
|
{
|
|
Value a = arg( 0 )->evaluate();
|
|
if ( !a.isNodeset() ) {
|
|
Expression::reportInvalidExpressionErr();
|
|
kWarning() << "sum() expects <nodeset>";
|
|
return Value( 0.0 );
|
|
}
|
|
|
|
double sum = 0.0;
|
|
const DomNodeList nodes = a.toNodeset();
|
|
for (unsigned long n = 0; n < nodes->length(); ++n) {
|
|
NodeImpl* node = nodes->item(n);
|
|
sum += Value( stringValue( node ) ).toNumber();
|
|
}
|
|
return Value( sum );
|
|
}
|
|
|
|
Value FunFloor::doEvaluate() const
|
|
{
|
|
const double num = arg( 0 )->evaluate().toNumber();
|
|
|
|
if ( KJS::isNaN( num ) || KJS::isInf( num ) ) {
|
|
return Value( num );
|
|
}
|
|
|
|
return Value( floor( num ) );
|
|
}
|
|
|
|
Value FunCeiling::doEvaluate() const
|
|
{
|
|
const double num = arg( 0 )->evaluate().toNumber();
|
|
|
|
if ( KJS::isNaN( num ) || KJS::isInf( num ) ) {
|
|
return Value( num );
|
|
}
|
|
|
|
return Value( ceil( num ) );
|
|
}
|
|
|
|
Value FunRound::doEvaluate() const
|
|
{
|
|
return Value( double( qRound( arg( 0 )->evaluate().toNumber() ) ) );
|
|
}
|
|
|
|
struct FunctionLibrary::FunctionRec
|
|
{
|
|
typedef Function *(*FactoryFn )();
|
|
|
|
FactoryFn factoryFn;
|
|
Interval args;
|
|
};
|
|
|
|
struct FunctionMapping
|
|
{
|
|
const char *name;
|
|
FunctionLibrary::FunctionRec function;
|
|
};
|
|
|
|
static FunctionMapping functions[] = {
|
|
{ "last", { &createFunLast, 0 } },
|
|
{ "last", { &createFunLast, 0 } },
|
|
{ "position", { &createFunPosition, 0 } },
|
|
{ "count", { &createFunCount, 1 } },
|
|
{ "sum", { &createFunSum, 1 } },
|
|
{ "local-name", { &createFunLocalName, Interval( 0, 1 ) } },
|
|
{ "namespace-uri", { &createFunNamespaceURI, Interval( 0, 1 ) } },
|
|
{ "id", { &createFunId, 1 } },
|
|
{ "name", { &createFunName, Interval( 0, 1 ) } },
|
|
|
|
|
|
{ "string", { &createFunString, Interval( 0, 1 ) } },
|
|
{ "concat", { &createFunConcat, Interval( 2, Interval::Inf ) } },
|
|
{ "starts-with", { &createFunStartsWith, 2 } },
|
|
{ "contains", { &createFunContains, 2 } },
|
|
{ "substring-before", { &createFunSubstringBefore, 2 } },
|
|
{ "substring-after", { &createFunSubstringAfter, 2 } },
|
|
{ "substring", { &createFunSubstring, Interval( 2, 3 ) } },
|
|
{ "string-length", { &createFunStringLength, Interval( 0, 1 ) } },
|
|
{ "normalize-space", { &createFunNormalizeSpace, Interval( 0, 1 ) } },
|
|
{ "translate", { &createFunTranslate, 3 } },
|
|
|
|
{ "boolean", { &createFunBoolean, 1 } },
|
|
{ "not", { &createFunNot, 1 } },
|
|
{ "true", { &createFunTrue, 0 } },
|
|
{ "false", { &createFunFalse, 0 } },
|
|
{ "lang", { &createFunLang, 1 } },
|
|
|
|
{ "number", { &createFunNumber, Interval( 0, 1 ) } },
|
|
{ "floor", { &createFunFloor, 1 } },
|
|
{ "ceiling", { &createFunCeiling, 1 } },
|
|
{ "round", { &createFunRound, 1 } }
|
|
};
|
|
static const unsigned int numFunctions = sizeof( functions ) / sizeof( functions[ 0 ] );
|
|
|
|
FunctionLibrary &FunctionLibrary::self()
|
|
{
|
|
static FunctionLibrary instance;
|
|
return instance;
|
|
}
|
|
|
|
FunctionLibrary::FunctionLibrary()
|
|
{
|
|
for ( unsigned int i = 0; i < numFunctions; ++i ) {
|
|
m_functionDict.insert( functions[ i ].name, functions[ i ].function );
|
|
}
|
|
}
|
|
|
|
Function *FunctionLibrary::getFunction( const DOM::DOMString& name,
|
|
const QList<Expression *> &args ) const
|
|
{
|
|
if ( !m_functionDict.contains( name ) ) {
|
|
kWarning() << "Function '" << name << "' not supported by this implementation.";
|
|
|
|
return 0;
|
|
}
|
|
|
|
FunctionRec functionRec = m_functionDict[ name ];
|
|
if ( !functionRec.args.contains( args.count() ) ) {
|
|
kWarning() << "Function '" << name << "' requires " << functionRec.args.asString() << " arguments, but " << args.count() << " given.";
|
|
return 0;
|
|
}
|
|
|
|
Function *function = functionRec.factoryFn();
|
|
function->setArguments( args );
|
|
function->setName( name );
|
|
return function;
|
|
}
|
|
|
|
} //namespace XPath
|
|
} //namespace khtml
|
|
|
|
// kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
|