Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
mwillbanks committed Oct 14, 2015
2 parents 46caa59 + c359837 commit c89f2d8
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 17 deletions.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@

All notable changes to this project will be documented in this file, in reverse chronological order by release.

## 2.6.0 - TBD

### Added

- [#2](https://github.com/zendframework/zend-dom/pull/4) ads context node
support for DOMXPath->query that supports querying in the context of a
specific node.

### Deprecated

- Nothing.

### Removed

- Nothing.

### Fixed

- Nothing.

## 2.5.2 - TBD

### Added
Expand Down
11 changes: 8 additions & 3 deletions src/DOMXPath.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,20 @@ class DOMXPath extends \DOMXPath
* raising an error
*
* @param string $expression The XPath expression to evaluate.
* @param \DOMNode $contextNode
* @return \DOMNodeList
* @throws ErrorException
*/
public function queryWithErrorException($expression)
public function queryWithErrorException($expression, \DOMNode $contextNode = null)
{
$this->errors = [null];

set_error_handler([$this, 'addError'], E_WARNING);
$nodeList = $this->query($expression);
if ($contextNode === null) {
$contextNode = $this->document->documentElement;
}

set_error_handler([$this, 'addError'], \E_WARNING);
$nodeList = $this->query($expression, $contextNode);
restore_error_handler();

$exception = array_pop($this->errors);
Expand Down
5 changes: 3 additions & 2 deletions src/Document/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ class Query
* @param string $expression CSS selector or XPath query
* @param Document $document Document to query
* @param string $type The type of $expression
* @param \DOMNode $contextNode
* @return NodeList
*/
public static function execute($expression, Document $document, $type = self::TYPE_XPATH)
public static function execute($expression, Document $document, $type = self::TYPE_XPATH, \DOMNode $contextNode = null)
{
// Expression check
if ($type === static::TYPE_CSS) {
Expand All @@ -50,7 +51,7 @@ public static function execute($expression, Document $document, $type = self::TY
($xpathPhpfunctions === true) ? $xpath->registerPHPFunctions() : $xpath->registerPHPFunctions($xpathPhpfunctions);
}

$nodeList = $xpath->queryWithErrorException($expression);
$nodeList = $xpath->queryWithErrorException($expression, $contextNode);
return new NodeList($nodeList);
}

Expand Down
27 changes: 22 additions & 5 deletions src/NodeList.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,27 @@ class NodeList implements Iterator, Countable, ArrayAccess
*/
protected $xpathQuery;

/**
* @var DOMNode|null
*/
protected $contextNode;

/**
* Constructor
*
* @param string $cssQuery
* @param string|array $xpathQuery
* @param DOMDocument $document
* @param DOMNodeList $nodeList
* @param DOMNode|null $contextNode
*/
public function __construct($cssQuery, $xpathQuery, DOMDocument $document, DOMNodeList $nodeList)
public function __construct($cssQuery, $xpathQuery, DOMDocument $document, DOMNodeList $nodeList, DOMNode $contextNode = null)
{
$this->cssQuery = $cssQuery;
$this->xpathQuery = $xpathQuery;
$this->document = $document;
$this->nodeList = $nodeList;
$this->cssQuery = $cssQuery;
$this->xpathQuery = $xpathQuery;
$this->document = $document;
$this->nodeList = $nodeList;
$this->contextNode = $contextNode;
}

/**
Expand Down Expand Up @@ -97,6 +104,16 @@ public function getDocument()
return $this->document;
}

/**
* Retrieve context node
*
* @return DOMNode
*/
public function getContextNode()
{
return $this->contextNode;
}

/**
* Iterator: rewind to first element
*
Expand Down
17 changes: 10 additions & 7 deletions src/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,23 +206,25 @@ public function getDocumentErrors()
* Perform a CSS selector query
*
* @param string $query
* @param DOMNode $contextNode
* @return NodeList
*/
public function execute($query)
public function execute($query, DOMNode $contextNode = null)
{
$xpathQuery = Document\Query::cssToXpath($query);
return $this->queryXpath($xpathQuery, $query);
return $this->queryXpath($xpathQuery, $query, $contextNode);
}

/**
* Perform an XPath query
*
* @param string|array $xpathQuery
* @param string|null $query CSS selector query
* @param DOMNode $contextNode $contextNode
* @throws Exception\RuntimeException
* @return NodeList
*/
public function queryXpath($xpathQuery, $query = null)
public function queryXpath($xpathQuery, $query = null, DOMNode $contextNode = null)
{
if (null === ($document = $this->getDocument())) {
throw new Exception\RuntimeException('Cannot query; no document registered');
Expand Down Expand Up @@ -266,8 +268,8 @@ public function queryXpath($xpathQuery, $query = null)
throw new Exception\RuntimeException(sprintf('Error parsing document (type == %s)', $type));
}

$nodeList = $this->getNodeList($domDoc, $xpathQuery);
return new NodeList($query, $xpathQuery, $domDoc, $nodeList);
$nodeList = $this->getNodeList($domDoc, $xpathQuery, $contextNode);
return new NodeList($query, $xpathQuery, $domDoc, $nodeList, $contextNode);
}

/**
Expand Down Expand Up @@ -297,10 +299,11 @@ public function registerXpathPhpFunctions($xpathPhpFunctions = true)
*
* @param DOMDocument $document
* @param string|array $xpathQuery
* @param DOMNode $contextNode
* @return \DOMNodeList
* @throws \ErrorException If query cannot be executed
*/
protected function getNodeList($document, $xpathQuery)
protected function getNodeList($document, $xpathQuery, DOMNode $contextNode = null)
{
$xpath = new DOMXPath($document);
foreach ($this->xpathNamespaces as $prefix => $namespaceUri) {
Expand All @@ -314,7 +317,7 @@ protected function getNodeList($document, $xpathQuery)
}
$xpathQuery = (string) $xpathQuery;

$nodeList = $xpath->queryWithErrorException($xpathQuery);
$nodeList = $xpath->queryWithErrorException($xpathQuery, $contextNode);
return $nodeList;
}
}
9 changes: 9 additions & 0 deletions test/DocumentTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,13 @@ public function testLoadingXmlContainingDoctypeShouldFailToPreventXxeAndXeeAttac
$this->setExpectedException(RuntimeException::class);
Document\Query::execute('/', $this->document);
}

public function testContextNode()
{
$this->loadHtml();
$results = Document\Query::execute('//div[@id="subnav"]', $this->document, Document\Query::TYPE_XPATH);
$contextNode = $results[0];
$results = Document\Query::execute('.//li', $this->document, Document\Query::TYPE_XPATH, $contextNode);
$this->assertSame('Item 1', $results[0]->nodeValue);
}
}

0 comments on commit c89f2d8

Please sign in to comment.