Source for file SparqlEngine.php

Documentation is available at SparqlEngine.php

  1. <?php
  2. require_once RDFAPI_INCLUDE_DIR 'util/Object.php';
  3. require_once RDFAPI_INCLUDE_DIR 'sparql/FilterFunctions.php';
  4. require_once RDFAPI_INCLUDE_DIR 'sparql/SparqlEngine/ResultConverter.php';
  5.  
  6. // ----------------------------------------------------------------------------------
  7. // Class: SparqlEngine
  8. // ----------------------------------------------------------------------------------
  9.  
  10. /**
  11. * This engine executes SPARQL queries against an RDF Datatset.
  12. *
  13. @version  $Id: fsource_sparql__sparqlSparqlEngine.php.html 443 2007-06-01 16:25:38Z cax $
  14. @author   Tobias Gauß <tobias.gauss@web.de>
  15. *
  16. @package sparql
  17. */
  18.  
  19. Class SparqlEngine extends Object{
  20.  
  21.  
  22.     /**
  23.     *   The query object.
  24.     *   @var Query 
  25.     */
  26.     protected $query;
  27.  
  28.     /**
  29.     *   The RDF Dataset.
  30.     *   @var Dataset 
  31.     */
  32.     protected $dataset;
  33.  
  34.  
  35.  
  36.     /**
  37.     * Use SparqlEngine::factory() instead of this
  38.     * constructor.
  39.     */
  40.     protected function __construct()
  41.     {
  42.         //protected to prevent direct instantiation
  43.     }
  44.  
  45.  
  46.     /**
  47.     * Creates a new instance of the SparqlEngine, depending on the
  48.     * given model. For example, if you pass a DbModel, you will
  49.     * get a SparqlEngine specialized on databases.
  50.     *
  51.     * @param Model $model   RDF model that uses the engine
  52.     */
  53.     public function factory($model null)
  54.     {
  55.         if ($model !== null && $model instanceof DbModel{
  56.             require_once RDFAPI_INCLUDE_DIR 'sparql/SparqlEngineDb.php';
  57.             return new SparqlEngineDb($model);
  58.         else {
  59.             return new SparqlEngine();
  60.         }
  61.     }
  62.  
  63.  
  64.  
  65.     /**
  66.     * The query engine's main method.
  67.     *
  68.     * @param  Dataset       $dataset    the RDF Dataset
  69.     * @param  mixed         $query      the parsed SPARQL query
  70.     * @param  String        $resultform the result form. If set to 'xml' the result will be
  71.     *                                    SPARQL Query Results XML Format as described in http://www.w3.org/TR/rdf-sparql-XMLres/ .
  72.     * @return Array/String  Type of the result depends on $resultform.
  73.     */
  74.     public function queryModel($datasetQuery $query$resultform false)
  75.     {
  76.         $this->query   = $query;
  77.         $this->dataset = $dataset;
  78.  
  79.         if($this->query->isEmpty){
  80.             $vartable[0]['patternResult'null;
  81.             return SparqlEngine_ResultConverter::convertFromResult(
  82.                 $vartable,
  83.                 $this,
  84.                 $resultform
  85.             );
  86.         }
  87.  
  88.         $graphlist $this->preselectGraphs();
  89.         /// match graph patterns against the RDF Dataset
  90.         $patternlist $this->matchPatterns($graphlist);
  91.         // filter results- apply inner filters
  92.         $patternlist $this->filterPatterns($patternlist,false);
  93.         // join pattern results
  94.         $vartable $this->joinResults($patternlist);
  95.         // filter results- apply outer filters
  96.         $vartable $this->filterPatterns($vartable,true);
  97.  
  98.         if ($vartable[0]['patternResult'!= null{
  99.             // sort vars (ORDER BY, LIMIT, OFFSET)
  100.             $vartable $this->sortVars($vartable[0]['patternResult']);
  101.             $qrf      $this->query->getResultForm();
  102.             if ($qrf == 'select' || $qrf == 'select distinct'{
  103.                 $vars     $this->query->getResultVars();
  104.                 $vartable $this->selectVars($vartable$vars);
  105.                 if ($qrf == 'select distinct'{
  106.                     $vartable $this->distinct($vartable);
  107.                 }
  108.             }
  109.         else {
  110.             $vartable null;
  111.         }
  112.  
  113.             $vartable,
  114.             $this,
  115.             $resultform
  116.         );
  117.     }//public function queryModel($dataset, Query $query, $resultform = false)
  118.  
  119.  
  120.  
  121.     /**
  122.     * Matches all graph Patterns against the dataset and generates an array which
  123.     * contains the result sets for every given GraphPattern.
  124.     *
  125.     * @param  Array      $graphlist   the graphlist which contains the names of the named
  126.     *                     graphs which has to be queried.
  127.     * @return Array 
  128.     */
  129.     protected function matchPatterns($graphlist){
  130.         $patternlist array();
  131.         // get the result part from the query
  132.         $resultPart $this->query->getResultPart();
  133.         // for each GrapPattern in the result part
  134.         if($resultPart)
  135.         foreach($resultPart as $graphPattern){
  136.             $this->matchPattern($patternlist$graphlist$graphPattern);
  137.         }
  138.         return $patternlist;
  139.     }
  140.  
  141.  
  142.  
  143.     /**
  144.     * Finds tuples that match one graph pattern.
  145.     *
  146.     * @param  Array        $patternlist list that contains the graphPatterns
  147.     * @param  array        $graphlist   the graphlist
  148.     * @param  GraphPattern $graphPattern the pattern which has to be matched
  149.     * @return void 
  150.     */
  151.     protected function matchPattern(&$patternlist$graphlist&$graphPattern{
  152.         // generate an empty result set
  153.         $finalRes null;
  154.         // if the GraphPattern has triple patterns
  155.         if($graphPattern->getTriplePattern()>0){
  156.             // check if the pattern has a GRAPH clause and if this Iri is in $graphlist
  157.             $newGraphList $this->_checkGraphs($graphPattern,$graphlist);
  158.             if($newGraphList){
  159.                 $qt $graphPattern->getTriplePattern();
  160.                 $resultSet $this->findTuplesMatchingOnePattern($qt[0]$newGraphList);
  161.                 for ($i=1$i<count($qt)$i++{
  162.                     $rs $this->findTuplesMatchingOnePattern($qt[$i]$newGraphList);
  163.                     $resultSet $this->joinTuples($resultSet$rs);
  164.                     if(!$resultSet)
  165.                     break;
  166.                 }
  167.                 if($finalRes != null){
  168.                     $finalRes $this->joinTuples($finalRes,$resultSet);
  169.                 }else{
  170.                     $finalRes $resultSet;
  171.                 }
  172.             }
  173.         }
  174.         // dependencies between pattern results
  175.         $patternlist[$graphPattern->getId()]['hasOptional']     0;
  176.         $patternlist[$graphPattern->getId()]['hasUnion']        0;
  177.         $patternlist[$graphPattern->getId()]['patternResult']   $finalRes;
  178.  
  179.         $op $graphPattern->getOptional();
  180.         $un $graphPattern->getUnion();
  181.  
  182.         $patternlist[$graphPattern->getId()]['optionalTo']      $op;
  183.         if(is_int($op))
  184.         $patternlist[$op]['hasOptional']++;
  185.  
  186.         $patternlist[$graphPattern->getId()]['unionWith']       $un;
  187.         if(is_int($un))
  188.         $patternlist[$un]['hasUnion']++;
  189.  
  190.         $constraint $graphPattern->getConstraint();
  191.         if($constraint != null){
  192.             foreach($constraint as $constr){
  193.                 if($constr->isOuterFilter()){
  194.                     $patternlist[$graphPattern->getId()]['outerFilter'][]          $constr;
  195.                     $patternlist[$graphPattern->getId()]['innerFilter'][]          null;
  196.                 }else{
  197.                     $patternlist[$graphPattern->getId()]['innerFilter'][]          $constr;
  198.                     $patternlist[$graphPattern->getId()]['outerFilter'][]          null;
  199.                 }
  200.             }
  201.         }else{
  202.             $patternlist[$graphPattern->getId()]['innerFilter']          null;
  203.             $patternlist[$graphPattern->getId()]['outerFilter']          null;
  204.         }
  205.     }
  206.  
  207.  
  208.     /**
  209.     * Finds Tuples matching one TriplePattern.
  210.     *
  211.     * @param  TriplePattern $pattern 
  212.     * @param  Array         $graphlist 
  213.     * @return Array 
  214.     */
  215.     protected function findTuplesMatchingOnePattern($pattern$graphlist){
  216.         $var null;
  217.         $sub  $pattern->getSubject();
  218.         $pred $pattern->getPredicate();
  219.         $obj  $pattern->getObject();
  220.  
  221.         if(is_string($sub)||$sub instanceof BlankNode){
  222.             if(is_string($sub))
  223.             $var['sub'$sub;
  224.             $sub null;
  225.         }
  226.         if(is_string($pred)||$pred instanceof BlankNode ){
  227.             if(is_string($pred))
  228.             $var['pred'$pred;
  229.             $pred null;
  230.         }
  231.         if(is_string($obj)||$obj instanceof BlankNode){
  232.             if(is_string($obj))
  233.             $var['obj'$obj;
  234.             $obj null;
  235.         }
  236.         $intBindings $this->_buildIntBindings($var);
  237.         $k 0;
  238.  
  239.         $key 0;
  240.         // search in named graphs
  241.         if($graphlist['var'][0!= null||$graphlist['list'][0!= null){
  242.             foreach($graphlist['list'as $key => $graphnode){
  243.  
  244.                 // query the dataset
  245.                 $it $this->dataset->findInNamedGraphs($graphnode,$sub,$pred,$obj,false);
  246.                 if($it->valid()){
  247.                     // add statements to the result list
  248.                     while($it->valid()){
  249.                         if($graphnode == null){
  250.                             $element $it->current()->getStatement();
  251.                             $grname  $it->current()->getGraphname();
  252.                         }else{
  253.                             if($it->current(instanceof Quad)
  254.                                 $element $it->current()->getStatement();
  255.                             else
  256.                                 $element $it->current();
  257.  
  258.                             $grname  $graphnode;
  259.                         }
  260.                         if($this->checkIntBindings($element,$intBindings)){
  261.                             $resmodel['trip'][$k]  $element;
  262.                             $resmodel['graph'][$k$grname;
  263.                         //    $resmodel['graphvar'][$k] = $graphlist['var'][$key];
  264.                             $resmodel['graphvar'][$k$graphlist['var'][0];
  265.                             $k++;
  266.  
  267.                         }
  268.                         $it->next();
  269.                     }
  270.                 }
  271.  
  272.             }
  273.         }
  274.         // search in the default graph
  275.         if($graphlist['list'][0== null && $graphlist['var'][0== null){
  276.  
  277.  
  278.             $gr $this->dataset->getDefaultGraph();
  279.  
  280.             $res $gr->find($sub,$pred,$obj);
  281.  
  282.             foreach($res->triples as $innerkey => $element){
  283.                 if($this->checkIntBindings($element,$intBindings)){
  284.                         $resmodel['trip'][$k]  $element;
  285.                         $resmodel['graph'][$knull;
  286.                         $resmodel['graphvar'][$k$graphlist['var'][$key];
  287.                         $k++;
  288.                     }
  289.             }
  290.         }
  291.         if($k == 0)
  292.         return false;
  293.         return $this->_buildResultSet($pattern,$resmodel);
  294.     }
  295.  
  296.     /**
  297.     * Checks it there are internal bindings between variables.
  298.     *
  299.     * @param  Triple  $trip 
  300.     * @param  Array   $intBindings 
  301.     * @return boolean 
  302.     */
  303.     protected function checkIntBindings($trip$intBindings){
  304.         switch($intBindings){
  305.             case -1:
  306.             return true;
  307.             break;
  308.             case 0:
  309.             if($trip->subj != $trip->pred)
  310.             return false;
  311.             break;
  312.             case 1:
  313.             if(is_a($trip->obj,'Literal'))
  314.             return false;
  315.             if($trip->subj != $trip->obj)
  316.             return false;
  317.             break;
  318.             case 2:
  319.             if(is_a($trip->obj,'Literal'))
  320.             return false;
  321.             if($trip->pred != $trip->obj)
  322.             return false;
  323.             break;
  324.             case 3:
  325.             if(is_a($trip->obj,'Literal'))
  326.             return false;
  327.             if($trip->pred != $trip->obj || $trip->pred != $trip->subj )
  328.             return false;
  329.             break;
  330.         }
  331.         return true;
  332.     }
  333.  
  334.  
  335.     /**
  336.     * Perform an SQL-like inner join on two resultSets.
  337.     *
  338.     * @param   Array   &$finalRes 
  339.     * @param   Array   &$res 
  340.     * @return  Array 
  341.     */
  342.     protected function joinTuples(&$finalRes&$res{
  343.  
  344.         if (!$finalRes || !$res)
  345.         return array();
  346.  
  347.         // find joint variables and new variables to be added to $finalRes
  348.         $jointVars array();
  349.         $newVars array();
  350.         $k key($res);
  351.  
  352.         foreach ($res[$kas $varname => $node{
  353.             if (array_key_exists($varname$finalRes[0]))
  354.             $jointVars[$varname;
  355.             else
  356.             $newVars[$varname;
  357.         }
  358.  
  359.         // eliminate rows of $finalRes in which the values of $jointVars do not have
  360.         // a corresponding row in $res.
  361.         foreach ($finalRes as $n => $fRes{
  362.             foreach ($res as $i => $r{
  363.                 $ok TRUE;
  364.                 foreach ($jointVars as $j_varname)
  365.                 if ($r[$j_varname!= $fRes[$j_varname]{
  366.                     $ok FALSE;
  367.                     break;
  368.                 }
  369.                 if ($ok)
  370.                 break;
  371.             }
  372.             if (!$ok)
  373.             unset($finalRes[$n]);
  374.         }
  375.  
  376.         // join $res and $finalRes
  377.         $joinedRes array();
  378.         foreach ($res as $r{
  379.             foreach ($finalRes as $n => $fRes{
  380.                 $ok TRUE;
  381.                 foreach ($jointVars as $j_varname)
  382.                 if ($r[$j_varname!= $fRes[$j_varname]{
  383.                     $ok FALSE;
  384.                     break;
  385.                 }
  386.                 if ($ok{
  387.                     $joinedRow $finalRes[$n];
  388.                     foreach($newVars as $n_varname)
  389.                     $joinedRow[$n_varname$r[$n_varname];
  390.                     $joinedRes[$joinedRow;
  391.                 }
  392.             }
  393.         }
  394.         return $joinedRes;
  395.     }
  396.  
  397.  
  398.     /**
  399.     * Joins OPTIONAL pattern results.
  400.     *
  401.     * @param   Array   &$finalRes 
  402.     * @param   Array   &$res 
  403.     * @return  Array    the joined Array
  404.     */
  405.     protected function joinOptionalTuples(&$finalRes&$res{
  406.  
  407.         if(!$finalRes && !$res)
  408.         return array();
  409.  
  410.         if(!$finalRes)
  411.         return $res;
  412.  
  413.         if(!$res)
  414.         return $finalRes;
  415.  
  416.         // find joint variables and new variables to be added to $finalRes
  417.         $jointVars array();
  418.         $newVars array();
  419.         $result array();
  420.  
  421.         $k key($res);
  422.  
  423.         foreach ($res[$kas $varname => $node{
  424.             if (array_key_exists($varname$finalRes[0])){
  425.                 $jointVars[$varname;
  426.             }else{
  427.                 $newVars[$varname;
  428.             }
  429.         }
  430.         $joined array();
  431.         $joinc 0;
  432.         foreach($finalRes as $i =>$fRes){
  433.             foreach($res as $n =>$r){
  434.                 $join false;
  435.                 foreach($jointVars as $j_varname){
  436.                     if($r[$j_varname]==$fRes[$j_varname]){
  437.                         $join true;
  438.                         //break;
  439.                     }else{
  440.                         $join false;
  441.                     }
  442.                 }
  443.                 if($join){
  444.                     $result[$joinc$fRes;
  445.                     foreach($newVars as $n_varname)
  446.                     $result[$joinc][$n_varname$r[$n_varname];
  447.                     $joined[]=$n;
  448.                     $joinc++;
  449.                 }
  450.  
  451.             }
  452.         }
  453.  
  454.         $count count($result);
  455.         foreach($res as $k =>$val){
  456.             if(!in_array($k,$joined)){
  457.                 $result[$count$finalRes[0];
  458.                 foreach($result[$countas $varname => $varVal){
  459.                     $result[$count][$varname]='';
  460.                 }
  461.  
  462.                 foreach($val as $varname2 => $varVal2){
  463.                     $result[$count][$varname2]=$varVal2;
  464.                 }
  465.                 $count++;
  466.             }
  467.         }
  468.         return $result;
  469.     }
  470.  
  471.  
  472.  
  473.     /**
  474.     * Looks in from and from named part of the query and
  475.     * adds the graphs to the graphlist.
  476.     *
  477.     * @return Array 
  478.     */
  479.     protected function preselectGraphs(){
  480.         $fromNamed $this->query->getFromNamedPart();
  481.         if($fromNamed == null)
  482.         $fromNamed[null;
  483.         return $fromNamed;
  484.     }
  485.  
  486.  
  487.     /**
  488.     * Evaluates the GRPAH clause if there is one. Checks if
  489.     * the GRAPH clause contains an IRI, variable or nothing.
  490.     * Returns an array which contains the graphs that has to be matched.
  491.     *
  492.     * @param  GraphPattern $pattern 
  493.     * @param  Array        $graphlist 
  494.     * @return Array 
  495.     */
  496.     protected function _checkGraphs(&$pattern,$graphlist){
  497.  
  498.         $gr $pattern->getGraphname();
  499.         if($gr instanceof Resource ){
  500.             if($graphlist[0]==null || in_array($gr,$graphlist)){
  501.                 $newGraphList['list'][$gr;
  502.                 $newGraphList['var'][]  null;
  503.             }else{
  504.                 return false;
  505.             }
  506.         }elseif (is_string($gr)){
  507.             $newGraphList['list'$graphlist;
  508.             $newGraphList['var'][]  $gr;
  509.         }else{
  510.             $newGraphList['list'$graphlist;
  511.             $newGraphList['var'][]  null;
  512.         }
  513.         return $newGraphList;
  514.     }
  515.  
  516.     /**
  517.     * Marks triples with internal bindings.
  518.     * int bindings -1 :none 0:sub=pred 1:sub=obj 2:pred=obj 3:sub=pred=obj.
  519.     *
  520.     * @param  Array $var 
  521.     * @return Array 
  522.     */
  523.     protected function _buildIntBindings($var){
  524.         $intBindings = -1;
  525.         if(!$var)
  526.         return $intBindings;
  527.  
  528.         if(isset($var['sub'])){
  529.             if(isset($var['pred']))
  530.             if($var['sub'== $var['pred'])
  531.             $intBindings 0;
  532.             if(isset($var['obj']))
  533.             if($var['sub'== $var['obj']){
  534.                 if$intBindings == 0){
  535.                     $intBindings 3;
  536.                 }else{
  537.                     $intBindings 1;
  538.                 }
  539.             }
  540.         }
  541.         if(isset($var['pred'])){
  542.             if(isset($var['obj']))
  543.             if($var['pred']==$var['obj']&&$intBindings!=3)
  544.             $intBindings 2;
  545.         }
  546.         return $intBindings;
  547.     }
  548.  
  549.     /**
  550.     * Builds the resultset.
  551.     *
  552.     * @param  GraphPattern $pattern 
  553.     * @param  Array        $resmodel 
  554.     * @return Array 
  555.     */
  556.     protected function _buildResultSet($pattern,$resmodel){
  557.         // determine variables and their corresponding values
  558.         $result null;
  559.         if(is_string($pattern->getSubject())){
  560.             $n 0;
  561.             foreach($resmodel['trip'as $key => $triple){
  562.                 if(isset($resmodel['graphvar'][$key]))
  563.                 $result[$n][$resmodel['graphvar'][$key]] $resmodel['graph'][$key];
  564.                 $result[$n++][$pattern->getSubject()$triple->subj;
  565.             }
  566.         }
  567.         if(is_string($pattern->getPredicate())){
  568.             $n 0;
  569.             foreach($resmodel['trip'as $key => $triple){
  570.                 if(isset($resmodel['graphvar'][$key]))
  571.                 $result[$n][$resmodel['graphvar'][$key]] $resmodel['graph'][$key];
  572.                 $result[$n++][$pattern->getPredicate()$triple->pred;
  573.             }
  574.         }
  575.         if(is_string($pattern->getObject())){
  576.             $n 0;
  577.             foreach($resmodel['trip'as $key => $triple){
  578.                 if(isset($resmodel['graphvar'][$key]))
  579.                 $result[$n][$resmodel['graphvar'][$key]] $resmodel['graph'][$key];
  580.                 $result[$n++][$pattern->getObject()$triple->obj;
  581.             }
  582.         }
  583.         return $result;
  584.     }
  585.  
  586.     /**
  587.     * Selects the result variables and builds a result table.
  588.     *
  589.     * @param  Array  $table the result table
  590.     * @param  Array  $vars the result variables
  591.     * @return Array 
  592.     */
  593.     protected function selectVars($table,$vars){
  594.         if($vars[0]=='*')
  595.         $vars $this->query->getAllVars();
  596.         $resTable array();
  597.         $hits 0;
  598.         foreach($table as $val){
  599.             foreach($vars as $var){
  600.                 if(isset($val[$var])){
  601.                     $resTable[$hits][$var]=$val[$var];
  602.                 }else{
  603.                     $resTable[$hits][$var]="";
  604.                 }
  605.             }
  606.             $hits++;
  607.         }
  608.         return $resTable;
  609.     }
  610.  
  611.     /**
  612.     * Joins the results of the different Graphpatterns.
  613.     *
  614.     * @param  Array $patternlist 
  615.     * @return Array 
  616.     */
  617.     protected function joinResults($patternlist){
  618.         $joined[0]['patternResult'null;
  619.         $joined[0]['outerFilter'null;
  620.  
  621.         while(count($patternlist)>0){
  622.             foreach($patternlist as $key => $pattern){
  623.                 if($pattern['hasOptional'== && $pattern['hasUnion'== 0){
  624.                     if(is_int($pattern['optionalTo'])){
  625.                         $patternlist[$pattern['optionalTo']]['hasOptional']--;
  626.                         $patternlist[$pattern['optionalTo']]['patternResult'$this->joinOptionalTuples($pattern['patternResult'],$patternlist[$pattern['optionalTo']]['patternResult']);
  627.                         unset($patternlist[$key]);
  628.                         break;
  629.                     }
  630.                     else if(is_int($pattern['unionWith'])){
  631.                         $patternlist[$pattern['unionWith']]['hasUnion']--;
  632.                         foreach($pattern['patternResult'as $value)
  633.                         array_push($patternlist[$pattern['unionWith']]['patternResult'],$value);
  634.                         unset($patternlist[$key]);
  635.                         break;
  636.                     }else{
  637.                         if($joined[0]['patternResult'== null){
  638.                             $joined[0]['patternResult'$pattern['patternResult'];
  639.                             if($joined[0]['outerFilter'== null )
  640.                             $joined[0]['outerFilter']  $pattern['outerFilter'];
  641.                             unset($patternlist[$key]);
  642.                             break;
  643.                         }
  644.                     //    if($pattern['patternResult'] !=null ){
  645.                             $joined[0]['patternResult'$this->joinTuples($joined[0]['patternResult'],$pattern['patternResult']);
  646.                             $joined[0]['outerFilter']   $pattern['outerFilter'];
  647.                             unset($patternlist[$key]);
  648.                             break;
  649.                     //    }
  650.                     }
  651.                 }
  652.             }
  653.         }
  654.         return $joined;
  655.     }
  656.  
  657.     /**
  658.     * Filters the pattern results.
  659.     *
  660.     * @param  Array   $patternlist list containing the results of the GraphPatterns
  661.     * @param  boolean $outer TRUE if its an outer filter FALSE if not
  662.     * @return Array   the filtered patternlist
  663.     */
  664.     protected function filterPatterns($patternlist,$outer){
  665.         if($outer)
  666.         $filter 'outerFilter';
  667.         else
  668.         $filter 'innerFilter';
  669.         foreach($patternlist as $patkey => $pattern){
  670.             // get constraints
  671.             $constraint $pattern[$filter];
  672.  
  673.             if(count($constraint)>0){
  674.                 foreach($constraint as $constr){
  675.                     if($constr != null){
  676.                         // extract Vars and function calls
  677.                         $evalString $constr->getExpression();
  678.                         preg_match_all("/\?.[^\s\)\,]*/",$evalString,$vars);
  679.                         preg_match_all("/bound\((.[^\)]*)\)/i",$evalString,$boundcalls);
  680.                         preg_match_all("/isuri\((.[^\)]*)\)/i",$evalString,$isUricalls);
  681.                         preg_match_all("/isblank\((.[^\)]*)\)/i",$evalString,$isBlankcalls);
  682.                         preg_match_all("/isLiteral\((.[^\)]*)\)/i",$evalString,$isLiteralcalls);
  683.                         preg_match_all("/lang\((.[^\)]*)\)/i",$evalString,$langcalls);
  684.                         preg_match_all("/datatype\((.[^\)]*)\)/i",$evalString,$datatypecalls);
  685.                         preg_match_all("/str\((.[^\)]*)\)/i",$evalString,$stringcalls);
  686.  
  687.                         // is Bound
  688.                         if(count($boundcalls[1])>0)
  689.                         $function['bound'$boundcalls[1];
  690.                         else
  691.                         $function['bound'false;
  692.  
  693.                         // is URI
  694.                         if(count($isUricalls[1])>0)
  695.                         $function['isUri'$isUricalls[1];
  696.                         else
  697.                         $function['isUri'false;
  698.  
  699.                         // is Blank
  700.                         if(count($isBlankcalls[1])>0)
  701.                         $function['isBlank'$isBlankcalls[1];
  702.                         else
  703.                         $function['isBlank'false;
  704.  
  705.                         // is Literal
  706.                         if(count($isLiteralcalls[1])>0)
  707.                         $function['isLiteral'$isLiteralcalls[1];
  708.                         else
  709.                         $function['isLiteral'false;
  710.  
  711.                         // lang
  712.                         if(count($langcalls[1])>0)
  713.                         $function['lang'$langcalls[1];
  714.                         else
  715.                         $function['lang'false;
  716.  
  717.                         // datatype
  718.                         if(count($datatypecalls[1])>0)
  719.                         $function['datatype'$datatypecalls[1];
  720.                         else
  721.                         $function['datatype'false;
  722.  
  723.                         // string
  724.                         if(count($stringcalls[1])>0)
  725.                         $function['string'$stringcalls[1];
  726.                         else
  727.                         $function['string'false;
  728.  
  729.  
  730.                         foreach($pattern['patternResult'as $key => $res){
  731.                             $result false;
  732.                             $evalString $this->fillConstraintString($vars,$res,$constr,$function);
  733.                             $evalString '$result =('.$evalString.');';
  734.                             // evaluate Constraint
  735.                             @eval($evalString);
  736.  
  737.                             if(!$result)
  738.                             unset($patternlist[$patkey]['patternResult'][$key]);
  739.  
  740.                         }
  741.                     }
  742.                 }
  743.             }
  744.         }
  745.         return $patternlist;
  746.     }
  747.  
  748.     /**
  749.     * Builds an evaluation string to determine wether the result passes
  750.     * the filter or not. This string is evaluatet by the php buildin eval() function
  751.     *
  752.     * @param  Array      $vars a list which contains the used variables
  753.     * @param  Array      $res  the result part which have to be evaluated
  754.     * @param  Constraint $constraint the Constrain object
  755.     * @param  Array      $function an Array which contains the used functions
  756.     * @return String 
  757.     */
  758.  
  759.     protected function fillConstraintString($vars,$res,$constraint,$function){
  760.  
  761.         $boundExpr false;
  762.         $evalString $constraint->getExpression();
  763.  
  764.         // extract Literals
  765.         $pattern1 "/\".[^\"]*\"[^\^\@]/";
  766.         $pattern2 "/\'.[^\']*\'[^\^\@]/";
  767.         preg_match_all($pattern1,$evalString,$hits1);
  768.         preg_match_all($pattern2,$evalString,$hits2);
  769.  
  770.         foreach($hits1[0as $k => $val){
  771.             $evalString preg_replace('/\".[^\"]*\"[^\^]/','_REPLACED1_'.$k++,$evalString,1);
  772.         }
  773.         foreach($hits2[0as $k => $val){
  774.             $evalString preg_replace('/\".[^\"]*\"[^\^]/','_REPLACED2_'.$k++,$evalString,1);
  775.         }
  776.  
  777.         // replace namespaces
  778.         $prefs $this->query->getPrefixes();
  779.         foreach($prefs as $key => $val){
  780.             if($key == '')
  781.             $key ' ';
  782.             $evalString preg_replace("/^(".$key."\:)(.[^\s]*)|([\s\(]?[^\^])(".$key."\:)(.[^\s\)]*)([\s\)]?)/","$3'<".$val."$2$5>'$6",$evalString);
  783.  
  784.             $evalString preg_replace("/(\^)(".$key."\:)(.[^\s]*)/","$1<".$val."$3>",$evalString);
  785.         }
  786.  
  787.         $xsd "http\:\/\/www.w3.org\/2001\/XMLSchema\#";
  788.  
  789.         // evaluate bound calls
  790.         if($function['bound']){
  791.             $boundExpr true;
  792.             foreach($function['bound'as $var){
  793.                 if(isset($res[$var]&& $res[$var]!=="")
  794.                 $replacement 'true';
  795.                 else
  796.                 $replacement 'false';
  797.                 $evalString preg_replace("/bound\(\\".$var."\)/i",$replacement,$evalString);
  798.             }
  799.  
  800.         }
  801.         // evaluate isBlank calls
  802.         if($function['isBlank']){
  803.             foreach($function['isBlank'as $var){
  804.                 if(isset($res[$var]&& $res[$var]!=="" && $res[$varinstanceof BlankNode )
  805.                 $replacement 'true';
  806.                 else
  807.                 $replacement 'false';
  808.                 $evalString preg_replace("/isBlank\(\\".$var."\)/i",$replacement,$evalString);
  809.             }
  810.  
  811.         }
  812.         // evaluate isLiteral calls
  813.         if($function['isLiteral']){
  814.             foreach($function['isLiteral'as $var){
  815.                 if(isset($res[$var]&& $res[$var]!=="" && $res[$varinstanceof Literal  )
  816.                 $replacement 'true';
  817.                 else
  818.                 $replacement 'false';
  819.                 $evalString preg_replace("/isLiteral\(\\".$var."\)/i",$replacement,$evalString);
  820.             }
  821.  
  822.         }
  823.         // evaluate isUri calls
  824.         if($function['isUri']){
  825.             foreach($function['isUri'as $var){
  826.                 if(isset($res[$var]&& $res[$var]!=="" && $res[$varinstanceof Resource && $res[$var]->getUri(&& !$res[$varinstanceof BlankNode )
  827.                 $replacement 'true';
  828.                 else
  829.                 $replacement 'false';
  830.                 $evalString preg_replace("/isUri\(\\".$var."\)/i",$replacement,$evalString);
  831.             }
  832.         }
  833.         // evaluate lang calls
  834.         if($function['lang']){
  835.             foreach($function['lang'as $var){
  836.                 if(isset($res[$var]&& $res[$var]!=="" && $res[$varinstanceof Literal && $res[$var]->getLanguage() )
  837.                 $replacement '"'.$res[$var]->getLanguage().'"';
  838.                 else
  839.                 $replacement 'null';
  840.                 $evalString preg_replace("/lang\(\\".$var."\)/i",$replacement,$evalString);
  841.             }
  842.         }
  843.         // evaluate datatype calls
  844.         if($function['datatype']){
  845.             foreach($function['datatype'as $var){
  846.                 if(isset($res[$var]&& $res[$var]!=="" && $res[$varinstanceof Literal && $res[$var]->getDatatype() )
  847.                 $replacement '\'<'.$res[$var]->getDatatype().'>\'';
  848.                 else
  849.                 $replacement 'false';
  850.                 $evalString preg_replace("/datatype\(\\".$var."\)/i",$replacement,$evalString);
  851.             }
  852.         }
  853.         // evaluate string calls
  854.         if($function['string']){
  855.             foreach($function['string'as $var){
  856.                 if($var{0}=='?' || $var{0}=='$'){
  857.                     if(isset($res[$var]&& $res[$var]!==""){
  858.                         $replacement "'str_".$res[$var]->getLabel()."'";
  859.                         if($res[$varinstanceof BlankNode)
  860.                         $replacement "''";
  861.                     }else{
  862.                         $replacement 'false';
  863.                     }
  864.                     $evalString preg_replace("/str\(\\".$var."\)/i",$replacement,$evalString);
  865.                 }else{
  866.                     if($var{0}=='<'){
  867.                         $evalString preg_replace("/str\(\s*\<(.[^\>]*)\>\s*\)/i","'str_$1'",$evalString);
  868.                     }
  869.                     if($var{0}=='"'){
  870.                         $evalString preg_replace("/str\(\s*\"(.[^\>]*)\"\@[a-z]*\s*\)/i","'str_$1'",$evalString);
  871.                     }
  872.                 }
  873.  
  874.             }
  875.         }
  876.         // evaluate VARS
  877.         foreach($vars[0as $var){
  878.             if(isset($res[$var])&&$res[$var]!== ""){
  879.                 //$replacement = "'".$res[$var]->getLabel()."'";
  880.                 $replacement '" "';
  881.                 if($res[$varinstanceof Literal){
  882.                     if($res[$var]->getDatatype()!= null){
  883.                         if($res[$var]->getDatatype(== XML_SCHEMA.'boolean')
  884.                         $replacement $res[$var]->getLabel();
  885.                         if($res[$var]->getDatatype(== XML_SCHEMA.'double')
  886.                         $replacement $res[$var]->getLabel();
  887.                         if($res[$var]->getDatatype(== XML_SCHEMA.'integer')
  888.                         $replacement $res[$var]->getLabel();
  889.                         if($res[$var]->getDatatype(== XML_SCHEMA.'dateTime')
  890.                         $replacement strtotime($res[$var]->getLabel());
  891.                     }else{
  892.                         if($res[$var]->getLabel()=="")
  893.                         $replacement 'false';
  894.                         else
  895.                         $replacement "'str_".$res[$var]->getLabel()."'";
  896.                     }
  897.                 }else{
  898.                     if($res[$varinstanceof Resource){
  899.                         $replacement "'<".$res[$var]->getLabel().">'";
  900.                     }
  901.                 }
  902.                 $evalString preg_replace("/\\".$var."/",$replacement,$evalString);
  903.             }
  904.  
  905.             // problem with PHP: false < 13 is true
  906.             if(isset($res[$var])){
  907.                 if($res[$var=== ""){
  908.                     if($boundExpr)
  909.                     $evalString preg_replace("/\\".$var."/","false",$evalString);
  910.                     else
  911.                     $evalString 'false';
  912.                 }
  913.             }else{
  914.                 $evalString preg_replace("/\\".$var."/","false",$evalString);
  915.             }
  916.  
  917.         }
  918.  
  919.         // replace '=' with '=='
  920.         $evalString preg_replace("/(.[^\=])(\=)(.[^\=])/","$1==$3",$evalString);
  921.  
  922.  
  923.         // rewrite Literals
  924.         foreach($hits1[0as $k => $val){
  925.             $pattern '/_REPLACED1_'.$k.'/';
  926.             $evalString preg_replace($pattern,$hits1[0][$k],$evalString,1);
  927.         }
  928.  
  929.         foreach($hits2[0as $k => $val){
  930.             $pattern '/_REPLACED2_'.$k.'/';
  931.             $evalString preg_replace($pattern,$hits2[0][$k],$evalString,1);
  932.         }
  933.  
  934.         // replace xsd:boolean expressions
  935.         $pattern $pattern '/\"\s?true\s?\"\^\^\<'.$xsd.'boolean\>|\'\s?true\s?\'\^\^xsd:boolean/';
  936.         $evalString preg_replace($pattern,"true",$evalString);
  937.  
  938.         $pattern $pattern '/\"\s?false\s?\"\^\^\<'.$xsd.'boolean\>|\'\s?false\s?\'\^\^xsd:boolean/';
  939.         $evalString preg_replace($pattern,"false",$evalString);
  940.  
  941.         // replace xsd:date expressions
  942.         $pattern "/\"(.[^\"]*)\"\^\^".$xsd."dateTime/";
  943.         preg_match_all($pattern,$evalString,$hits);
  944.  
  945.         foreach($hits[1as $dummy)
  946.         $evalString preg_replace("/\".[^\"]*\"\^\^".$xsd."dateTime/",strtotime($dummy),$evalString,1);
  947.  
  948.  
  949.         $evalString preg_replace("/(\'\<".$xsd."dateTime\()(.[^\)]*\))\>\'/","dateTime($2",$evalString);
  950.  
  951.         $evalString preg_replace("/(\'\<".$xsd."integer\()(.[^\)]*\))\>\'/","integer($2",$evalString);
  952.  
  953.         // tag plain literals
  954.         $evalString preg_replace("/\"(.[^\"]*)\"([^\^])|\"(.[^\"]*)\"$/","'str_$1$3'$2",$evalString);
  955.  
  956.         return $evalString;
  957.     }
  958.  
  959.     /**
  960.     * Sorts the results.
  961.     *
  962.     * @param  Array  $vartable List containing the unsorted result vars
  963.     * @return Array  List containing the sorted result vars
  964.     */
  965.     protected function sortVars($vartable)
  966.     {
  967.         $newTable array();
  968.         $mod $this->query->getSolutionModifier();
  969.         // if no ORDER BY solution modifier return vartable
  970.         if($mod['order by']!= null){
  971.             $order $mod['order by'];
  972.             $map $this->buildVarmap($order,$vartable);
  973.             foreach($map as $val){
  974.                 $newTable[$vartable[$val];
  975.             }
  976.         }else{
  977.             $newTable $vartable;
  978.         }
  979.  
  980.         if($mod['offset'!= null){
  981.             $newTable array_slice ($newTable$mod['offset']);
  982.         }
  983.         if($mod['limit'!= null){
  984.             $newTable array_slice($newTable,0,$mod['limit']);
  985.         }
  986.  
  987.         return $newTable;
  988.     }
  989.  
  990.     /**
  991.     * Sorts the result table.
  992.     *
  993.     * @param  String $order (ASC/DESC)
  994.     * @param  Array  $vartable the vartable
  995.     * @return Array  A map that contains the new order of the result vars
  996.     */
  997.     protected function buildVarmap($order$vartable)
  998.     {
  999.         $n0;
  1000.         $result array();
  1001.         $num_var array();
  1002.         foreach($order as $variable)
  1003.         $num_var[$variable['val']] 0;
  1004.  
  1005.         foreach($vartable as $k => $x){
  1006.             foreach($order as $value){
  1007.                 // if the value is a typed Literal try to determine if it
  1008.                 // a numeric datatype
  1009.                 if($x[$value['val']] instanceof Literal){
  1010.                     $dtype $x[$value['val']]->getDatatype();
  1011.                     if($dtype){
  1012.                         switch($dtype){
  1013.                             case XML_SCHEMA."integer":
  1014.                             $num_var[$value['val']]++;
  1015.                             break;
  1016.                             case XML_SCHEMA."double":
  1017.                             $num_var[$value['val']]++;
  1018.                             break;
  1019.  
  1020.                         }
  1021.                     }
  1022.                 }
  1023.                 if($x[$value['val']]){
  1024.                     if($x[$value['val']]instanceof Literal){
  1025.                         $pref "2";
  1026.                     }
  1027.                     if($x[$value['val']]instanceof Resource){
  1028.                         $pref "1";
  1029.                     }
  1030.                     if($x[$value['val']]instanceof BlankNode){
  1031.                         $pref "0";
  1032.                     }
  1033.                     $result[$value['val']][$n$pref.$x[$value['val']]->getLabel();
  1034.                 }else{
  1035.                     $result[$value['val']][$n"";
  1036.                 }
  1037.             }
  1038.             $result['oldKey'][$n$k;
  1039.             $n++;
  1040.         }
  1041.         $sortString "";
  1042.         foreach($order as $value){
  1043.             if($num_var[$value['val']] == $n)
  1044.             $sort SORT_NUMERIC;
  1045.             else
  1046.             $sort SORT_STRING;
  1047.  
  1048.             if($value['type'== 'asc')
  1049.             $type SORT_ASC;
  1050.             else
  1051.             $type SORT_DESC;
  1052.  
  1053.             $sortString $sortString.'$result["'.$value['val'].'"],'.$type.','.$sort.',';
  1054.         }
  1055.         $sortString "array_multisort(".$sortString.'$result["oldKey"]);';
  1056.  
  1057.         @eval($sortString);
  1058.         return $result['oldKey'];
  1059.     }
  1060.  
  1061.  
  1062.  
  1063.     /**
  1064.     * Eliminates duplicate results.
  1065.     *
  1066.     * @param  Array  $vartable a table that contains the result vars and their bindings
  1067.     * @return Array the result table without duplicate results
  1068.     */
  1069.     protected function distinct($vartable)
  1070.     {
  1071.         $index array();
  1072.         foreach($vartable as $key => $value){
  1073.             $key_index="";
  1074.             foreach($value as $k => $v)
  1075.             if($v instanceof Object)
  1076.                 $key_index $key_index.$k.$v->toString();
  1077.             if(isset($index[$key_index]))
  1078.             unset($vartable[$key]);
  1079.             else
  1080.             $index[$key_index]1;
  1081.         }
  1082.         return $vartable;
  1083.     }
  1084.  
  1085.  
  1086.     /**
  1087.     * Prints a query result as HTML table.
  1088.     * You can change the colors in the configuration file.
  1089.     *
  1090.     * @param array $queryResult [][?VARNAME] = object Node
  1091.     * @return void 
  1092.     */
  1093.     public function writeQueryResultAsHtmlTable($queryResult{
  1094.         // Import Package Utility
  1095.         include_once(RDFAPI_INCLUDE_DIR.PACKAGE_UTILITY);
  1096.  
  1097.         if $queryResult[0== null{
  1098.             echo 'no match<br>';
  1099.             return;
  1100.         }
  1101.         if $queryResult == 'false'{
  1102.             echo 'boolean: false<br>';
  1103.             return;
  1104.         }
  1105.         if $queryResult == 'true'{
  1106.             echo 'boolean: true<br>';
  1107.             return;
  1108.         }
  1109.  
  1110.  
  1111.         echo '<table border="1" cellpadding="3" cellspacing="0"><tr><td><b>No.</b></td>';
  1112.         foreach ($queryResult[0as $varName => $value)
  1113.         echo "<td align='center'><b>$varName</b></td>";
  1114.         echo '</tr>';
  1115.  
  1116.         foreach ($queryResult as $n => $var{
  1117.  
  1118.  
  1119.             echo '<tr><td width="20" align="right">' .($n 1.'.</td>';
  1120.             foreach ($var as $varName => $value{
  1121.                 if($value !=''){
  1122.                     echo INDENTATION INDENTATION '<td bgcolor="';
  1123.                     echo RDFUtil::chooseColor($value);
  1124.                     echo '">';
  1125.                     echo '<p>';
  1126.  
  1127.                     $lang  NULL;
  1128.                     $dtype NULL;
  1129.                     if (is_a($value'Literal')) {
  1130.                         if ($value->getLanguage(!= NULL)
  1131.                         $lang ' <b>(xml:lang="' $value->getLanguage('") </b> ';
  1132.                         if ($value->getDatatype(!= NULL)
  1133.                         $dtype ' <b>(rdf:datatype="' $value->getDatatype('") </b> ';
  1134.                     }
  1135.                     echo  RDFUtil::getNodeTypeName($value.$value->getLabel($lang $dtype .'</p>';
  1136.                 }else{
  1137.                     echo "<td bgcolor='white'>unbound";
  1138.                 }
  1139.             }
  1140.             echo '</tr>';
  1141.         }
  1142.         echo '</table>';
  1143.     }
  1144.  
  1145.  
  1146.  
  1147.     /*
  1148.     *   Dumb getters
  1149.     */
  1150.  
  1151.  
  1152.  
  1153.     public function getQuery()
  1154.     {
  1155.         return $this->query;
  1156.     }//public function getQuery()
  1157.  
  1158.  
  1159.  
  1160.     public function getDataset()
  1161.     {
  1162.         return $this->dataset;
  1163.     }//public function getDataset()
  1164.  
  1165. // end: Class SparqlEngine
  1166.  
  1167. ?>

Documentation generated on Fri, 1 Jun 2007 16:52:05 +0200 by phpDocumentor 1.3.2