145 lines
4.2 KiB
PHP
145 lines
4.2 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @file
|
|
* Provides a custom version of DOMXPath for use with feeds_xpathparser.
|
|
*/
|
|
class FeedsXPathParserDOMXPath extends DOMXPath {
|
|
protected $config = array();
|
|
protected $modifiedQueries = array();
|
|
|
|
public function __construct(DOMDocument $doc) {
|
|
$this->namespaces = array();
|
|
$simple = simplexml_import_dom($doc);
|
|
// An empty DOMDocument will make $simple NULL.
|
|
if ($simple !== NULL) {
|
|
$this->namespaces = $simple->getNamespaces(TRUE);
|
|
}
|
|
$this->doc = $doc;
|
|
parent::__construct($doc);
|
|
}
|
|
|
|
public function setConfig(array $config) {
|
|
$this->config = $config;
|
|
}
|
|
|
|
protected function debug($data, $source) {
|
|
$output = "$source : <ul>";
|
|
if ($data instanceof DOMNodeList) {
|
|
foreach ($data as $node) {
|
|
$output .= '<li>' . check_plain($this->doc->saveXML($node)) . '</li>';
|
|
}
|
|
}
|
|
else {
|
|
$output .= '<li>' . check_plain($data) . '</li>';
|
|
}
|
|
$output .= '</ul>';
|
|
drupal_set_message($output);
|
|
}
|
|
|
|
/**
|
|
* Executes an XPath query with namespace support.
|
|
*
|
|
* @param $xpath
|
|
* The DOMXPath object.
|
|
*
|
|
* @param $query
|
|
* An XPath query.
|
|
*
|
|
* @return array
|
|
* An array containing the results of the query.
|
|
*/
|
|
public function namespacedQuery($query, $context, $source) {
|
|
$this->addDefaultNamespace($query);
|
|
$results = $this->_query($query, $context);
|
|
if (in_array($source, $this->config['debug'])) {
|
|
$this->debug($results, $source);
|
|
}
|
|
|
|
if (is_object($this->error) && $this->config['errors']) {
|
|
|
|
if ($this->error->level == LIBXML_ERR_ERROR) {
|
|
drupal_set_message(
|
|
t("There was an error during the XPath query: %query.<br />
|
|
Libxml returned the message: %message, with the error code: %code.",
|
|
array('%query' => $query,
|
|
'%message' => trim($this->error->message),
|
|
'%code' => $this->error->code)),
|
|
'error',
|
|
FALSE);
|
|
}
|
|
elseif ($this->error->level == LIBXML_ERR_WARNING) {
|
|
drupal_set_message(
|
|
t("There was an error during the XPath query: %query.<br />
|
|
Libxml returned the message: %message, with the error code: %code.",
|
|
array('%query' => $query,
|
|
'%message' => trim($this->error->message),
|
|
'%code' => $this->error->code)),
|
|
'warning',
|
|
FALSE);
|
|
}
|
|
}
|
|
|
|
// DOMXPath::evaluate() and DOMXPath::query() will return FALSE on error or
|
|
// if the value is false. We check error result and return NULL in case
|
|
// of error.
|
|
if (is_object($this->error) && $this->error->level == LIBXML_ERR_ERROR) {
|
|
return NULL;
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Normalizes XPath queries, adding the default namespace.
|
|
*
|
|
* @param $query
|
|
* An XPath query string
|
|
*/
|
|
protected function addDefaultNamespace(&$query) {
|
|
foreach ($this->namespaces as $prefix => $namespace) {
|
|
if ($prefix === '') {
|
|
$this->registerNamespace('__default__', $namespace);
|
|
|
|
// Replace all the elements without prefix by the default prefix.
|
|
if (!isset($this->modifiedQueries[$query])) {
|
|
$parser = new FeedsXPathParserQueryParser($query);
|
|
$modQuery = $parser->getQuery();
|
|
$this->modifiedQueries[$query] = $modQuery;
|
|
$query = $modQuery;
|
|
}
|
|
else {
|
|
$query = $this->modifiedQueries[$query];
|
|
}
|
|
}
|
|
else {
|
|
$this->registerNamespace($prefix, $namespace);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Here we set libxml_use_internal_errors to TRUE because depending on the
|
|
* libxml version, $xml->xpath() might return FALSE or an empty array() when
|
|
* a query doesn't match.
|
|
*/
|
|
protected function _query($query, $context = NULL) {
|
|
$use_errors = libxml_use_internal_errors(TRUE);
|
|
|
|
// Perfom XPath query.
|
|
// So, grrr. FALSE is returned when there is an error. However, FALSE is
|
|
// also a valid return value from DOMXPath::evaluate(). Ex: '1 = 2'
|
|
if ($context) {
|
|
$results = $this->evaluate($query, $context);
|
|
}
|
|
else {
|
|
$results = $this->query($query);
|
|
}
|
|
|
|
$this->error = libxml_get_last_error();
|
|
libxml_clear_errors();
|
|
libxml_use_internal_errors($use_errors);
|
|
return $results;
|
|
}
|
|
}
|