mirror of
https://github.com/zeux/pugixml.git
synced 2024-12-31 00:13:01 +08:00
XPath: Added variable interface and implementation
git-svn-id: http://pugixml.googlecode.com/svn/trunk@676 99668b35-9821-0410-8761-19e4c4f06640
This commit is contained in:
parent
5442ff6aba
commit
7b4141582d
329
src/pugixml.cpp
329
src/pugixml.cpp
@ -4603,28 +4603,28 @@ namespace
|
||||
{
|
||||
using namespace pugi;
|
||||
|
||||
char_t* duplicate_string(const char_t* string, size_t length)
|
||||
{
|
||||
char_t* result = static_cast<char_t*>(get_memory_allocation_function()((length + 1) * sizeof(char_t)));
|
||||
if (!result) return 0; // $$ out of memory
|
||||
|
||||
memcpy(result, string, length * sizeof(char_t));
|
||||
result[length] = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
char_t* duplicate_string(const char_t* string)
|
||||
{
|
||||
return duplicate_string(string, strlength(string));
|
||||
}
|
||||
|
||||
class xpath_string
|
||||
{
|
||||
const char_t* _buffer;
|
||||
bool _uses_heap;
|
||||
|
||||
static char_t* duplicate_string(const char_t* string, size_t length)
|
||||
{
|
||||
char_t* result = static_cast<char_t*>(get_memory_allocation_function()((length + 1) * sizeof(char_t)));
|
||||
if (!result) return 0; // $$ out of memory
|
||||
|
||||
memcpy(result, string, length * sizeof(char_t));
|
||||
result[length] = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static char_t* duplicate_string(const char_t* string)
|
||||
{
|
||||
return duplicate_string(string, strlength(string));
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false)
|
||||
{
|
||||
}
|
||||
@ -5331,6 +5331,119 @@ namespace
|
||||
// zero-terminate
|
||||
*write = 0;
|
||||
}
|
||||
|
||||
struct xpath_variable_boolean: xpath_variable
|
||||
{
|
||||
bool value;
|
||||
char_t name[1];
|
||||
};
|
||||
|
||||
struct xpath_variable_number: xpath_variable
|
||||
{
|
||||
double value;
|
||||
char_t name[1];
|
||||
};
|
||||
|
||||
struct xpath_variable_string: xpath_variable
|
||||
{
|
||||
char_t* value;
|
||||
char_t name[1];
|
||||
};
|
||||
|
||||
struct xpath_variable_node_set: xpath_variable
|
||||
{
|
||||
xpath_node_set value;
|
||||
char_t name[1];
|
||||
};
|
||||
|
||||
const xpath_node_set dummy_node_set;
|
||||
|
||||
unsigned int hash_string(const char_t* str)
|
||||
{
|
||||
// Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time)
|
||||
unsigned int result = 0;
|
||||
|
||||
while (*str)
|
||||
{
|
||||
result += static_cast<unsigned int>(*str++);
|
||||
result += result << 10;
|
||||
result ^= result >> 6;
|
||||
}
|
||||
|
||||
result += result << 3;
|
||||
result ^= result >> 11;
|
||||
result += result << 15;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T> T* new_xpath_variable(const char_t* name)
|
||||
{
|
||||
size_t length = strlength(name);
|
||||
|
||||
// we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters
|
||||
void* memory = get_memory_allocation_function()(sizeof(T) + length * sizeof(char_t));
|
||||
if (!memory) return 0;
|
||||
|
||||
T* result = new (memory) T();
|
||||
|
||||
memcpy(result->name, name, (length + 1) * sizeof(char_t));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case xpath_type_node_set:
|
||||
return new_xpath_variable<xpath_variable_node_set>(name);
|
||||
|
||||
case xpath_type_number:
|
||||
return new_xpath_variable<xpath_variable_number>(name);
|
||||
|
||||
case xpath_type_string:
|
||||
return new_xpath_variable<xpath_variable_string>(name);
|
||||
|
||||
case xpath_type_boolean:
|
||||
return new_xpath_variable<xpath_variable_boolean>(name);
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void delete_xpath_variable(xpath_variable* var)
|
||||
{
|
||||
static_cast<T*>(var)->~T();
|
||||
get_memory_deallocation_function()(var);
|
||||
}
|
||||
|
||||
void delete_xpath_variable(xpath_value_type type, xpath_variable* var)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case xpath_type_node_set:
|
||||
delete_xpath_variable<xpath_variable_node_set>(var);
|
||||
break;
|
||||
|
||||
case xpath_type_number:
|
||||
delete_xpath_variable<xpath_variable_number>(var);
|
||||
break;
|
||||
|
||||
case xpath_type_string:
|
||||
delete_xpath_variable<xpath_variable_string>(var);
|
||||
break;
|
||||
|
||||
case xpath_type_boolean:
|
||||
delete_xpath_variable<xpath_variable_boolean>(var);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace pugi
|
||||
@ -8105,6 +8218,188 @@ namespace pugi
|
||||
return error ? error : "No error";
|
||||
}
|
||||
|
||||
const char_t* xpath_variable::name() const
|
||||
{
|
||||
switch (_type)
|
||||
{
|
||||
case xpath_type_node_set:
|
||||
return static_cast<const xpath_variable_node_set*>(this)->name;
|
||||
|
||||
case xpath_type_number:
|
||||
return static_cast<const xpath_variable_number*>(this)->name;
|
||||
|
||||
case xpath_type_string:
|
||||
return static_cast<const xpath_variable_string*>(this)->name;
|
||||
|
||||
case xpath_type_boolean:
|
||||
return static_cast<const xpath_variable_boolean*>(this)->name;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
xpath_value_type xpath_variable::type() const
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
bool xpath_variable::get_boolean() const
|
||||
{
|
||||
return (_type == xpath_type_boolean) ? static_cast<const xpath_variable_boolean*>(this)->value : false;
|
||||
}
|
||||
|
||||
double xpath_variable::get_number() const
|
||||
{
|
||||
return (_type == xpath_type_number) ? static_cast<const xpath_variable_number*>(this)->value : gen_nan();
|
||||
}
|
||||
|
||||
const char_t* xpath_variable::get_string() const
|
||||
{
|
||||
const char_t* value = (_type == xpath_type_string) ? static_cast<const xpath_variable_string*>(this)->value : 0;
|
||||
return value ? value : PUGIXML_TEXT("");
|
||||
}
|
||||
|
||||
const xpath_node_set& xpath_variable::get_node_set() const
|
||||
{
|
||||
return (_type == xpath_type_node_set) ? static_cast<const xpath_variable_node_set*>(this)->value : dummy_node_set;
|
||||
}
|
||||
|
||||
bool xpath_variable::set(bool value)
|
||||
{
|
||||
if (_type != xpath_type_boolean) return false;
|
||||
|
||||
static_cast<xpath_variable_boolean*>(this)->value = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xpath_variable::set(double value)
|
||||
{
|
||||
if (_type != xpath_type_number) return false;
|
||||
|
||||
static_cast<xpath_variable_number*>(this)->value = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xpath_variable::set(const char_t* value)
|
||||
{
|
||||
if (_type != xpath_type_string) return false;
|
||||
|
||||
xpath_variable_string* var = static_cast<xpath_variable_string*>(this);
|
||||
|
||||
// duplicate string
|
||||
char_t* copy = duplicate_string(value);
|
||||
if (!copy) return false;
|
||||
|
||||
// replace old string
|
||||
if (var->value) get_memory_deallocation_function()(var->value);
|
||||
var->value = copy;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xpath_variable::set(const xpath_node_set& value)
|
||||
{
|
||||
if (_type != xpath_type_node_set) return false;
|
||||
|
||||
static_cast<xpath_variable_node_set*>(this)->value = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
xpath_variable_set::xpath_variable_set()
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0;
|
||||
}
|
||||
|
||||
xpath_variable_set::~xpath_variable_set()
|
||||
{
|
||||
for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
|
||||
{
|
||||
xpath_variable* var = _data[i];
|
||||
|
||||
while (var)
|
||||
{
|
||||
xpath_variable* next = var->_next;
|
||||
|
||||
delete_xpath_variable(var->_type, var);
|
||||
|
||||
var = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xpath_variable* xpath_variable_set::find(const char_t* name) const
|
||||
{
|
||||
const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
|
||||
size_t hash = hash_string(name) % hash_size;
|
||||
|
||||
// look for existing variable
|
||||
for (xpath_variable* var = _data[hash]; var; var = var->_next)
|
||||
if (strequal(var->name(), name))
|
||||
return var;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type)
|
||||
{
|
||||
const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
|
||||
size_t hash = hash_string(name) % hash_size;
|
||||
|
||||
// look for existing variable
|
||||
for (xpath_variable* var = _data[hash]; var; var = var->_next)
|
||||
if (strequal(var->name(), name))
|
||||
return var->type() == type ? var : 0;
|
||||
|
||||
// add new variable
|
||||
xpath_variable* result = new_xpath_variable(type, name);
|
||||
|
||||
if (result)
|
||||
{
|
||||
result->_type = type;
|
||||
result->_next = _data[hash];
|
||||
|
||||
_data[hash] = result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool xpath_variable_set::set(const char_t* name, bool value)
|
||||
{
|
||||
xpath_variable* var = add(name, xpath_type_boolean);
|
||||
return var ? var->set(value) : false;
|
||||
}
|
||||
|
||||
bool xpath_variable_set::set(const char_t* name, double value)
|
||||
{
|
||||
xpath_variable* var = add(name, xpath_type_number);
|
||||
return var ? var->set(value) : false;
|
||||
}
|
||||
|
||||
bool xpath_variable_set::set(const char_t* name, const char_t* value)
|
||||
{
|
||||
xpath_variable* var = add(name, xpath_type_string);
|
||||
return var ? var->set(value) : false;
|
||||
}
|
||||
|
||||
bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value)
|
||||
{
|
||||
xpath_variable* var = add(name, xpath_type_node_set);
|
||||
return var ? var->set(value) : false;
|
||||
}
|
||||
|
||||
xpath_variable* xpath_variable_set::get(const char_t* name)
|
||||
{
|
||||
return find(name);
|
||||
}
|
||||
|
||||
const xpath_variable* xpath_variable_set::get(const char_t* name) const
|
||||
{
|
||||
return find(name);
|
||||
}
|
||||
|
||||
xpath_query::xpath_query(const char_t* query): _alloc(0), _root(0)
|
||||
{
|
||||
_result.error = 0;
|
||||
|
@ -1804,6 +1804,68 @@ namespace pugi
|
||||
const char* description() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that holds XPath variable
|
||||
*/
|
||||
class xpath_variable
|
||||
{
|
||||
friend class xpath_variable_set;
|
||||
|
||||
protected:
|
||||
// Non-copyable semantics
|
||||
xpath_variable(const xpath_variable&);
|
||||
xpath_variable& operator=(const xpath_variable&);
|
||||
|
||||
xpath_value_type _type;
|
||||
xpath_variable* _next;
|
||||
|
||||
xpath_variable() {}
|
||||
~xpath_variable() {}
|
||||
|
||||
public:
|
||||
const char_t* name() const;
|
||||
xpath_value_type type() const;
|
||||
|
||||
bool get_boolean() const;
|
||||
double get_number() const;
|
||||
const char_t* get_string() const;
|
||||
const xpath_node_set& get_node_set() const;
|
||||
|
||||
bool set(bool value);
|
||||
bool set(double value);
|
||||
bool set(const char_t* value);
|
||||
bool set(const xpath_node_set& value);
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that holds XPath variables
|
||||
*/
|
||||
class xpath_variable_set
|
||||
{
|
||||
private:
|
||||
// Non-copyable semantics
|
||||
xpath_variable_set(const xpath_variable_set&);
|
||||
xpath_variable_set& operator=(const xpath_variable_set&);
|
||||
|
||||
xpath_variable* _data[64];
|
||||
|
||||
xpath_variable* find(const char_t* name) const;
|
||||
|
||||
public:
|
||||
xpath_variable_set();
|
||||
~xpath_variable_set();
|
||||
|
||||
xpath_variable* add(const char_t* name, xpath_value_type type);
|
||||
|
||||
bool set(const char_t* name, bool value);
|
||||
bool set(const char_t* name, double value);
|
||||
bool set(const char_t* name, const char_t* value);
|
||||
bool set(const char_t* name, const xpath_node_set& value);
|
||||
|
||||
xpath_variable* get(const char_t* name);
|
||||
const xpath_variable* get(const char_t* name) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that holds compiled XPath query and allows to evaluate query result
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user