780 lines
18 KiB
C++
780 lines
18 KiB
C++
#ifndef _XPATH_H
|
|
#define _XPATH_H
|
|
|
|
#include "xml.h"
|
|
#include "error.h"
|
|
#if 0
|
|
#include "mask.h"
|
|
#endif
|
|
|
|
#include <list>
|
|
#include <memory>
|
|
|
|
namespace ledger {
|
|
namespace xml {
|
|
|
|
class xpath_t
|
|
{
|
|
public:
|
|
struct op_t;
|
|
|
|
class parse_error : public error {
|
|
public:
|
|
parse_error(const string& _reason,
|
|
error_context * _ctxt = NULL) throw()
|
|
: error(_reason, _ctxt) {}
|
|
virtual ~parse_error() throw() {}
|
|
};
|
|
|
|
class compile_error : public error {
|
|
public:
|
|
compile_error(const string& _reason,
|
|
error_context * _ctxt = NULL) throw()
|
|
: error(_reason, _ctxt) {}
|
|
virtual ~compile_error() throw() {}
|
|
};
|
|
|
|
class calc_error : public error {
|
|
public:
|
|
calc_error(const string& _reason,
|
|
error_context * _ctxt = NULL) throw()
|
|
: error(_reason, _ctxt) {}
|
|
virtual ~calc_error() throw() {}
|
|
};
|
|
|
|
class context : public error_context {
|
|
public:
|
|
const xpath_t& xpath;
|
|
const op_t * err_node;
|
|
|
|
context(const xpath_t& _xpath,
|
|
const op_t * _err_node,
|
|
const string& desc = "") throw();
|
|
virtual ~context() throw();
|
|
|
|
virtual void describe(std::ostream& out) const throw();
|
|
};
|
|
|
|
public:
|
|
class scope_t;
|
|
|
|
class functor_t {
|
|
protected:
|
|
string fname;
|
|
public:
|
|
bool wants_args;
|
|
|
|
functor_t(const string& _fname, bool _wants_args = false)
|
|
: fname(_fname), wants_args(_wants_args) {}
|
|
virtual ~functor_t() {}
|
|
|
|
virtual void operator()(value_t& result, scope_t * locals) = 0;
|
|
virtual string name() const { return fname; }
|
|
};
|
|
|
|
template <typename T, typename U>
|
|
class member_functor_t : public functor_t {
|
|
public:
|
|
T * ptr;
|
|
U T::*dptr;
|
|
|
|
member_functor_t(const string& _name, T * _ptr, U T::*_dptr)
|
|
: functor_t(_name, false), ptr(_ptr), dptr(_dptr) {}
|
|
|
|
virtual void operator()(value_t& result, scope_t * locals) {
|
|
assert(ptr);
|
|
assert(dptr);
|
|
result = ptr->*dptr;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class member_functor_t<T, string> : public functor_t {
|
|
public:
|
|
T * ptr;
|
|
string T::*dptr;
|
|
|
|
member_functor_t(const string& _name, T * _ptr, string T::*_dptr)
|
|
: functor_t(_name, false), ptr(_ptr), dptr(_dptr) {}
|
|
|
|
virtual void operator()(value_t& result, scope_t * locals) {
|
|
assert(ptr);
|
|
assert(dptr);
|
|
result.set_string(ptr->*dptr);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class memfun_functor_t : public functor_t {
|
|
public:
|
|
T * ptr;
|
|
void (T::*mptr)(value_t& result);
|
|
|
|
memfun_functor_t(const string& _name, T * _ptr,
|
|
void (T::*_mptr)(value_t& result))
|
|
: functor_t(_name, false), ptr(_ptr), mptr(_mptr) {}
|
|
|
|
virtual void operator()(value_t& result,
|
|
scope_t * locals = NULL) {
|
|
assert(ptr);
|
|
assert(mptr);
|
|
assert(locals || locals == NULL);
|
|
(ptr->*mptr)(result);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class memfun_args_functor_t : public functor_t {
|
|
public:
|
|
T * ptr;
|
|
void (T::*mptr)(value_t& result, scope_t * locals);
|
|
|
|
memfun_args_functor_t(const string& _name, T * _ptr,
|
|
void (T::*_mptr)(value_t& result, scope_t * locals))
|
|
: functor_t(_name, true), ptr(_ptr), mptr(_mptr) {}
|
|
|
|
virtual void operator()(value_t& result, scope_t * locals) {
|
|
assert(ptr);
|
|
assert(mptr);
|
|
(ptr->*mptr)(result, locals);
|
|
}
|
|
};
|
|
|
|
static op_t * wrap_value(const value_t& val);
|
|
static op_t * wrap_sequence(value_t::sequence_t * val);
|
|
static op_t * wrap_functor(functor_t * fobj);
|
|
#if 0
|
|
static op_t * wrap_mask(const string& pattern);
|
|
#endif
|
|
|
|
template <typename T, typename U>
|
|
static op_t *
|
|
make_functor(const string& name, T * ptr, U T::*mptr) {
|
|
return wrap_functor(new member_functor_t<T, U>(name, ptr, mptr));
|
|
}
|
|
|
|
template <typename T>
|
|
static op_t *
|
|
make_functor(const string& fname, T * ptr,
|
|
void (T::*mptr)(value_t& result)) {
|
|
return wrap_functor(new memfun_functor_t<T>(fname, ptr, mptr));
|
|
}
|
|
|
|
template <typename T>
|
|
static op_t *
|
|
make_functor(const string& fname, T * ptr,
|
|
void (T::*mptr)(value_t& result, scope_t * locals)) {
|
|
return wrap_functor(new memfun_args_functor_t<T>(fname, ptr, mptr));
|
|
}
|
|
|
|
#define MAKE_FUNCTOR(cls, name) \
|
|
xml::xpath_t::make_functor(#name, this, &cls::name)
|
|
|
|
public:
|
|
class scope_t
|
|
{
|
|
typedef std::map<const string, op_t *> symbol_map;
|
|
typedef std::pair<const string, op_t *> symbol_pair;
|
|
|
|
symbol_map symbols;
|
|
|
|
scope_t(const scope_t&);
|
|
scope_t& operator=(const scope_t&);
|
|
|
|
public:
|
|
scope_t * parent;
|
|
value_t args;
|
|
|
|
enum kind_t { NORMAL, STATIC, ARGUMENT } kind;
|
|
|
|
scope_t(scope_t * _parent = NULL, kind_t _kind = NORMAL)
|
|
: parent(_parent), kind(_kind) {
|
|
TRACE_CTOR(xpath_t::scope_t, "scope *, kind_t");
|
|
}
|
|
|
|
virtual ~scope_t() {
|
|
TRACE_DTOR(xpath_t::scope_t);
|
|
for (symbol_map::iterator i = symbols.begin();
|
|
i != symbols.end();
|
|
i++)
|
|
(*i).second->release();
|
|
}
|
|
|
|
public:
|
|
virtual void define(const string& name, op_t * def);
|
|
virtual bool resolve(const string& name, value_t& result,
|
|
scope_t * locals = NULL) {
|
|
if (parent)
|
|
return parent->resolve(name, result, locals);
|
|
return false;
|
|
}
|
|
virtual op_t * lookup(const string& name);
|
|
|
|
void define(const string& name, functor_t * def);
|
|
|
|
friend struct op_t;
|
|
};
|
|
|
|
class function_scope_t : public scope_t
|
|
{
|
|
value_t::sequence_t * sequence;
|
|
value_t * value;
|
|
int index;
|
|
|
|
public:
|
|
function_scope_t(value_t::sequence_t * _sequence, value_t * _value,
|
|
int _index, scope_t * _parent = NULL)
|
|
: scope_t(_parent, STATIC),
|
|
sequence(_sequence), value(_value), index(_index) {}
|
|
|
|
virtual bool resolve(const string& name, value_t& result,
|
|
scope_t * locals = NULL);
|
|
};
|
|
|
|
#define XPATH_PARSE_NORMAL 0x00
|
|
#define XPATH_PARSE_PARTIAL 0x01
|
|
#define XPATH_PARSE_RELAXED 0x02
|
|
#define XPATH_PARSE_NO_MIGRATE 0x04
|
|
#define XPATH_PARSE_NO_REDUCE 0x08
|
|
#if 0
|
|
#define XPATH_PARSE_REGEXP 0x10
|
|
#endif
|
|
#define XPATH_PARSE_ALLOW_DATE 0x20
|
|
|
|
private:
|
|
struct token_t
|
|
{
|
|
enum kind_t {
|
|
IDENT, // [A-Za-z_][-A-Za-z0-9_:]*
|
|
VALUE, // any kind of literal value
|
|
#if 0
|
|
REGEXP, // /regexp/ jww (2006-09-24): deprecate
|
|
// in favor of a "match" function
|
|
#endif
|
|
AT_SYM, // @
|
|
DOLLAR, // $
|
|
DOT, // .
|
|
DOTDOT, // ..
|
|
LPAREN, // (
|
|
RPAREN, // )
|
|
LBRACKET, // (
|
|
RBRACKET, // )
|
|
EXCLAM, // !
|
|
NEQUAL, // !=
|
|
MINUS, // -
|
|
PLUS, // +
|
|
STAR, // *
|
|
POWER, // **
|
|
SLASH, // /
|
|
EQUAL, // =
|
|
ASSIGN, // :=
|
|
LESS, // <
|
|
LESSEQ, // <=
|
|
GREATER, // >
|
|
GREATEREQ, // >=
|
|
AMPER, // &
|
|
PIPE, // |
|
|
QUESTION, // ?
|
|
COLON, // :
|
|
COMMA, // ,
|
|
#if 0
|
|
MATCH, // =~
|
|
NMATCH, // !~
|
|
PERCENT, // %
|
|
#endif
|
|
KW_AND,
|
|
KW_OR,
|
|
KW_DIV,
|
|
KW_MOD,
|
|
KW_UNION,
|
|
TOK_EOF,
|
|
UNKNOWN
|
|
} kind;
|
|
|
|
char symbol[3];
|
|
value_t value;
|
|
unsigned int length;
|
|
|
|
token_t() : kind(UNKNOWN), length(0) {
|
|
TRACE_CTOR(xpath_t::token_t, "");
|
|
}
|
|
|
|
token_t(const token_t& other) {
|
|
assert(0);
|
|
TRACE_CTOR(xpath_t::token_t, "copy");
|
|
*this = other;
|
|
}
|
|
|
|
~token_t() {
|
|
TRACE_DTOR(xpath_t::token_t);
|
|
}
|
|
|
|
token_t& operator=(const token_t& other) {
|
|
if (&other == this)
|
|
return *this;
|
|
assert(0);
|
|
return *this;
|
|
}
|
|
|
|
void clear() {
|
|
kind = UNKNOWN;
|
|
length = 0;
|
|
value = 0L;
|
|
|
|
symbol[0] = '\0';
|
|
symbol[1] = '\0';
|
|
symbol[2] = '\0';
|
|
}
|
|
|
|
void parse_ident(std::istream& in);
|
|
void next(std::istream& in, unsigned short flags);
|
|
void rewind(std::istream& in);
|
|
void unexpected();
|
|
|
|
static void unexpected(char c, char wanted = '\0');
|
|
};
|
|
|
|
public:
|
|
struct op_t
|
|
{
|
|
enum kind_t {
|
|
VOID,
|
|
VALUE,
|
|
|
|
NODE_NAME,
|
|
NODE_ID,
|
|
FUNC_NAME,
|
|
ATTR_NAME,
|
|
VAR_NAME,
|
|
|
|
ARG_INDEX,
|
|
|
|
CONSTANTS, // constants end here
|
|
|
|
FUNCTOR,
|
|
#if 0
|
|
MASK,
|
|
#endif
|
|
|
|
TERMINALS, // terminals end here
|
|
|
|
O_NOT,
|
|
O_NEG,
|
|
|
|
O_UNION,
|
|
|
|
O_ADD,
|
|
O_SUB,
|
|
O_MUL,
|
|
O_DIV,
|
|
|
|
O_NEQ,
|
|
O_EQ,
|
|
O_LT,
|
|
O_LTE,
|
|
O_GT,
|
|
O_GTE,
|
|
|
|
O_AND,
|
|
O_OR,
|
|
|
|
O_QUES,
|
|
O_COLON,
|
|
|
|
O_COMMA,
|
|
|
|
#if 0
|
|
O_MATCH,
|
|
O_NMATCH,
|
|
#endif
|
|
|
|
O_DEFINE,
|
|
O_EVAL,
|
|
O_ARG,
|
|
|
|
#if 0
|
|
O_PERC,
|
|
#endif
|
|
|
|
O_FIND,
|
|
O_RFIND,
|
|
O_PRED,
|
|
|
|
LAST // operators end here
|
|
};
|
|
|
|
kind_t kind;
|
|
mutable short refc;
|
|
op_t * left;
|
|
|
|
union {
|
|
value_t * valuep; // used by constant VALUE
|
|
string * name; // used by constant SYMBOL
|
|
unsigned int arg_index; // used by ARG_INDEX and O_ARG
|
|
functor_t * functor; // used by terminal FUNCTOR
|
|
unsigned int name_id; // used by NODE_NAME and ATTR_NAME
|
|
#if 0
|
|
mask_t * mask; // used by terminal MASK
|
|
#endif
|
|
op_t * right; // used by all operators
|
|
};
|
|
|
|
op_t(const kind_t _kind)
|
|
: kind(_kind), refc(0), left(NULL), right(NULL) {
|
|
TRACE_CTOR(xpath_t::op_t, "const kind_t");
|
|
}
|
|
op_t(const op_t&);
|
|
~op_t();
|
|
|
|
op_t& operator=(const op_t&);
|
|
|
|
bool constant() const {
|
|
return kind == VALUE;
|
|
}
|
|
void get_value(value_t& result) const;
|
|
value_t value() const {
|
|
value_t temp;
|
|
get_value(temp);
|
|
return temp;
|
|
}
|
|
|
|
functor_t * functor_obj() const {
|
|
if (kind == FUNCTOR)
|
|
return functor;
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
void release() const {
|
|
DEBUG_PRINT("ledger.xpath.memory",
|
|
"Releasing " << this << ", refc now " << refc - 1);
|
|
assert(refc > 0);
|
|
if (--refc == 0)
|
|
delete this;
|
|
}
|
|
op_t * acquire() {
|
|
DEBUG_PRINT("ledger.xpath.memory",
|
|
"Acquiring " << this << ", refc now " << refc + 1);
|
|
assert(refc >= 0);
|
|
refc++;
|
|
return this;
|
|
}
|
|
const op_t * acquire() const {
|
|
DEBUG_PRINT("ledger.xpath.memory",
|
|
"Acquiring " << this << ", refc now " << refc + 1);
|
|
assert(refc >= 0);
|
|
refc++;
|
|
return this;
|
|
}
|
|
|
|
void set_left(op_t * expr) {
|
|
assert(kind > TERMINALS);
|
|
if (left)
|
|
left->release();
|
|
left = expr ? expr->acquire() : NULL;
|
|
}
|
|
|
|
void set_right(op_t * expr) {
|
|
assert(kind > TERMINALS);
|
|
if (right)
|
|
right->release();
|
|
right = expr ? expr->acquire() : NULL;
|
|
}
|
|
|
|
static op_t * new_node(kind_t kind, op_t * left = NULL,
|
|
op_t * right = NULL);
|
|
|
|
op_t * copy(op_t * left = NULL,
|
|
op_t * right = NULL) const;
|
|
op_t * compile(value_t * context, scope_t * scope,
|
|
bool resolve = false);
|
|
|
|
void find_values(value_t * context, scope_t * scope,
|
|
value_t::sequence_t& result_seq, bool recursive);
|
|
bool test_value(value_t * context, scope_t * scope, int index = 0);
|
|
|
|
void append_value(value_t& value, value_t::sequence_t& result_seq);
|
|
|
|
static op_t * defer_sequence(value_t::sequence_t& result_seq);
|
|
|
|
bool write(std::ostream& out,
|
|
const bool relaxed = true,
|
|
const op_t * op_to_find = NULL,
|
|
unsigned long * start_pos = NULL,
|
|
unsigned long * end_pos = NULL) const;
|
|
|
|
void dump(std::ostream& out, const int depth) const;
|
|
};
|
|
|
|
public:
|
|
op_t * ptr;
|
|
|
|
xpath_t& operator=(op_t * _expr) {
|
|
expr = "";
|
|
reset(_expr);
|
|
return *this;
|
|
}
|
|
|
|
op_t& operator*() throw() {
|
|
return *ptr;
|
|
}
|
|
const op_t& operator*() const throw() {
|
|
return *ptr;
|
|
}
|
|
op_t * operator->() throw() {
|
|
return ptr;
|
|
}
|
|
const op_t * operator->() const throw() {
|
|
return ptr;
|
|
}
|
|
|
|
op_t * get() throw() { return ptr; }
|
|
const op_t * get() const throw() { return ptr; }
|
|
|
|
op_t * release() throw() {
|
|
op_t * tmp = ptr;
|
|
ptr = 0;
|
|
return tmp;
|
|
}
|
|
|
|
void reset(op_t * p = 0) throw() {
|
|
if (p != ptr) {
|
|
if (ptr)
|
|
ptr->release();
|
|
ptr = p;
|
|
}
|
|
}
|
|
|
|
#ifdef THREADSAFE
|
|
mutable token_t lookahead;
|
|
#else
|
|
static token_t lookahead;
|
|
#endif
|
|
mutable bool use_lookahead;
|
|
|
|
token_t& next_token(std::istream& in, unsigned short tflags) const {
|
|
if (use_lookahead)
|
|
use_lookahead = false;
|
|
else
|
|
lookahead.next(in, tflags);
|
|
return lookahead;
|
|
}
|
|
void push_token(const token_t& tok) const {
|
|
assert(&tok == &lookahead);
|
|
use_lookahead = true;
|
|
}
|
|
void push_token() const {
|
|
use_lookahead = true;
|
|
}
|
|
|
|
op_t * parse_value_term(std::istream& in, unsigned short flags) const;
|
|
op_t * parse_predicate_expr(std::istream& in, unsigned short flags) const;
|
|
op_t * parse_path_expr(std::istream& in, unsigned short flags) const;
|
|
op_t * parse_unary_expr(std::istream& in, unsigned short flags) const;
|
|
op_t * parse_union_expr(std::istream& in, unsigned short flags) const;
|
|
op_t * parse_mul_expr(std::istream& in, unsigned short flags) const;
|
|
op_t * parse_add_expr(std::istream& in, unsigned short flags) const;
|
|
op_t * parse_logic_expr(std::istream& in, unsigned short flags) const;
|
|
op_t * parse_and_expr(std::istream& in, unsigned short flags) const;
|
|
op_t * parse_or_expr(std::istream& in, unsigned short flags) const;
|
|
op_t * parse_querycolon_expr(std::istream& in, unsigned short flags) const;
|
|
op_t * parse_value_expr(std::istream& in, unsigned short flags) const;
|
|
|
|
op_t * parse_expr(std::istream& in,
|
|
unsigned short flags = XPATH_PARSE_RELAXED) const;
|
|
|
|
op_t * parse_expr(const string& str,
|
|
unsigned short tflags = XPATH_PARSE_RELAXED) const
|
|
{
|
|
std::istringstream stream(str);
|
|
try {
|
|
return parse_expr(stream, tflags);
|
|
}
|
|
catch (error * err) {
|
|
err->context.push_back
|
|
(new line_context(str, (long)stream.tellg() - 1,
|
|
"While parsing value expression:"));
|
|
throw err;
|
|
}
|
|
}
|
|
|
|
op_t * parse_expr(const char * p,
|
|
unsigned short tflags = XPATH_PARSE_RELAXED) const {
|
|
return parse_expr(string(p), tflags);
|
|
}
|
|
|
|
bool write(std::ostream& out,
|
|
const bool relaxed,
|
|
const op_t * op_to_find,
|
|
unsigned long * start_pos,
|
|
unsigned long * end_pos) const {
|
|
if (ptr)
|
|
ptr->write(out, relaxed, op_to_find, start_pos, end_pos);
|
|
return true;
|
|
}
|
|
|
|
public:
|
|
string expr;
|
|
unsigned short flags; // flags used to parse `expr'
|
|
|
|
xpath_t() : ptr(NULL), use_lookahead(false), flags(0) {
|
|
TRACE_CTOR(xpath_t, "");
|
|
}
|
|
xpath_t(op_t * _ptr) : ptr(_ptr), use_lookahead(false) {
|
|
TRACE_CTOR(xpath_t, "op_t *");
|
|
}
|
|
|
|
xpath_t(const string& _expr,
|
|
unsigned short _flags = XPATH_PARSE_RELAXED)
|
|
: ptr(NULL), use_lookahead(false), flags(0) {
|
|
TRACE_CTOR(xpath_t, "const string&, unsigned short");
|
|
if (! _expr.empty())
|
|
parse(_expr, _flags);
|
|
}
|
|
xpath_t(std::istream& in, unsigned short _flags = XPATH_PARSE_RELAXED)
|
|
: ptr(NULL), use_lookahead(false), flags(0) {
|
|
TRACE_CTOR(xpath_t, "std::istream&, unsigned short");
|
|
parse(in, _flags);
|
|
}
|
|
xpath_t(const xpath_t& other)
|
|
: ptr(other.ptr ? other.ptr->acquire() : NULL),
|
|
use_lookahead(false), expr(other.expr), flags(other.flags) {
|
|
TRACE_CTOR(xpath_t, "copy");
|
|
}
|
|
virtual ~xpath_t() {
|
|
TRACE_DTOR(xpath_t);
|
|
reset(NULL);
|
|
}
|
|
|
|
xpath_t& operator=(const string& _expr) {
|
|
parse(_expr);
|
|
return *this;
|
|
}
|
|
xpath_t& operator=(const xpath_t& _expr);
|
|
xpath_t& operator=(xpath_t& _xpath) {
|
|
ptr = _xpath.ptr->acquire();
|
|
expr = _xpath.expr;
|
|
flags = _xpath.flags;
|
|
use_lookahead = false;
|
|
return *this;
|
|
}
|
|
|
|
operator op_t *() throw() {
|
|
return ptr;
|
|
}
|
|
|
|
operator bool() const throw() {
|
|
return ptr != NULL;
|
|
}
|
|
operator string() const throw() {
|
|
return expr;
|
|
}
|
|
|
|
void parse(const string& _expr, unsigned short _flags = XPATH_PARSE_RELAXED) {
|
|
expr = _expr;
|
|
flags = _flags;
|
|
op_t * tmp = parse_expr(_expr, _flags);
|
|
assert(tmp);
|
|
reset(tmp ? tmp->acquire() : NULL);
|
|
}
|
|
void parse(std::istream& in, unsigned short _flags = XPATH_PARSE_RELAXED) {
|
|
expr = "";
|
|
flags = _flags;
|
|
op_t * tmp = parse_expr(in, _flags);
|
|
assert(tmp);
|
|
reset(tmp ? tmp->acquire() : NULL);
|
|
}
|
|
|
|
void compile(const string& _expr, scope_t * scope = NULL,
|
|
unsigned short _flags = XPATH_PARSE_RELAXED) {
|
|
parse(_expr, _flags);
|
|
// jww (2006-09-24): fix
|
|
compile((node_t *)NULL, scope);
|
|
}
|
|
void compile(std::istream& in, scope_t * scope = NULL,
|
|
unsigned short _flags = XPATH_PARSE_RELAXED) {
|
|
parse(in, _flags);
|
|
// jww (2006-09-24): fix
|
|
compile((node_t *)NULL, scope);
|
|
}
|
|
|
|
void compile(document_t * document, scope_t * scope = NULL) {
|
|
if (! document) {
|
|
document_t tdoc;
|
|
compile(tdoc.top, scope);
|
|
} else {
|
|
compile(document->top, scope);
|
|
}
|
|
}
|
|
void compile(node_t * top_node, scope_t * scope = NULL) {
|
|
if (ptr) {
|
|
value_t noderef(top_node);
|
|
op_t * compiled = ptr->compile(&noderef, scope);
|
|
if (compiled == ptr)
|
|
compiled->release();
|
|
else
|
|
reset(compiled);
|
|
}
|
|
}
|
|
|
|
virtual void calc(value_t& result, node_t * node, scope_t * scope = NULL) const;
|
|
|
|
virtual value_t calc(document_t * document, scope_t * scope = NULL) const {
|
|
if (! ptr)
|
|
return 0L;
|
|
value_t temp;
|
|
calc(temp, document ? document->top : NULL, scope);
|
|
return temp;
|
|
}
|
|
virtual value_t calc(node_t * tcontext, scope_t * scope = NULL) const {
|
|
if (! ptr)
|
|
return 0L;
|
|
value_t temp;
|
|
calc(temp, tcontext, scope);
|
|
return temp;
|
|
}
|
|
|
|
static value_t eval(const string& _expr, document_t * document,
|
|
scope_t * scope = NULL) {
|
|
xpath_t temp(_expr);
|
|
return temp.calc(document, scope);
|
|
}
|
|
|
|
void write(std::ostream& out) const {
|
|
write(out, true, NULL, NULL, NULL);
|
|
}
|
|
void dump(std::ostream& out) const {
|
|
if (ptr)
|
|
ptr->dump(out, 0);
|
|
}
|
|
|
|
friend class scope_t;
|
|
};
|
|
|
|
} // namespace xml
|
|
|
|
template <typename T>
|
|
inline T * get_ptr(xml::xpath_t::scope_t * locals, unsigned int idx) {
|
|
assert(locals->args.size() > idx);
|
|
T * ptr = static_cast<T *>(locals->args[idx].to_pointer());
|
|
assert(ptr);
|
|
return ptr;
|
|
}
|
|
|
|
class xml_command : public xml::xpath_t::functor_t
|
|
{
|
|
public:
|
|
xml_command() : xml::xpath_t::functor_t("xml") {}
|
|
|
|
virtual void operator()(value_t&, xml::xpath_t::scope_t * locals) {
|
|
std::ostream * out = get_ptr<std::ostream>(locals, 0);
|
|
xml::document_t * doc = get_ptr<xml::document_t>(locals, 1);
|
|
|
|
doc->write(*out);
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace ledger
|
|
|
|
#endif // _XPATH_H
|