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 :
";
if ($data instanceof DOMNodeList) {
foreach ($data as $node) {
$output .= '- ' . check_plain($this->doc->saveXML($node)) . '
';
}
}
else {
$output .= '- ' . check_plain($data) . '
';
}
$output .= '
';
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.
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.
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;
}
}