topical media & game development
server-php-xml-class-xquery-lite-class-xquery-lite.php / php
<?
// # # # # # # # # # # # # # # # # # # # ###
// Title : XqueryLite (class_xquery_lite.php)
// Version : 0.4 beta
// Author : Luis Argerich (lrargerich@yahoo.com)
// Last modification date : 05-21-2002
// Description : This is an implementation of a subset of the Xquery
// language with intention to add new features in
// next releases. It is based on flwr expressions.
// # # # # # # # # # # # # # # # # # # # ###
// History:
// 05-21-2002 : First release of this class from my prototype engine
// 05-17-2002 : Some changes to solve W3C use-cases
// # # # # # # # # # # # # # # # # # # # ###
// To-Dos:
// # # # # # # # # # # # # # # # # # # # ###
// How to use it:
// # # # # # # # # # # # # # # # # # # # ###
class XqueryLite {
var bindings=Array();
function init() {
this->bindings=Array();
}
function _tokenize(exprs=Array();
level=0;
exp," \n\t");
while (i=0;tok);tok,level++;
}
if(substr(i,1)=="}") {
level==0) {
if(in_array(trim(strtoupper(current)>0) {
current;
current.=tok = strtok(" \n\t");
}
if(strlen(exprs[]=current=exprs;
}
// This function is the "main" function of the flwr-lite engine, it evaluates a flwr expression
// returning an XML fragment as a string.
// The function won't be called only for top-level flwr expressions but for inner sub-expressions
// recursively as well.
function evaluate_xqueryl(result='';
i=0;
expr,level=0;
i<strlen(chr=='{') {
chr=='}') {
level>0) && (level>1)) {
chr;
}
if(level==0) {
if(strlen(result.=query);
}
chr<>"{") && (level==0) ){
chr;
}
chr=substr(i,1);
}
return node) {
node->node_name();
return name IN xmlmem(name IN xmldoc(name IN expr) {
tokens=split(" ",name=tokens[2])<>"IN") {
trigger_error("Invalid FOR expresion path= or document then
// queues the function and repeat
cosa=substr(path,0,1)<>'path,0,8)<>"document") && (substr(path,path=path=substr(path));
array_unshift(regs[1]);
}
path,2);
parts[0];
parts[1];
// Source maybe xmldoc(
// or xmlmem(xml)
// or
if(substr(xml_source,0,8)=='document') {
/* PROCESSING FROM A FILE */
ereg("document\((.*)\)",regs);
regs[1];
source);
if(!file_exists(name_doc file not found", E_USER_WARNING);
}
name_doc);
//doc->document_element());
//rootname.doc) {
trigger_error("XML source document xpath=ctx = result=path);
result->nodeset;
foreach(f) {
if(f="distinct";}
this->nodes);
}
nodes as node->node_type()==XML_ATTRIBUTE_NODE) {
node->value;
} else {
node->dump_node(xpath);
unset(cts);
unset(xml_source,0,6)=='xmlmem') {
/* PROCESSING FROM MEM */
ereg("xmlmem\((.*)\)",regs);
regs[1];
source);
source,1);
// NOTE THAT THE XML STRING MUST BE GLOBAL
if(!isset(name_var])) {
trigger_error("data=name_var];
if(strlen(doc=xmldoc(rootname=doc->document_element());
//rootname.doc) {
trigger_error("XML source was not well formed",E_USER_WARNING);
}
doc->xpath_init();
doc->xpath_new_context();
ctx->xpath_eval(nodes=functions as f=="distinct-values") {nodes=f(nodeset=Array();
foreach(node) {
if(nodeset[]=nodeset[]=node);
}
}
}
unset(doc);
unset(result);
} elseif(substr(') {
/* PROCESS FROM A VARIABLE */
//ereg("xmlmem\((.*)\)",regs);
xml_source;
source,1);
this->bindings[data)>0) {
data);
this->_get_root_name(path='/'.path;
if(!name_var was not well formed",E_USER_WARNING);
}
doc->xpath_init();
doc->xpath_new_context();
ctx->xpath_eval(nodes=functions as f=="distinct-values") {nodes=f(nodeset=Array();
foreach(node) {
if(nodeset=nodeset[]=node);
}
}
}
unset(doc);
unset(result);
} else {
trigger_error("Invalid xml source name_of_name=substr(this->result_sets[nodeset;
return nodeset) {
seen=Array();
nodeset);
foreach(node) {
this->normalize_elements(normalized,new_nodeset[]=seen[]=cant=count(new_nodeset;
}
// Normalize can eliminate all the tags
// If the node has only one child and it is text then just the text is returned
function _normalize_elements(node->node_type()==XML_ATTRIBUTE_NODE) {
return data=trim(node));
preg_match_all("/<([^>]*)>[^<]*<\/[^>]*>/",foo);
if(count(data=trim(preg_replace("/<.*>(.*)<\/.*>/","$1",node->node_type()==XML_ELEMENT_NODE) {
data);
data);
data);
}
}
return name/xpath_expression
// outside a FOR expression so it aways returns a
// string, if the xpath expression returned an element
// the element is normalized.
function _parse_var(norm) {
name/expr
expr,2);
parts[0],1);
if(strlen(path="/".data=var_name];
if(strlen(path)>0) {
data);
this->_get_root_name(path='/'.path;
if(!data is not xml ",E_USER_WARNING);
}
doc->xpath_init();
doc->xpath_new_context();
ctx->xpath_eval(nodes=nodes)>0) {
foreach(a_node ) {
if(res=a_node);
res;
} else {
if(res=result.=res=a_node);
res;
}
}
}
} else {
result=doc=xmldoc(root=doc);
if(result=_normalize_elements(root->node_type()==XML_ATTRIBUTE_NODE) {
print("dumping an attribute <br/>");
root->value;
} else {
root->dump_node(xpath);
unset(result_xp);
unset(result;
}
// This function is very similar to _parse_var BUT
// instead of returning the result or the variable
// it just counts the number of elements in the nodeset
function _count_var(result='';
// If it is a var is parts=explode("/",var_name=substr(parts[1])>0) {
parts[1];
}
this->bindings[data)==0) {
return '';
}
if(strlen(doc=xmldoc(rootname=doc->document_element());
rootname.doc) {
trigger_error("cannot evaluate a xpath expression because xpath=ctx = result_xp=path);
result_xp->nodeset;
unset(ctx);
unset(doc);
return count(result=doc=xmldoc(root=doc);
if(result=_normalize_elements(root->node_type()==XML_ATTRIBUTE_NODE) {
print("dumping an attribute <br/>");
root->value;
} else {
root->dump_node(result;
}
// This function parses a flwr-lite where expression returning
// true/false depending on the expression value
// First flwr variables followed or not by an expression are
// evaluated and replaced by their values
// then and/or are replaced by &&/||
// then a PHP eval construction is used to eval the expression
// :TODO: code this function
function _parse_where(result=true;
expr);
expr,5);
wexpr); wexpr);
wexpr);
if(strstr(wexpr,i=0;counts[1]);cant=counts[1][cosa=i];
cosa,"wexpr);
}
is_a_var=false;
i=0;wexpr);chr=substr(i,1);
if(") {
is_a_var=true;
}
if(chr,Array(' ',"\t","\n",';',"\n"))) {
chr=="[") {
chr=="]") {
predicate) {
if(in_array(is_a_var=false;
}
}
if(!vars[]=a_var='';
}
}
if(chr<>"a_var.=is_a_var) {
a_var;
}
// Now each variable must be evaluated
foreach(exp) {
'.ret=exp,1);
// And now strreplace ret='"'.wexpr=str_replace(ret,php_code='return('.result=eval(result;
}
// This function parses a flwr-lite RETURN expression
// basically a return expression just contains the word
// RETURN followed by another flwr-lite query that can
// contain flwr-lite expressions.
function _parse_return(expr=ltrim(result='';
// A return expr is
expr,6);
this->evaluate_xqueryl(sub;
}
// This function parses a flwr-lite LET expression
// a LET statement only binds an evaluation to a variable
// name
// Let won't normalize path expressions
function parse_let(expr=ltrim(name := value
expr,4);
letexpr);
tokens[0];
tokens[1];
var_value);
var_name);
if(strstr(')) {
// We are assigning to a var value
//var_value,1);
this->_parse_var(var_name=substr(this->bindings[var_value;
}
function _split_fors(fors=Array();
level=0;
for(i<strlen(i++) {
expr,chr=="[") {
chr=="]") {
chr==',') && (afor)>0) {
afor;
afor.=afor)>0) {
afor;
fors;
}
// This function parses a flwr-lite expression
// this function is called after filtering out XML constructs from
// a flwr-lite query
function _parse_query(result='';
this->_tokenize(expr=array_shift(expr=trim(tokens=split(" ",what=trim(what,0,1)=="result.=what,0);
} else {
switch(strtoupper(multi_fors=expr);
if(count(i=count(i>0;afor=ltrim(i]);
if(strtoupper(substr(afor='FOR '.afor=rtrim(exprs,expr=name=expr);
this->result_sets[nodes as this->bindings[node;
exprs); // What follows the FOR expr
this->_parse_query(this->_parse_where(query=implode("\n",result.=query);
}
break;
case "RETURN":
// If we have a return we parse the return and nothing can follow a return
// Theres nothing after a return
this->_parse_return(this->parse_let(query=implode("\n",result.=query);
break;
default:
// If we have something else (whitespace I hope) we process what follows
// :TODO: cambiar el implode
exprs);
this->_parse_query(result;
}
}
/*
b in xmlmem(b/publisher = "Addison-Wesley" and b/@year }">
{ bib='<bib>
<book year="1994">
<title>TCP/IP Illustrated</title>
<author><last>Stevens</last><first>W.</first></author>
<publisher>Addison-Wesley</publisher>
<price> 65.95</price>
</book>
<book year="1992">
<title>Advanced XML Programming in the Unix environment</title>
<author><last>Stevens</last><first>W.</first></author>
<publisher>Addison-Wesley</publisher>
<price>65.95</price>
</book>
<book year="2000">
<title>Data on the Web</title>
<author><last>Abiteboul</last><first>Serge</first></author>
<author><last>Buneman</last><first>Peter</first></author>
<author><last>Suciu</last><first>Dan</first></author>
<publisher>Morgan Kaufmann Publishers</publisher>
<price> 39.95</price>
</book>
<book year="1999">
<title>The Economics of Technology and Content for Digital TV</title>
<editor>
<last>Gerbarg</last><first>Darcy</first>
<affiliation>CITI</affiliation>
</editor>
<publisher>Kluwer Academic Publishers</publisher>
<price>129.95</price>
</book>
</bib>';
result=case1);
print("Result:<br />");
print("<textarea rows='20' cols='50'>
?>
(C) Æliens
20/2/2008
You may not copy or print any of this material without explicit permission of the author or the publisher.
In case of other copyright issues, contact the author.