gestione gare pubbliche
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 

215 righe
6.4 KiB

<?php
use lyquidity\xml\MS\XmlNamespaceManager;
use lyquidity\xml\xpath\XPathNodeType;
use lyquidity\XPath2\NodeProvider;
use lyquidity\XPath2\XPath2Expression;
use lyquidity\XPath2\DOM\DOMXPathNavigator;
use lyquidity\XPath2\FalseValue;
use lyquidity\XPath2\TrueValue;
use lyquidity\XPath2\XPath2Exception;
use SebastianBergmann\Type\FalseType;
/**
* Helper class to run XPath 2.0 queries on XML files
*/
class XML_XPath20_Querier
{
public $dom; // @var DOMDocument
protected $nsMgr; // @var XmlNamespaceManager
public $navigator; // @var DOMXPathNavigator
protected $xpath10; // Runner di XPath 1.0
protected $code_cache;
protected $code_cache_enabled = true;
protected $result_cache;
protected $result_cache_enabled = true;
/**
* Initialize the Querier with an existing DOM
*
* @param DOMDocument $dom
*/
function __construct($dom, $enable_result_cache = true, $enable_code_cache = true)
{
$this->dom = $dom;
$this->xpath10 = new DOMXPath($this->dom);
$this->result_cache_enabled = $enable_result_cache;
$this->code_cache_enabled = $enable_code_cache;
// Load the namespaces from the document. $node is a DOMNameSpaceNode so extract the prefix from the node name
$this->nsMgr = new XmlNamespaceManager();
$xpath = new DOMXPath($this->dom);
foreach ($xpath->query('namespace::*', $this->dom->documentElement) as $node) {
$this->nsMgr->addNamespace(str_replace(array('xmlns', ':'), array('', ''), $node->nodeName), (string)$node->nodeValue);
}
// Create a navigator to navigate the document and move to root
$this->navigator = new DOMXPathNavigator($this->dom, $this->nsMgr);
$this->navigator->MoveToRoot();
}
/**
* Helper function to convert from (some) lyquidity types to native ones
*
* @param mixed $result
* @return mixed
*/
protected function processResult($result)
{
if ($result instanceof FalseValue)
return False;
if ($result instanceof TrueValue)
return True;
return $result;
}
/**
* Runs a XPath 2.0 query and returns an array of DomNodes
*
* @param String $query
* @return array[DOMNode]
*/
public function runQuery(String $query): array
{
// Array di risultati
$results = [];
try {
$xpath10results = @$this->xpath10->query($query);
} catch (\Throwable $t) {
$xpath10results = false;
}
if ($xpath10results !== false) {
// Creiamo l'array di nodi
foreach ($xpath10results as $node) {
$results[] = $node;
}
} else {
// Compile the XPath 2.0
$expression = null;
if ($this->code_cache_enabled) {
$expression = $this->code_cache[$query] ?? null;
}
if ($expression === null) {
$expression = XPath2Expression::Compile($query, $this->nsMgr);
if ($this->code_cache_enabled)
$this->code_cache[$query] = $expression;
}
$provider = new NodeProvider($this->navigator);
// Evaluate the expression
$result = $expression->EvaluateWithVars($provider, null);
if ($result) {
// If there is a list of context then iterate over them. In this case $result will be ChildNodeIterator
foreach ($result as
/** @var DOMXPathNavigator $localNav */
$localNav) {
$provider = new NodeProvider($localNav);
$domNode = $localNav->getUnderlyingObject();
$results[] = $domNode;
}
}
}
// Return results
return $results;
}
/**
* Runs a XPath 2.0 query on a XPath 2.0 context query
*
* @param String $context_query
* @param String $query
* @return array
*/
public function runQueryContext(String $context_query, String $query): array
{
if ($this->result_cache_enabled && isset($this->result_cache[$context_query]) && isset($this->result_cache[$context_query][$query])) {
return $this->result_cache[$context_query][$query];
}
$results = [];
$context = $this->runQuery($context_query);
if (!empty($context)) {
// If there is a list of context then iterate over them. In this case $result will be ChildNodeIterator
foreach ($context as /** @var DOMNode $domNode */ $domNode) {
$localNav = new DOMXPathNavigator($domNode);
$provider = new NodeProvider($localNav);
// Compile the XPath 2.0
$expression = null;
if ($this->code_cache_enabled) {
$expression = $this->code_cache[$query] ?? null;
}
if ($expression === null) {
$expression = XPath2Expression::Compile($query, $this->nsMgr);
if ($this->code_cache_enabled)
$this->code_cache[$query] = $expression;
}
// Evaluate it in the current context
$result = $expression->EvaluateWithVars($provider, null);
// Organize the results in a simple to use array
$results[] = $this->processResult($result);
}
}
// Return results
if ($this->result_cache_enabled)
$this->result_cache[$context_query][$query] = $results;
return $results;
}
public const XPATH_FAIL_EXCEPTION = 1;
public const XPATH_FAIL_NO_RESULTS = 2;
public const XPATH_FAIL_NOT_ENOUGH_RESULTS = 3;
public const XPATH_FAIL_WRONG_TYPE = 4;
/**
* Will evaluate an XPath 2.0 condition to True/False and fail gracefully
*
* @param string $query
* @param string||null $context If not null, manually provide a context to execute the query
* @return array||null The value of the evaluation
*/
public function evalBoolean($query, $context, $index, &$error): ?bool
{
// Evaluate the condition
try {
$condition_results = $this->runQueryContext($context, $query);
} catch (XPath2Exception $xpath_ex) {
// TODO Un giorno magari le debugghiamo
$error = self::XPATH_FAIL_EXCEPTION;
return null;
} catch (\Throwable $ex) {
throw $ex;
$error = self::XPATH_FAIL_EXCEPTION;
return null;
}
// Get count of results
$cr_count = count($condition_results);
// No results
if ($cr_count === 0) {
$error = self::XPATH_FAIL_NO_RESULTS;
return null;
}
if ($index >= $cr_count) {
$error = self::XPATH_FAIL_NOT_ENOUGH_RESULTS;
return null;
}
$condition_result = $condition_results[$index];
// Not a boolean
if (!is_bool($condition_result)) {
$error = self::XPATH_FAIL_WRONG_TYPE;
throw new Exception("Wrong type, boolean expected.");
return null;
}
return $condition_result;
}
}