rdql
[ class tree: rdql ] [ index: rdql ] [ all elements ]

Source for file Parser.php

Documentation is available at Parser.php

  1. <?php
  2. // ----------------------------------------------------------------------------------
  3. // Class: RDF_RDQL_Parser
  4. // ----------------------------------------------------------------------------------
  5. /**
  6.  * This class contains methods for parsing an RDQL query string into PHP variables.
  7.  * The output of the RDQLParser is an array with variables and constraints
  8.  * of each query clause (Select, From, Where, And, Using).
  9.  * To perform an RDQL query this array has to be passed to the RDQLEngine.
  10.  *
  11.  * @version  V0.7
  12.  * @author   Radoslaw Oldakowski <radol@gmx.de>
  13.  *
  14.  * @package rdql
  15.  * @access public
  16.  */
  17.  
  18.  
  19. class RDF_RDQL_Parser extends RDF_Object {
  20. /**
  21.  * Parsed query variables and constraints.
  22.  * { } are only used within the parser class and are not returned as parsed query.
  23.  * ( [] stands for an integer index - 0..N )
  24.  *
  25.  * @var     array   ['selectVars'][] = ?VARNAME
  26.  *                   ['sources'][]{['value']} = URI | QName
  27.  *                                {['is_qname'] = boolean}
  28.  *                   ['patterns'][]['subject']['value'] = VARorURI
  29.  *                                           {['is_qname'] = boolean}
  30.  *                                 ['predicate']['value'] = VARorURI
  31.  *                                             {['is_qname'] = boolean}
  32.  *                                 ['object']['value'] = VARorURIorLiterl
  33.  *                                          {['is_qname'] = boolean}
  34.  *                                           ['is_literal'] = boolean
  35.  *                                           ['l_lang'] = string
  36.  *                                           ['l_dtype'] = string
  37.  *                                          {['l_dtype_is_qname'] = boolean}
  38.  *                   ['filters'][]['string'] = string
  39.  *                                ['evalFilterStr'] = string
  40.  *                                ['reqexEqExprs'][]['var'] = ?VARNAME
  41.  *                                                  ['operator'] = (eq | ne)
  42.  *                                                  ['regex'] = string
  43.  *                                ['strEqExprs'][]['var'] = ?VARNAME
  44.  *                                                ['operator'] = (eq | ne)
  45.  *                                                ['value'] = string
  46.  *                                                ['value_type'] = ('variable' | 'URI' | 'QName' | 'Literal')
  47.  *                                                ['value_lang'] = string
  48.  *                                                ['value_dtype'] = string
  49.  *                                               {['value_dtype_is_qname'] = boolean}
  50.  *                                ['numExpr']['vars'][] = ?VARNAME
  51.  *                  {['ns'][PREFIX] = NAMESPACE}
  52.  
  53.      * @access protected
  54.      */
  55.     var $parsedQuery;
  56.  
  57.     /**
  58.      * Query string divided into a sequence of tokens.
  59.      * A token is either: ' ' or "\n" or "\r" or "\t" or ',' or '(' or ')'
  60.      * or a string containing any characters except from the above.
  61.      *
  62.      * @var array 
  63.      * @access protected
  64.      */
  65.     var $tokens;
  66.  
  67.     /**
  68.      * Parse the given RDQL query string and return an array with query variables and constraints.
  69.      *
  70.      * @param string $queryString 
  71.      * @return array $this->parsedQuery
  72.      * @access public
  73.      */
  74.     function &parseQuery($queryString)
  75.     {
  76.         $cleanQueryString $this->removeComments($queryString);
  77.         if (PEAR::isError($cleanQueryString)) {
  78.             return $cleanQueryString;
  79.         }
  80.         $this->tokenize($cleanQueryString);
  81.         $result $this->startParsing();
  82.         if (PEAR::isError($result)) {
  83.             return $result;
  84.         }
  85.         if ($this->parsedQuery['selectVars'][0== '*'{
  86.             $this->parsedQuery['selectVars'$this->findAllQueryVariables();
  87.             if (PEAR::isError($this->parsedQuery['selectVars'])) {
  88.                 return $this->parsedQuery['selectVars'];
  89.             }
  90.         else {
  91.             $this->_checkSelectVars();
  92.         }
  93.         $this->replaceNamespacePrefixes();
  94.  
  95.         return $this->parsedQuery;
  96.     }
  97.  
  98.     /**
  99.      * Remove comments from the passed query string.
  100.      *
  101.      * @param string $query 
  102.      * @return string 
  103.      * @throws PHPError
  104.      * @access protected
  105.      */
  106.     function removeComments($query)
  107.     {
  108.         $last strlen($query)-1;
  109.         $query .= ' ';
  110.         $clean '';
  111.         for ($i = 0; $i <= $last$i++{
  112.             // don't search for comments inside a 'literal'@lang^^dtype or "literal"@lang^^dtype
  113.             if ($query{$i== "'" || $query{$i== '"'{
  114.                 $quotMark $query{$i};
  115.                 do {
  116.                     $clean .= $query{$i++};
  117.                 while ($i $last && $query{$i!= $quotMark);
  118.                 $clean .= $query{$i};
  119.                 // language
  120.                 if ($query{$i+1== '@'{
  121.                     do {
  122.                         if ($query{$i+1== '^' && $query{$i+2== '^'{
  123.                             break;
  124.                         }
  125.                         $clean .= $query{++$i};
  126.                     while ($i $last && $query{$i!= ' ' && $query{$i!= "\t"
  127.                         && $query{$i!= "\n" && $query{$i!= "\r");
  128.                 }
  129.                 // datatype
  130.                 if ($query{$i+1== '^' && $query{$i+2== '^'{
  131.                     do {
  132.                         $clean .= $query{++$i};
  133.                     while ($i $last && $query{$i!= ' ' && $query{$i!= "\t"
  134.                         && $query{$i!= "\n" && $query{$i!= "\r");
  135.                 }
  136.                 // don't search for comments inside an <URI> either
  137.             elseif ($query{$i== '<'{
  138.                 do {
  139.                     $clean .= $query{$i++};
  140.                 while ($i $last && $query{$i!= '>');
  141.                 $clean .= $query{$i};
  142.             elseif ($query{$i== '/'{
  143.                 // clear: // comment
  144.                 if ($i $last && $query{$i+1== '/'{
  145.                     while ($i $last && $query{$i!= "\n" && $query{$i!= "\r"{
  146.                         ++$i;
  147.                     }
  148.                     $clean .= ' ';
  149.                     // clear: /*comment*/
  150.                 elseif ($i $last-2 && $query{$i+1== '*'{
  151.                     $i += 2;
  152.                     while ($i $last && ($query{$i!= '*' || $query{$i+1!= '/')) {
  153.                         ++$i;
  154.                     }
  155.                     if ($i >= $last && ($query{$last-1!= '*' || $query{$last!= '/')) {
  156.                         $errmsg "unterminated comment - '*/' missing";
  157.                         return RDF_RDQL::raiseError(RDF_RDQL_ERROR_SYNTAXnullnull$errmsg);
  158.                     }
  159.                     ++$i;
  160.                 else {
  161.                     $clean .= $query{$i};
  162.                 }
  163.             else {
  164.                 $clean .= $query{$i};
  165.             }
  166.         }
  167.         return $clean;
  168.     }
  169.  
  170.     /**
  171.      * Divide the query string into tokens.
  172.      * A token is either: ' ' or "\n" or "\r" or '\t' or ',' or '(' or ')'
  173.      * or a string containing any character except from the above.
  174.      *
  175.      * @param string $queryString 
  176.      * @access protected
  177.      */
  178.     function tokenize($queryString)
  179.     {
  180.         $queryString trim($queryString" \r\n\t");
  181.         $specialChars = array (" ""\t""\r""\n"",""("")");
  182.         $len strlen($queryString);
  183.         $this->tokens[0'';
  184.         $n = 0;
  185.  
  186.         for ($i = 0; $i $len; ++$i{
  187.             if (!in_array($queryString{$i}$specialChars)) {
  188.                 $this->tokens[$n.= $queryString{$i};
  189.             else {
  190.                 if ($this->tokens[$n!= ''{
  191.                     ++$n;
  192.                 }
  193.                 $this->tokens[$n$queryString{$i};
  194.                 $this->tokens[++$n'';
  195.             }
  196.         }
  197.     }
  198.  
  199.     /**
  200.      * Start parsing of the tokenized query string.
  201.      *
  202.      * @access protected
  203.      */
  204.     function startParsing()
  205.     {
  206.         return $this->parseSelect();
  207.     }
  208.  
  209.     /**
  210.      * Parse the SELECT clause of an RDQL query.
  211.      * When the parsing of the SELECT clause is finished, this method will call
  212.      * a suitable method to parse the subsequent clause.
  213.      *
  214.      * @throws PhpError
  215.      * @access protected
  216.      */
  217.     function parseSelect()
  218.     {
  219.         $this->_clearWhiteSpaces();
  220.         // Check if the queryString contains a "SELECT" token
  221.         if (strcasecmp('SELECT'current($this->tokens))) {
  222.             $errmsg current($this->tokens"' - SELECT keyword expected";
  223.             return RDF_RDQL::raiseError(RDF_RDQL_ERROR_SELECTnullnull$errmsg);
  224.         }
  225.         unset($this->tokens[key($this->tokens)]);
  226.         $this->_clearWhiteSpaces();
  227.         // Parse SELECT *
  228.         if (current($this->tokens== '*'{
  229.             unset($this->tokens[key($this->tokens)]);
  230.             $this->parsedQuery['selectVars'][0'*';
  231.             $this->_clearWhiteSpaces();
  232.             if (strcasecmp('FROM'current($this->tokens))
  233.                 && strcasecmp('SOURCE'current($this->tokens))
  234.                 && strcasecmp('WHERE'current($this->tokens))
  235.             {
  236.                 $errmsg htmlspecialchars(current($this->tokens)) .
  237.                     ' - SOURCE or WHERE clause expected';
  238.                 return RDF_RDQL::raiseError(RDF_RDQL_ERROR_SYNTAXnullnull$errmsg);
  239.             }
  240.         }
  241.         // Parse SELECT ?Var (, ?Var)*
  242.         $commaExpected = false;
  243.         $comma = false;
  244.         while (current($this->tokens!= null{
  245.             $k key($this->tokens);
  246.             $token $this->tokens[$k];
  247.  
  248.             switch ($token{
  249.             case ',':
  250.                 if (!$commaExpected{
  251.                     $errmsg 'unexpected comma';
  252.                     return RDF_RDQL::raiseError(RDF_RDQL_ERROR_SELECTnullnull$errmsg);
  253.                 }
  254.                 $comma = true;
  255.                 $commaExpected = false;
  256.                 break;
  257.             case '(':
  258.             case ')':
  259.                 $errmsg = "'$token' - illegal input";
  260.                 return RDF_RDQL::raiseError(RDF_RDQL_ERROR_SELECTnullnull$errmsg);
  261.                 break;
  262.             default :
  263.                 if (!strcasecmp('FROM'$token|| !strcasecmp('SOURCE'$token)) {
  264.                     if ($comma{
  265.                         $errmsg 'unexpected comma';
  266.                         return RDF_RDQL::raiseError(RDF_RDQL_ERROR_SELECTnullnull$errmsg);
  267.                     }
  268.                     unset($this->tokens[$k]);
  269.                     return $this->parseFrom();
  270.                 elseif (!strcasecmp('WHERE'$token&& !$comma{
  271.                     if ($comma{
  272.                         $errmsg 'unexpected comma';
  273.                         return RDF_RDQL::raiseError(RDF_RDQL_ERROR_SELECTnullnull$errmsg);
  274.                     }
  275.                     unset($this->tokens[$k]);
  276.                     return $this->parseWhere();
  277.                 }
  278.                 if ($token{0== '?'{
  279.                     $result $this->_validateVar($token'SELECT');
  280.                     if (PEAR::isError($result)) {
  281.                         return $result;
  282.                     }
  283.                     $this->parsedQuery['selectVars'][$result;
  284.                     $commaExpected = true;
  285.                     $comma = false;
  286.                 else {
  287.                     $errmsg = "'$token' - '?' missing";
  288.                     return RDF_RDQL::raiseError(RDF_RDQL_ERROR_SELECTnullnull$errmsg);
  289.                 }
  290.             }
  291.             unset($this->tokens[$k]);
  292.             $this->_clearWhiteSpaces();
  293.         }
  294.         $errmsg 'WHERE clause missing';
  295.         return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  296.     }
  297.  
  298.     /**
  299.      * Parse the FROM/SOURCES clause of an RDQL query
  300.      * When the parsing of this clause is finished, parseWhere() will be called.
  301.      *
  302.      * @throws PhpError
  303.      * @access protected
  304.      */
  305.     function parseFrom()
  306.     {
  307.         $comma = false;
  308.         $commaExpected = false;
  309.         $i = -1;
  310.         while (current($this->tokens!= null{
  311.             $this->_clearWhiteSpaces();
  312.             if (!strcasecmp('WHERE'current($this->tokens))
  313.                 && count($this->parsedQuery['sources']!= 0
  314.             {
  315.                 if ($comma{
  316.                     $errmsg 'unexpected comma';
  317.                     return RDF_RDQL::raiseError(RDF_RDQL_ERROR_SELECTnullnull$errmsg);
  318.                 }
  319.                 unset($this->tokens[key($this->tokens)]);
  320.                 return $this->parseWhere();
  321.             }
  322.             if (current($this->tokens== ','{
  323.                 if ($commaExpected{
  324.                     $comma = true;
  325.                     $commaExpected = false;
  326.                     unset($this->tokens[key($this->tokens)]);
  327.                 else {
  328.                     $errmsg 'unecpected comma';
  329.                     return RDF_RDQL::raiseError(RDF_RDQL_ERROR_SOURCEnullnull$errmsg);
  330.                 }
  331.             else {
  332.                 $token current($this->tokens);
  333.                 $result $this->_validateURI($tokenRDF_RDQL_ERROR_SOURCE);
  334.                 if (PEAR::isError($result)) {
  335.                     return $result;
  336.                 }
  337.                 $this->parsedQuery['sources'][++$i]['value'$result;
  338.                 if ($token{0!= '<'{
  339.                     $this->parsedQuery['sources'][$i]['is_qname'= true;
  340.                 }
  341.                 $commaExpected = true;
  342.                 $comma = false;
  343.             }
  344.         }
  345.         $errmsg 'WHERE clause missing';
  346.         return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  347.     }
  348.  
  349.     /**
  350.      * *'
  351.      * Parse the WHERE clause of an RDQL query.
  352.      * When the parsing of the WHERE clause is finished, this method will call
  353.      * a suitable method to parse the subsequent clause if provided.
  354.      *
  355.      * @throws PhpError
  356.      * @access protected
  357.      */
  358.     function parseWhere()
  359.     {
  360.         $comma = false;
  361.         $commaExpected = false;
  362.         $i = 0;
  363.  
  364.         do {
  365.             $this->_clearWhiteSpaces();
  366.             if (!strcasecmp('AND'current($this->tokens))
  367.                 && count($this->parsedQuery['patterns']!= 0
  368.             {
  369.                 if ($comma{
  370.                     $errmsg 'unexpected comma';
  371.                     return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  372.                 }
  373.                 unset($this->tokens[key($this->tokens)]);
  374.                 return $this->parseAnd();
  375.             elseif (!strcasecmp('USING'current($this->tokens))
  376.                 && count($this->parsedQuery['patterns']!= 0
  377.             {
  378.                 if ($comma{
  379.                     $errmsg 'unexpected comma';
  380.                     return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  381.                 }
  382.                 unset($this->tokens[key($this->tokens)]);
  383.                 return $this->parseUsing();
  384.             }
  385.  
  386.             if (current($this->tokens== ','{
  387.                 $comma = true;
  388.                 $result $this->_checkComma($commaExpected'WHERE');
  389.                 if (PEAR::isError($result)) {
  390.                     return $result;
  391.                 }
  392.             else {
  393.                 if (current($this->tokens!= '('{
  394.                     $errmsg current($this->tokens"' - '(' expected";
  395.                     return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  396.                 }
  397.                 unset($this->tokens[key($this->tokens)]);
  398.                 $this->_clearWhiteSpaces();
  399.  
  400.                 $this->parsedQuery['patterns'][$i]['subject'=
  401.                     $this->_validateVarUri(current($this->tokens));
  402.                 $result $this->_checkComma(true'WHERE');
  403.                 if (PEAR::isError($result)) {
  404.                     return $result;
  405.                 }
  406.                 $this->parsedQuery['patterns'][$i]['predicate'=
  407.                     $this->_validateVarUri(current($this->tokens));
  408.                 $result $this->_checkComma(true'WHERE');
  409.                 if (PEAR::isError($result)) {
  410.                     return $result;
  411.                 }
  412.                 $result $this->_validateVarUriLiteral(current($this->tokens));
  413.                 if (PEAR::isError($result)) {
  414.                     return $result;
  415.                 }
  416.                 $this->parsedQuery['patterns'][$i++]['object'$result;
  417.                 $this->_clearWhiteSpaces();
  418.  
  419.                 if (current($this->tokens!= ')'{
  420.                     $errmsg current($this->tokens"' - ')' expected";
  421.                     return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  422.                 }
  423.                 unset($this->tokens[key($this->tokens)]);
  424.                 $this->_clearWhiteSpaces();
  425.                 $commaExpected = true;
  426.                 $comma = false;
  427.             }
  428.         while (current($this->tokens!= null);
  429.  
  430.         if ($comma{
  431.             $errmsg 'unexpected comma';
  432.             return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  433.         }
  434.     }
  435.  
  436.     /**
  437.      * Parse the AND clause of an RDQL query
  438.      *
  439.      * @throws PhpError
  440.      * @access protected
  441.      * @toDo clear comments
  442.      */
  443.     function parseAnd()
  444.     {
  445.         $this->_clearWhiteSpaces();
  446.         $n = 0;
  447.         $filterStr '';
  448.  
  449.         while (current($this->tokens!= null{
  450.             $k key($this->tokens);
  451.             $token $this->tokens[$k];
  452.  
  453.             if (!strcasecmp('USING'$token)) {
  454.                 $result $this->parseFilter($n$filterStr);
  455.                 if (PEAR::isError($result)) {
  456.                     return $result;
  457.                 }
  458.                 unset($this->tokens[$k]);
  459.                 return $this->parseUsing();
  460.             elseif ($token == ','{
  461.                 $result $this->parseFilter($n$filterStr);
  462.                 if (PEAR::isError($result)) {
  463.                     return $result;
  464.                 }
  465.                 $filterStr '';
  466.                 $token '';
  467.                 ++$n;
  468.             }
  469.             $filterStr .= $token;
  470.             unset($this->tokens[$k]);
  471.         }
  472.         return $this->parseFilter($n$filterStr);
  473.     }
  474.  
  475.     /**
  476.      * Parse the USING clause of an RDQL query
  477.      *
  478.      * @throws PhpError
  479.      * @access protected
  480.      */
  481.     function parseUsing()
  482.     {
  483.         $commaExpected = false;
  484.         $comma = false;
  485.  
  486.         do {
  487.             $this->_clearWhiteSpaces();
  488.             if (current($this->tokens== ','{
  489.                 $comma = true;
  490.                 $result $this->_checkComma($commaExpected'USING');
  491.                 if (PEAR::isError($result)) {
  492.                     return $result;
  493.                 }
  494.             else {
  495.                 $prefix $this->_validatePrefix(current($this->tokens));
  496.                 if (PEAR::isError($prefix)) {
  497.                     return $prefix;
  498.                 }
  499.                 $this->_clearWhiteSpaces();
  500.  
  501.                 if (strcasecmp('FOR'current($this->tokens))) {
  502.                     $errmsg "keyword 'FOR' missing in the namespace declaration";
  503.                     return RDF_RDQL::raiseError(RDF_RDQL_ERROR_USINGnullnull$errmsg);
  504.                 }
  505.                 unset($this->tokens[key($this->tokens)]);
  506.                 $this->_clearWhiteSpaces();
  507.  
  508.                 $result $this->_validateURI(current($this->tokens)'USING');
  509.                 if (PEAR::isError($result)) {
  510.                     return $result;
  511.                 }
  512.                 $this->parsedQuery['ns'][$prefix=
  513.                 $this->_clearWhiteSpaces();
  514.                 $commaExpected = true;
  515.                 $comma = false;
  516.             }
  517.         while (current($this->tokens!= null);
  518.  
  519.         if ($comma{
  520.             $errmsg 'unexpected comma';
  521.             return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  522.         }
  523.     }
  524.  
  525.     /**
  526.      * Check if a filter from the AND clause contains an equal number of '(' and ')'
  527.      * and parse filter expressions.
  528.      *
  529.      * @param integer $n 
  530.      * @param string $filter 
  531.      * @throws PHPError
  532.      * @access protected
  533.      */
  534.     function parseFilter($n$filter)
  535.     {
  536.         if ($filter == null{
  537.             $errmsg 'unexpected comma';
  538.             return RDF_RDQL::raiseError(RDF_RDQL_ERROR_ANDnullnull$errmsg);
  539.         }
  540.         $paren substr_count($filter'('substr_count($filter')');
  541.         if ($paren != 0{
  542.             if ($paren > 0{
  543.                 $errmsg = "'{htmlspecialchars($filter)}' - ')' missing ";
  544.             elseif ($paren < 0{
  545.                 $errmsg = "'{htmlspecialchars($filter)}' - too many ')' ";
  546.             }
  547.             return RDF_RDQL::raiseError(RDF_RDQL_ERROR_ANDnullnull$errmsg);
  548.         }
  549.  
  550.         $this->parsedQuery['filters'][$n$this->parseExpressions($filter);
  551.     }
  552.  
  553.     /**
  554.      * Parse expressions inside the passed filter:
  555.      * 1)  regex equality expressions:    ?var [~~ | =~ | !~ ] REG_EX
  556.      * 2a) string equality expressions:   ?var  [eq | ne] "literal"@lang^^dtype.
  557.      * 2b) string equality expressions:   ?var [eq | ne] <URI> or ?var [eq | ne] prefix:local_name
  558.      * 3)  numerical expressions: e.q.    (?var1 - ?var2)*4 >= 20
  559.      *
  560.      * In cases 1-2 parse each expression of the given filter into an array of variables.
  561.      * For each parsed expression put a place holder (e.g. ##RegEx_1##) into the filterStr.
  562.      * The RDQLengine will then replace each place holder with the outcomming boolean value
  563.      * of the corresponding expression.
  564.      * The remaining filterStr contains only numerical expressions and place holders.
  565.      *
  566.      * @param string $filteStr 
  567.      * @return array ['string'] = string
  568.      *                    ['evalFilterStr'] = string
  569.      *                    ['reqexEqExprs'][]['var'] = ?VARNAME
  570.      *                                      ['operator'] = (eq | ne)
  571.      *                                      ['regex'] = string
  572.      *                    ['strEqExprs'][]['var'] = ?VARNAME
  573.      *                                   ['operator'] = (eq | ne)
  574.      *                                   ['value'] = string
  575.      *                                   ['value_type'] = ('variable' | 'URI' 'QName' | | 'Literal')
  576.      *                                   ['value_lang'] = string
  577.      *                                   ['value_dtype'] = string
  578.      *                                   ['value_dtype_is_qname'] = boolean
  579.      *                    ['numExpr']['vars'][] = ?VARNAME
  580.      * @access protected
  581.      */
  582.     function parseExpressions($filterStr)
  583.     {
  584.         $parsedFilter['string'$filterStr;
  585.         $parsedFilter['regexEqExprs'= array();
  586.         $parsedFilter['strEqExprs'= array();
  587.         $parsedFilter['numExprVars'= array();
  588.         // parse regex string equality expressions, e.g. ?x ~~ !//foo.com/r!i
  589.         $reg_ex  "/(\?[a-zA-Z0-9_]+)\s+([~!=]~)\s+(['|\"])?([^\s'\"]+)(['|\"])?/";
  590.         $eqExprs = array();
  591.         preg_match_all($reg_ex$filterStr$eqExprs);
  592.         foreach ($eqExprs[0as $i => $eqExpr{
  593.             $result $this->_checkRegExQuotation($filterStr$eqExprs[3][$i]$eqExprs[5][$i]);
  594.             if (PEAR::isError($result)) {
  595.                 return $result;
  596.             }
  597.             $parsedFilter['regexEqExprs'][$i]['var'$this->_isDefined($eqExprs[1][$i]);
  598.             if (PEAR::isError($parsedFilter['regexEqExprs'][$i]['var'])) {
  599.                 return $parsedFilter['regexEqExprs'][$i]['var'];
  600.             }
  601.             $parsedFilter['regexEqExprs'][$i]['operator'$eqExprs[2][$i];
  602.             $parsedFilter['regexEqExprs'][$i]['regex'$eqExprs[4][$i];
  603.  
  604.             $filterStr str_replace($eqExpr" ##RegEx_$i## "$filterStr);
  605.         }
  606.         // parse ?var  [eq | ne] "literal"@lang^^dtype
  607.         $reg_ex  "/(\?[a-zA-Z0-9_]+)\s+(eq|ne)\s+(\'[^\']*\'|\"[^\"]*\")";
  608.         $reg_ex .= "(@[a-zA-Z]+)?(\^{2}\S+:?\S+)?/i";
  609.         preg_match_all($reg_ex$filterStr$eqExprs);
  610.         foreach ($eqExprs[0as $i => $eqExpr{
  611.             $parsedFilter['strEqExprs'][$i]['var'$this->_isDefined($eqExprs[1][$i]);
  612.             if (PEAR::isError($parsedFilter['strEqExprs'][$i]['var'])) {
  613.                 return $parsedFilter['strEqExprs'][$i]['var'];
  614.             }
  615.             $parsedFilter['strEqExprs'][$i]['operator'strtolower($eqExprs[2][$i]);
  616.             $parsedFilter['strEqExprs'][$i]['value'trim($eqExprs[3][$i],"'\"");
  617.             $parsedFilter['strEqExprs'][$i]['value_type''Literal';
  618.             $parsedFilter['strEqExprs'][$i]['value_lang'substr($eqExprs[4][$i]1);
  619.             $dtype substr($eqExprs[5][$i]2);
  620.             if ($dtype{
  621.                 $result $this->_validateURI($dtypeRDF_RDQL_ERROR_AND);
  622.                 if (PEAR::isError($result)) {
  623.                     return $result;
  624.                 }
  625.                 $parsedFilter['strEqExprs'][$i]['value_dtype'$result;
  626.                 if ($dtype{0!= '<'{
  627.                     $parsedFilter['strEqExprs'][$i]['value_dtype_is_qname'= true;
  628.                 }
  629.             else {
  630.                 $parsedFilter['strEqExprs'][$i]['value_dtype''';
  631.             }
  632.  
  633.             $filterStr str_replace($eqExprs[0][$i]" ##strEqExpr_$i## "$filterStr);
  634.         }
  635.         // parse ?var [eq | ne] ?var
  636.         $ii count($parsedFilter['strEqExprs']);
  637.         $reg_ex  "/(\?[a-zA-Z0-9_]+)\s+(eq|ne)\s+(\?[a-zA-Z0-9_]+)/i";
  638.         preg_match_all($reg_ex$filterStr$eqExprs);
  639.         foreach ($eqExprs[0as $i => $eqExpr{
  640.             $parsedFilter['strEqExprs'][$ii]['var'$this->_isDefined($eqExprs[1][$i]);
  641.             if (PEAR::isError($parsedFilter['strEqExprs'][$ii]['var'])) {
  642.                 return $parsedFilter['strEqExprs'][$ii]['var'];
  643.             }
  644.             $parsedFilter['strEqExprs'][$ii]['operator'strtolower($eqExprs[2][$i]);
  645.             $parsedFilter['strEqExprs'][$ii]['value'$this->_isDefined($eqExprs[3][$i]);
  646.             if (PEAR::isError($parsedFilter['strEqExprs'][$ii]['value'])) {
  647.                 return $parsedFilter['strEqExprs'][$ii]['value'];
  648.             }
  649.             $parsedFilter['strEqExprs'][$ii]['value_type''variable';
  650.  
  651.             $filterStr str_replace($eqExprs[0][$i]" ##strEqExpr_$ii## "$filterStr);
  652.             $ii++;
  653.         }
  654.         // parse ?var [eq | ne] <URI> or ?var [eq | ne] prefix:local_name
  655.         $reg_ex "/(\?[a-zA-Z0-9_]+)\s+(eq|ne)\s+((<\S+>)|(\S+:\S*))/i";
  656.         preg_match_all($reg_ex$filterStr$eqExprs);
  657.         foreach ($eqExprs[0as $i => $eqExpr{
  658.             $parsedFilter['strEqExprs'][$ii]['var'$this->_isDefined($eqExprs[1][$i]);
  659.             if (PEAR::isError($parsedFilter['strEqExprs'][$ii]['var'])) {
  660.                 return $parsedFilter['strEqExprs'][$ii]['var'];
  661.             }
  662.             $parsedFilter['strEqExprs'][$ii]['operator'strtolower($eqExprs[2][$i]);
  663.             if ($eqExprs[4][$i]{
  664.                 $parsedFilter['strEqExprs'][$ii]['value'trim($eqExprs[4][$i]"<>");
  665.                 $parsedFilter['strEqExprs'][$ii]['value_type''URI';
  666.             else if($eqExprs[5][$i]{
  667.                 $result $this->_validateQName($eqExprs[5][$i]RDF_RDQL_ERROR_AND);
  668.                 if (PEAR::isError($result)) {
  669.                     return $result;
  670.                 }
  671.                 $parsedFilter['strEqExprs'][$ii]['value'$eqExprs[5][$i];
  672.                 $parsedFilter['strEqExprs'][$ii]['value_type''QName';
  673.             }
  674.  
  675.             $filterStr str_replace($eqExprs[0][$i]" ##strEqExpr_$ii## "$filterStr);
  676.             $ii++;
  677.         }
  678.         $parsedFilter['evalFilterStr'$filterStr;
  679.  
  680.         // all that is left are numerical expressions and place holders for the above expressions
  681.         preg_match_all("/\?[a-zA-Z0-9_]+/"$filterStr$vars);
  682.         foreach ($vars[0as $var{
  683.             $result $this->_isDefined($var);
  684.             if (PEAR::isError($result)) {
  685.                 return $result;
  686.             }
  687.             $parsedFilter['numExprVars'][$result;
  688.         }
  689.  
  690.         return $parsedFilter;
  691.     }
  692.  
  693.     /**
  694.      * Find all query variables used in the WHERE clause.
  695.      *
  696.      * @return array [] = ?VARNAME
  697.      * @access protected
  698.      */
  699.     function findAllQueryVariables()
  700.     {
  701.         $vars = array();
  702.         foreach ($this->parsedQuery['patterns'as $pattern{
  703.             $count = 0;
  704.             foreach ($pattern as $v{
  705.                if ($v['value'&& $v['value']{0== '?'{
  706.                     ++$count;
  707.                     if (!in_array($v['value']$vars)) {
  708.                         $vars[$v['value'];
  709.                     }
  710.                 }
  711.             }
  712.             if (!$count{
  713.                 $errmsg 'pattern contains no variables';
  714.                 return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  715.             }
  716.         }
  717.  
  718.         return $vars;
  719.     }
  720.  
  721.     /**
  722.      * Replace all namespace prefixes in the pattern and constraint clause of an RDQL query
  723.      * with the namespaces declared in the USING clause and default namespaces.
  724.      *
  725.      * @access protected
  726.      */
  727.     function replaceNamespacePrefixes()
  728.     {
  729.         if (!isset($this->parsedQuery['ns'])) {
  730.             $this->parsedQuery['ns'= array();
  731.         }
  732.         // add default namespaces
  733.         // if in an RDQL query a reserved prefix (e.g. rdf: rdfs:) is used
  734.         // it will be overridden by the default namespace defined in constants.php
  735.         $this->parsedQuery['ns'array_merge($this->parsedQuery['ns']$GLOBALS['_RDF_RDQL_default_prefixes']);
  736.  
  737.         // replace namespace prefixes in the FROM clause
  738.         if (isset($this->parsedQuery['sources'])) {
  739.             foreach ($this->parsedQuery['sources'as $n => $source{
  740.                 if (isset($source['is_qname'])) {
  741.                     $result $this->_replaceNamespacePrefix($source['value']RDF_RDQL_ERROR_SOURCE);
  742.                     if (PEAR::isError($result)) {
  743.                         return $result;
  744.                     }
  745.                     $this->parsedQuery['sources'][$n$result;
  746.                 else {
  747.                     foreach ($this->parsedQuery['ns'as $prefix => $uri{
  748.                         $source['value'preg_replace('/'.$prefix.':/i'$uri$source['value']);
  749.                     }
  750.                    $this->parsedQuery['sources'][$n$source['value'];
  751.                 }
  752.             }
  753.         }
  754.  
  755.         // replace namespace prefixes in the where clause
  756.         foreach ($this->parsedQuery['patterns'as $n => $pattern{
  757.             foreach ($pattern as $key => $v{
  758.                 if ($v['value'&& $v['value']{0!= '?'{
  759.                     if (isset($v['is_qname'])) {
  760.                         $result $this->_replaceNamespacePrefix($v['value']RDF_RDQL_ERROR_WHERE);
  761.                         if (PEAR::isError($result)) {
  762.                             return $result;
  763.                         }
  764.                         $this->parsedQuery['patterns'][$n][$key]['value'$result;
  765.                         unset($this->parsedQuery['patterns'][$n][$key]['is_qname']);
  766.                     else // is quoted URI (== <URI>) or Literal
  767.                         if (isset($this->parsedQuery['patterns'][$n][$key]['is_literal'])) {
  768.                             if (isset($this->parsedQuery['patterns'][$n][$key]['l_dtype_is_qname'])) {
  769.                                 $result $this->_replaceNamespacePrefix($v['l_dtype']RDF_RDQL_ERROR_WHERE);
  770.                                 if (PEAR::isError($result)) {
  771.                                     return $result;
  772.                                 }
  773.                                 $this->parsedQuery['patterns'][$n][$key]['l_dtype'$result;
  774.                                 unset($this->parsedQuery['patterns'][$n][$key]['l_dtype_is_qname']);
  775.                             else {
  776.                                 foreach ($this->parsedQuery['ns'as $prefix => $uri{
  777.                                     $this->parsedQuery['patterns'][$n][$key]['l_dtype']
  778.                                         = preg_replace('/'.$prefix.':/i'$uri$this->parsedQuery['patterns'][$n][$key]['l_dtype']);
  779.                                 }
  780.                             }
  781.                         else {
  782.                             foreach ($this->parsedQuery['ns'as $prefix => $uri{
  783.                                 $this->parsedQuery['patterns'][$n][$key]['value']
  784.                                     = preg_replace('/'.$prefix.':/i'$uri$this->parsedQuery['patterns'][$n][$key]['value']);
  785.                             }
  786.                         }
  787.                     }
  788.                 }
  789.             }
  790.         }
  791.  
  792.         // replace prefixes in the constraint clause
  793.         if (isset($this->parsedQuery['filters'])) {
  794.             foreach ($this->parsedQuery['filters'as $n => $filter{
  795.                 foreach ($filter['strEqExprs'as $i => $expr{
  796.                     if ($expr['value_type'== 'QName'{
  797.                         $result $this->_replaceNamespacePrefix($expr['value']RDF_RDQL_ERROR_AND);
  798.                         if (PEAR::isError($result)) {
  799.                             return $result;
  800.                         }
  801.                         $this->parsedQuery['filters'][$n]['strEqExprs'][$i]['value'$result;
  802.                         $this->parsedQuery['filters'][$n]['strEqExprs'][$i]['value_type''URI';
  803.                     }
  804.                     if ($expr['value_type'== 'URI'{
  805.                         foreach ($this->parsedQuery['ns'as $prefix => $uri{
  806.                             $this->parsedQuery['filters'][$n]['strEqExprs'][$i]['value']
  807.                                 = preg_replace('/'.$prefix.':/i'$uri$this->parsedQuery['filters'][$n]['strEqExprs'][$i]['value']);
  808.                         }
  809.                     elseif ($expr['value_type'== 'Literal'{
  810.                         if (isset($expr['value_dtype_is_qname'])) {
  811.                             $result $this->_replaceNamespacePrefix($expr['value_dtype']RDF_RDQL_ERROR_AND);
  812.                             if (PEAR::isError($result)) {
  813.                                 return $result;
  814.                             }
  815.                             $this->parsedQuery['filters'][$n]['strEqExprs'][$i]['value_dtype'$result;
  816.                             unset($this->parsedQuery['filters'][$n]['strEqExprs'][$i]['value_dtype_is_qname']);
  817.                         else {
  818.                             foreach ($this->parsedQuery['ns'as $prefix => $uri{
  819.                                 $this->parsedQuery['filters'][$n]['strEqExprs'][$i]['value_dtype']
  820.                                     = preg_replace('/'.$prefix.':/i'$uri$this->parsedQuery['filters'][$n]['strEqExprs'][$i]['value_dtype']);
  821.                             }
  822.                         }
  823.                     }
  824.                 }
  825.             }
  826.         }
  827.  
  828.         unset($this->parsedQuery['ns']);
  829.     }
  830.  
  831.     // =============================================================================
  832.     // *************************** helper functions ********************************
  833.     // =============================================================================
  834.     /**
  835.      * Remove whitespace-tokens from the array $this->tokens
  836.      *
  837.      * @access protected
  838.      */
  839.     function _clearWhiteSpaces()
  840.     {
  841.         while (current($this->tokens== ' '
  842.             || current($this->tokens== "\n"
  843.             || current($this->tokens== "\t"
  844.             || current($this->tokens== "\r"
  845.         {
  846.             unset($this->tokens[key($this->tokens)]);
  847.         }
  848.     }
  849.  
  850.     /**
  851.      * Check if the query string of the given clause contains an undesired ','.
  852.      * If a comma was correctly placed then remove it and clear all whitespaces.
  853.      *
  854.      * @param string $commaExpected 
  855.      * @param string $clause_error 
  856.      * @throws PHPError
  857.      * @access protected
  858.      */
  859.     function _checkComma($commaExpected$clause_error)
  860.     {
  861.         $this->_clearWhiteSpaces();
  862.         if (current($this->tokens== ','{
  863.             if (!$commaExpected{
  864.                 $errmsg 'unexpected comma';
  865.                 return RDF_RDQL::raiseError($clause_errornullnull$errmsg);
  866.             else {
  867.                 unset($this->tokens[key($this->tokens)]);
  868.                 $result $this->_checkComma(false$clause_error);
  869.                 if (PEAR::isError($result)) {
  870.                     return $result;
  871.                 }
  872.             }
  873.         }
  874.     }
  875.  
  876.     /**
  877.      * Check if the given token is either a variable (?var) or the first token of an URI (<URI>).
  878.      * In case of an URI this function returns the whole URI string.
  879.      *
  880.      * @param string $token 
  881.      * @return array ['value'] = string
  882.      * @throws PHPError
  883.      * @access protected
  884.      */
  885.     function _validateVarUri($token)
  886.     {
  887.         if ($token{0== '?'{
  888.             $token_res['value'$this->_validateVar($tokenRDF_RDQL_ERROR_WHERE);
  889.         else {
  890.             $token_res['value'$this->_validateURI($tokenRDF_RDQL_ERROR_WHERE);
  891.             if (PEAR::isError($token_res['value'])) {
  892.                 return $token_res['value'];
  893.             }
  894.             if ($token{0!= '<'{
  895.                 $token_res['is_qname'= true;
  896.             }
  897.         }
  898.         return $token_res;
  899.     }
  900.  
  901.     /**
  902.      * Check if the given token is either a variable (?var) or the first token
  903.      * of either an URI (<URI>) or a literal ("Literal").
  904.      * In case of a literal return an array with literal properties (value, language, datatype).
  905.      * In case of a variable or an URI return only ['value'] = string.
  906.      *
  907.      * @param string $token 
  908.      * @return array ['value'] = string
  909.      *                  ['is_qname'] = boolean
  910.      *                  ['is_literal'] = boolean
  911.      *                  ['l_lang'] = string
  912.      *                  ['l_dtype'] = string
  913.      * @throws PHPError
  914.      * @access protected
  915.      */
  916.     function _validateVarUriLiteral($token)
  917.     {
  918.         if ($token{0== '?'{
  919.             $result $this->_validateVar($tokenRDF_RDQL_ERROR_WHERE);
  920.             if (PEAR::isError($result)) {
  921.                 return $result;
  922.             }
  923.             $statement_object['value'$result;
  924.         elseif ($token{0== "'" || $token{0== '"'{
  925.             $statement_object $this->_validateLiteral($token);
  926.             if (PEAR::isError($statement_object)) {
  927.                 return $statement_object;
  928.             }
  929.         elseif ($token{0== '<'{
  930.             $statement_object['value'$this->_validateURI($tokenRDF_RDQL_ERROR_WHERE);
  931.             if (PEAR::isError($statement_object['value'])) {
  932.                 return $statement_object['value'];
  933.             }
  934.         elseif (strpos($token':'!== false{
  935.             $statement_object['value'$this->_validateURI($tokenRDF_RDQL_ERROR_WHERE);
  936.             if (PEAR::isError($statement_object['value'])) {
  937.                 return $statement_object['value'];
  938.             }
  939.             $statement_object['is_qname'= true;
  940.         else {
  941.             $errmsg = " '$token' - ?Variable, &lt;URI&gt;, QName, or \"LITERAL\" expected";
  942.             return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHRnullnull$errmsg);
  943.         }
  944.         return $statement_object;
  945.     }
  946.  
  947.     /**
  948.      * Check if the given token is a valid variable name (?var).
  949.      *
  950.      * @param string $token 
  951.      * @param string $clause 
  952.      * @return string 
  953.      * @throws PHPError
  954.      * @access protected
  955.      */
  956.     function _validateVar($token$clause_error)
  957.     {
  958.         $match = array();
  959.         preg_match("/\?[a-zA-Z0-9_]+/"$token$match);
  960.         if (!isset($match[0]|| $match[0!= $token{
  961.             $errmsg htmlspecialchars($token"' - variable name contains illegal characters";
  962.             return RDF_RDQL::raiseError($clause_errornullnull$errmsg);
  963.         }
  964.         unset($this->tokens[key($this->tokens)]);
  965.         return $token;
  966.     }
  967.  
  968.     /**
  969.      * Check if $token is the first token of a valid URI (<URI>) and return the whole URI string
  970.      *
  971.      * @param string $token 
  972.      * @param string $clause_error 
  973.      * @return string 
  974.      * @throws PHPError
  975.      * @access protected
  976.      */
  977.     function _validateURI($token$clause_error)
  978.     {
  979.         if ($token{0!= '<'{
  980.             if (strpos($token':')) {
  981.                 $result $this->_validateQName($token$clause_error);
  982.                 if (PEAR::isError($result)) {
  983.                     return $result;
  984.                 }
  985.                 if ($result{
  986.                     unset($this->tokens[key($this->tokens)]);
  987.                     return rtrim($token':');
  988.                 }
  989.             }
  990.             if ($clause_error == RDF_RDQL_ERROR_WHERE{
  991.                 $errmsg htmlspecialchars($token)
  992.                     . "' - ?Variable or &lt;URI&gt; or QName expected";
  993.             else {
  994.                 $errmsg htmlspecialchars($token)
  995.                     . "' - &lt;URI&gt; or QName expected";
  996.             }
  997.             return RDF_RDQL::raiseError($clause_errornullnull$errmsg);
  998.         else {
  999.             $token_res $token;
  1000.             while ($token{strlen($token)-1!= '>' && $token != null{
  1001.                 if ($token == '(' || $token == ')' || $token == ','
  1002.                     || $token == ' ' || $token == "\n" || $token == "\r"
  1003.                 {
  1004.                     $errmsg htmlspecialchars($token_res)
  1005.                         . "' - illegal input: '$token' - '>' missing";
  1006.                     return RDF_RDQL::raiseError($clause_errornullnull$errmsg);
  1007.                 }
  1008.                 unset($this->tokens[key($this->tokens)]);
  1009.                 $token current($this->tokens);
  1010.                 $token_res .= $token;
  1011.             }
  1012.             if ($token == null{
  1013.                 $errmsg htmlspecialchars($token_res)
  1014.                     . "' - '>' missing";
  1015.                 return RDF_RDQL::raiseError($clause_errornullnull$errmsg);
  1016.             }
  1017.             unset($this->tokens[key($this->tokens)]);
  1018.             return trim($token_res'<>');
  1019.         }
  1020.     }
  1021.  
  1022.     /**
  1023.      * Check if $token is the first token of a valid literal ("LITERAL") and
  1024.      * return an array with literal properties (value, language, datatype).
  1025.      *
  1026.      * @param string $token 
  1027.      * @return array ['value'] = string
  1028.      *                    ['is_literal'] = boolean
  1029.      *                    ['l_lang'] = string
  1030.      *                    ['l_dtype'] = string
  1031.      *                    ['l_dtype_is_qname'] = boolean
  1032.      * @throws PHPError
  1033.      * @access protected
  1034.      */
  1035.     function _validateLiteral($token)
  1036.     {
  1037.         $quotation_mark $token{0};
  1038.         $statement_object = array (
  1039.             'value' => '',
  1040.             'is_literal' => true,
  1041.             'l_lang' => '',
  1042.             'l_dtype' => ''
  1043.         );
  1044.         $this->tokens[key($this->tokens)substr($token1);
  1045.  
  1046.         $return = false;
  1047.         foreach ($this->tokens as $k => $token{
  1048.             if ($token != null && $token{strlen($token)-1== $quotation_mark{
  1049.                 $token rtrim($token$quotation_mark);
  1050.                 $return = true;
  1051.                 // parse @language (^^datatype)?
  1052.             elseif (strpos($token$quotation_mark '@')
  1053.                 || substr($token02== $quotation_mark '@'
  1054.             {
  1055.                 $lang substr($tokenstrpos($token$quotation_mark '@'+ 2);
  1056.                 if (strpos($lang'^^'|| substr($lang02== '^^'{
  1057.                     $dtype substr($langstrpos($lang'^^'+ 2);
  1058.                     if (!$dtype{
  1059.                         $errmsg $quotation_mark $statement_object['value']
  1060.                             . $token " - datatype expected";
  1061.                         return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  1062.                     }
  1063.                     $statement_object['l_dtype'$this->_validateURI($dtypeRDF_RDQL_ERROR_WHERE);
  1064.                     if (PEAR::isError($statement_object['l_dtype'])) {
  1065.                         return $statement_object['l_dtype'];
  1066.                     }
  1067.                     if ($dtype{0!= '<'{
  1068.                         $statement_object['l_dtype_is_qname'= true;
  1069.                     }
  1070.                     $lang substr($lang0strpos($lang'^^'));
  1071.                 }
  1072.                 if (!$lang{
  1073.                     $errmsg $quotation_mark $statement_object['value']
  1074.                         . $token " - language expected";
  1075.                     return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  1076.                 }
  1077.                 $statement_object['l_lang'$lang;
  1078.                 $token substr($token0strpos($token$quotation_mark '@'));
  1079.                 $return = true;
  1080.                 // parse ^^datatype
  1081.             elseif (strpos($token$quotation_mark '^^'|| substr($token03== $quotation_mark '^^'{
  1082.                 $dtype substr($tokenstrpos($token$quotation_mark '^^'+ 3);
  1083.                 if (!$dtype{
  1084.                     $errmsg $quotation_mark $statement_object['value']
  1085.                         . $token " - datatype expected";
  1086.                     return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  1087.                 }
  1088.                 $statement_object['l_dtype'$this->_validateURI($dtypeRDF_RDQL_ERROR_WHERE);
  1089.                 if (PEAR::isError($statement_object['l_dtype'])) {
  1090.                     return $statement_object['l_dtype'];
  1091.                 }
  1092.                 if ($dtype{0!= '<'{
  1093.                     $statement_object['l_dtype_is_qname'= true;
  1094.                 }
  1095.                 $token substr($token0strpos($token$quotation_mark '^^'));
  1096.                 $return = true;
  1097.             elseif (strpos($token$quotation_mark)) {
  1098.                 $errmsg = "'$token' - illegal input";
  1099.                 return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  1100.             }
  1101.             $statement_object['value'.= $token;
  1102.             unset($this->tokens[$k]);
  1103.             if ($return{
  1104.                 return $statement_object;
  1105.             }
  1106.         }
  1107.         $errmsg = "quotation end mark: $quotation_mark missing";
  1108.         return RDF_RDQL::raiseError(RDF_RDQL_ERROR_WHEREnullnull$errmsg);
  1109.     }
  1110.  
  1111.     /**
  1112.      * Check if the given token is a valid QName.
  1113.      *
  1114.      * @param   string  $token 
  1115.      * @param   string  $clause_error 
  1116.      * @return  boolean 
  1117.      * @throws  PHPError
  1118.      * @access    protected
  1119.      */
  1120.     function _validateQName($token$clause_error)
  1121.     {
  1122.         $parts explode(':'$token);
  1123.         if (count($parts> 2{
  1124.             $errmsg = "illegal QName: '$token'";
  1125.             return RDF_RDQL::raiseError($clause_errornullnull$errmsg);
  1126.         }
  1127.         if (!$this->_validateNCName($parts[0])) {
  1128.             $errmsg = "illegal prefix in QName: '$token'";
  1129.             return RDF_RDQL::raiseError($clause_errornullnull$errmsg);
  1130.         }
  1131.         if ($parts[1&& !$this->_validateNCName($parts[1])) {
  1132.             $errmsg = "illegal local part in QName: '$token'";
  1133.             return RDF_RDQL::raiseError($clause_errornullnull$errmsg);
  1134.         }
  1135.  
  1136.         return true;
  1137.     }
  1138.  
  1139.     /**
  1140.      * Check if the given token is a valid NCName.
  1141.      *
  1142.      * @param   string  $token 
  1143.      * @return  boolean 
  1144.      * @access    protected
  1145.      */ 
  1146.     function _validateNCName($token)
  1147.     {
  1148.         preg_match("/[a-zA-Z_]+[a-zA-Z_0-9.\-]*/"$token$match);
  1149.         if (isset($match[0]&& $match[0== $token{
  1150.             return true;
  1151.         }
  1152.         return false;
  1153.     }
  1154.  
  1155.     /**
  1156.      * Check if the given token is a valid namespace prefix.
  1157.      *
  1158.      * @param string $token 
  1159.      * @return string 
  1160.      * @throws PHPError
  1161.      * @access protected
  1162.      */
  1163.     function _validatePrefix($token)
  1164.     {
  1165.         if (!$this->_validateNCName($token)) {
  1166.             $errmsg "'" htmlspecialchars($token)
  1167.                 . "' - illegal input, namespace prefix expected";
  1168.             return RDF_RDQL::raiseError(RDF_RDQL_ERROR_USINGnullnull$errmsg);
  1169.         }
  1170.         unset($this->tokens[key($this->tokens)]);
  1171.         return $token;
  1172.     }
  1173.  
  1174.     /**
  1175.      * Replace a prefix in a given QName and return a full URI.
  1176.      *
  1177.      * @param   string  $qName 
  1178.      * @param   string  $clasue_error 
  1179.      * @return  string 
  1180.      * @throws  PHPError
  1181.      * @access    protected
  1182.      */ 
  1183.      function _replaceNamespacePrefix($qName$clause_error)
  1184.      {
  1185.         $qName_parts explode(':'$qName);
  1186.         if (!array_key_exists($qName_parts[0]$this->parsedQuery['ns'])) {
  1187.             $errmsg "undefined prefix: '" .$qName_parts[0. "' in: '$qName'";
  1188.             return RDF_RDQL::raiseError($clause_errornullnull$errmsg);
  1189.         }
  1190.         return $this->parsedQuery['ns'][$qName_parts[0]] .$qName_parts[1];
  1191.      }
  1192.  
  1193.     /**
  1194.      * Check if all variables from the SELECT clause are defined in the WHERE clause
  1195.      *
  1196.      * @access protected
  1197.      */
  1198.     function _checkSelectVars()
  1199.     {
  1200.         foreach ($this->parsedQuery['selectVars'as $var{
  1201.             $result $this->_isDefined($var);
  1202.             if (PEAR::isError($result)) {
  1203.                 return $result;
  1204.             }
  1205.         }
  1206.     }
  1207.  
  1208.     /**
  1209.      * Check if the given variable is defined in the WHERE clause.
  1210.      *
  1211.      * @param  $var string
  1212.      * @return string 
  1213.      * @throws PHPError
  1214.      * @access protected
  1215.      */
  1216.     function _isDefined($var)
  1217.     {
  1218.         $allQueryVars $this->findAllQueryVariables();
  1219.         if (PEAR::isError($allQueryVars)) {
  1220.             return $allQueryVars;
  1221.         }
  1222.  
  1223.         if (!in_array($var$allQueryVars)) {
  1224.             $errmsg = "'$var' - variable must be defined in the WHERE clause";
  1225.             return RDF_RDQL::raiseError(RDF_RDQL_ERRORnullnull$errmsg);
  1226.         }
  1227.         return $var;
  1228.     }
  1229.  
  1230.     /**
  1231.      * Throw an error if the regular expression from the AND clause is not quoted.
  1232.      *
  1233.      * @param string $filterString 
  1234.      * @param string $lQuotMark 
  1235.      * @param string $rQuotMark 
  1236.      * @throws PHPError
  1237.      * @access protected
  1238.      */
  1239.     function _checkRegExQuotation($filterString$lQuotMark$rQuotMark)
  1240.     {
  1241.         if (!$lQuotMark{
  1242.             $errmsg = "'$filterString' - regular expressions must be quoted";
  1243.             return RDF_RDQL::raiseError(RDF_RDQL_ERROR_ANDnullnull$errmsg);
  1244.         }
  1245.  
  1246.         if ($lQuotMark != $rQuotMark{
  1247.             $errmsg = "'$filterString' - quotation end mark in the regular expression missing";
  1248.             return RDF_RDQL::raiseError(RDF_RDQL_ERROR_ANDnullnull$errmsg);
  1249.         }
  1250.     }
  1251. // end: Class RDQLParser
  1252.  
  1253. ?>

Documentation generated on Mon, 11 Mar 2019 15:39:50 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.