Applies some optional post-processing to the HTML in the DOM document.

@param \DOMXPath $xPath

@return void
503320
private function postProcess(\DOMXPath $xPath)
    {
        if ($this->shouldMapCssToHtml) {
            $this->mapAllInlineStylesToHtmlAttributes($xPath);
        }
        if ($this->shouldRemoveInvisibleNodes) {
            $this->removeInvisibleNodes($xPath);
        }
    }
1315618
public function process(\DOMDocument $xml)
    {
        $xpath = new \DOMXPath($xml);
        $nodes = $xpath->query('//tag[@name=\'covers\']');

        /** @var \DOMElement $node */
        foreach ($nodes as $node) {
            $refers = $node->getAttribute('refers');
            $refers_array = explode('::', $refers);

            // determine the type so we know where to put the @coveredby tag on
            $type = 'class';
            if (isset($refers_array[1])) {
                // starts with $ = property, ends with () = method,
                // otherwise constant
                $type = $refers_array[1][0] == '$' ? 'property' : 'constant';
                $type = substr($refers_array[1], -2) == '()' ? 'method' : $type;
            }

            switch ($type) {
                case 'class':
                    // escape single quotes in the class name
                    $xpath_refers = 'concat(\''.str_replace(
                        array("'", '"'),
                        array('\', "\'", \'', '\', \'"\' , \''),
                        $refers
                    ) . "', '')";

                    $qry = '/project/file/class[full_name=' . $xpath_refers . ']';
                    break;
                default:
                    $class_name = $refers_array[0];

                    // escape single quotes in the class name
                    $xpath_class_name = 'concat(\''.str_replace(
                        array("'", '"'),
                        array('\', "\'", \'', '\', \'"\' , \''),
                        $class_name
                    ) . "', '')";

                    // escape single quotes in the method name
                    $xpath_method_name = 'concat(\''.str_replace(
                        array("'", '"'),
                        array('\', "\'", \'', '\', \'"\' , \''),
                        rtrim($refers_array[1], '()')
                    ) . "', '')";

                    $qry = '/project/file/class[full_name=' . $xpath_class_name
                        . ']/'.$type.'[name=' . $xpath_method_name .']';
                    break;
            }

            /** @noinspection PhpUsageOfSilenceOperatorInspection as there is no pre-validation possible */
            $referral_nodes = @$xpath->query($qry);

            // if the query is wrong; output a Critical error and continue to
            // the next @covers
            if ($referral_nodes === false) {
                // $this->log(
                //    'An XPath error occurs while processing @covers, the query used was: ' . $qry,
                //    LogLevel::CRITICAL
                // );
                continue;
            }

            // check if the result is unique; if not we error and continue
            // to the next @covers
            if ($referral_nodes->length > 1) {
                continue;
            }

            // if there is one matching element; link them together
            if ($referral_nodes->length > 0) {
                /** @var \DOMElement $referral  */
                $referral = $referral_nodes->item(0);
                $docblock = $referral->getElementsByTagName('docblock');
                if ($docblock->length < 1) {
                    $docblock = new \DOMElement('docblock');
                    $referral->appendChild($docblock);
                } else {
                    $docblock = $docblock->item(0);
                }

                $used_by = new \DOMElement('tag');
                $docblock->appendChild($used_by);
                $used_by->setAttribute('name', 'used_by');
                $used_by->setAttribute('line', '');

                // gather the name of the referring element and set that as refers
                // attribute
                if ($node->parentNode->parentNode->nodeName == 'class') {
                    // if the element where the @covers is in is a class; nothing
                    // more than the class name need to returned
                    $referral_name = $node->parentNode->parentNode
                        ->getElementsByTagName('full_name')->item(0)->nodeValue;
                } else {

                    $referral_class_name = null;
                    if ($node->parentNode->parentNode->nodeName == 'method') {
                        // gather the name of the class where the @covers is in
                        $referral_class_name = $node->parentNode->parentNode
                            ->parentNode->getElementsByTagName('full_name')->item(0)
                            ->nodeValue;
                    }

                    // gather the name of the subelement of the class where
                    // the @covers is in
                    $referral_name = $node->parentNode->parentNode
                        ->getElementsByTagName('name')->item(0)->nodeValue;

                    // if it is a method; suffix with ()
                    if ($node->parentNode->parentNode->nodeName == 'method'
                        || $node->parentNode->parentNode->nodeName == 'function'
                    ) {
                        $referral_name .= '()';
                    }

                    // only prefix class name if this is a class member
                    if ($referral_class_name) {
                        $referral_name = $referral_class_name . '::'
                            . $referral_name;
                    }
                }

                $used_by->setAttribute('description', $referral_name);
                $used_by->setAttribute('refers', $referral_name);
            }
        }

        return $xml;
    }
754073
public function click($xpath) {
    $elements = $this->findElement($xpath, 1);
    $this->browser->click($elements["page_id"], $elements["ids"][0]);
  }
139613
protected function loadElementsFromXmlFileWithPath($xmlFile, $nodePath)
    {
        $xml = file_get_contents($xmlFile);
        // Remove whitespaces between closing tag and opening tag.
        $xml = preg_replace('/>\s+</', '><', $xml);

        $doc = new \DOMDocument();
        $doc->loadXML($xml);

        $xpath = new \DOMXpath($doc);
        $elements = $xpath->query($nodePath);

        return $elements;
    }
38352
public static function deleteElementsByXpath($node, $xpath_query, $namespaces = array())
    {
        if(is_a($node, 'DOMDocument'))
        {
            $xpath = new DOMXPath($node);
        }
        elseif(is_a($node, 'DOMNode'))
        {
            $xpath = new DOMXPath($node->ownerDocument);
        }
        else
        {
            return false;
        }

        foreach($namespaces as $prefix => $namespaceURI)
        {
            $xpath->registerNamespace($prefix, $namespaceURI);
        }

        $node_list = $xpath->query($xpath_query, $node);

        if($node_list->length > 0)
        {
            foreach($node_list as $node_to_delete)
            {
                if(isset($node_to_delete->parentNode))
                {
                    $node_to_delete->parentNode->removeChild($node_to_delete);
                }
            }
        }
    }
439336
protected final function loadHTML(DOMDocument $dom, string $html)
   {
       try {
           $dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
       } catch (Throwable $e) {
           throw new RuntimeException("Can't load HTML: " . $e->getMessage());
       }
   }
672007
public function iShouldSeeTextInXpath($xpath, $regex)
    {
        $result = $this->getSession()->getPage()->find('xpath', $xpath);

        if (is_null($result)) {
            // We should only have one element
            throw new ExpectationException(
                sprintf(
                    'The xpath %s returned no results on %s',
                    $xpath,
                    $this->getSession()->getCurrentUrl()
                ),
                $this->getSession()->getDriver()
            );
        }

        if (0 === preg_match(ReformatRegex::spaceTabsEqual(sprintf('/%s/', $regex)), trim(strip_tags($result->getHtml())))) {
            // Text not found
            throw new ExpectationException(
                sprintf(
                    'The content %s can not be found on %s in element %s',
                    $xpath,
                    $this->getSession()->getCurrentUrl(),
                    $regex
                ),
                $this->getSession()->getDriver()
            );
        }
    }
351412
public function before_path($path) {
        if ($this->path_is_grouped($path) and !isset($this->currentdata[$path])) {
            // If the grouped element itself does not contain any final tags,
            // we would not get any chunk data for it. So we add an artificial
            // empty data chunk here that will be eventually replaced with
            // real data later in {@link self::postprocess_chunk()}.
            $this->currentdata[$path] = array(
                'path' => $path,
                'level' => substr_count($path, '/') + 1,
                'tags' => array(),
            );
        }
        if (!$this->grouped_parent_exists($path)) {
            parent::before_path($path);
        }
    }
387457
private function getNodesToExclude(\DOMXPath $xPath)
    {
        $excludedNodes = [];
        foreach (array_keys($this->excludedSelectors) as $selectorToExclude) {
            try {
                $matchingNodes = $xPath->query($this->translateCssToXpath($selectorToExclude));
            } catch (\InvalidArgumentException $e) {
                if ($this->debug) {
                    throw $e;
                }
                continue;
            }
            foreach ($matchingNodes as $node) {
                $excludedNodes[] = $node;
            }
        }

        return $excludedNodes;
    }
151208
public function loadXml( $xml )
	{
		$this->document	= new DOMDocument();
		$validator	= new XML_Validator();
		if( !$validator->validate( $xml ) ){
			$message	= $validator->getErrorMessage();
			throw new InvalidArgumentException( 'XML is invalid ('.$message.')' );
		}
		$this->document->loadXml( $xml );
		$this->xPath	= new DOMXPath( $this->document );
	}
7074
private function relativize(string $xpath): string
    {
        $expressions = [];

        // An expression which will never match to replace expressions which cannot match in the crawler
        // We cannot drop
        $nonMatchingExpression = 'a[name() = "b"]';

        $xpathLen = \strlen($xpath);
        $openedBrackets = 0;
        $startPosition = strspn($xpath, " \t\n\r\0\x0B");

        for ($i = $startPosition; $i <= $xpathLen; ++$i) {
            $i += strcspn($xpath, '"\'[]|', $i);

            if ($i < $xpathLen) {
                switch ($xpath[$i]) {
                    case '"':
                    case "'":
                        if (false === $i = strpos($xpath, $xpath[$i], $i + 1)) {
                            return $xpath; // The XPath expression is invalid
                        }
                        continue 2;
                    case '[':
                        ++$openedBrackets;
                        continue 2;
                    case ']':
                        --$openedBrackets;
                        continue 2;
                }
            }
            if ($openedBrackets) {
                continue;
            }

            if ($startPosition < $xpathLen && '(' === $xpath[$startPosition]) {
                // If the union is inside some braces, we need to preserve the opening braces and apply
                // the change only inside it.
                $j = 1 + strspn($xpath, "( \t\n\r\0\x0B", $startPosition + 1);
                $parenthesis = substr($xpath, $startPosition, $j);
                $startPosition += $j;
            } else {
                $parenthesis = '';
            }
            $expression = rtrim(substr($xpath, $startPosition, $i - $startPosition));

            if (0 === strpos($expression, 'self::*/')) {
                $expression = './'.substr($expression, 8);
            }

            // add prefix before absolute element selector
            if ('' === $expression) {
                $expression = $nonMatchingExpression;
            } elseif (0 === strpos($expression, '//')) {
                $expression = 'descendant-or-self::'.substr($expression, 2);
            } elseif (0 === strpos($expression, './/')) {
                $expression = 'descendant-or-self::'.substr($expression, 3);
            } elseif (0 === strpos($expression, './')) {
                $expression = 'self::'.substr($expression, 2);
            } elseif (0 === strpos($expression, 'child::')) {
                $expression = 'self::'.substr($expression, 7);
            } elseif ('/' === $expression[0] || '.' === $expression[0] || 0 === strpos($expression, 'self::')) {
                $expression = $nonMatchingExpression;
            } elseif (0 === strpos($expression, 'descendant::')) {
                $expression = 'descendant-or-self::'.substr($expression, 12);
            } elseif (preg_match('/^(ancestor|ancestor-or-self|attribute|following|following-sibling|namespace|parent|preceding|preceding-sibling)::/', $expression)) {
                // the fake root has no parent, preceding or following nodes and also no attributes (even no namespace attributes)
                $expression = $nonMatchingExpression;
            } elseif (0 !== strpos($expression, 'descendant-or-self::')) {
                $expression = 'self::'.$expression;
            }
            $expressions[] = $parenthesis.$expression;

            if ($i === $xpathLen) {
                return implode(' | ', $expressions);
            }

            $i += strspn($xpath, " \t\n\r\0\x0B", $i + 1);
            $startPosition = $i + 1;
        }

        return $xpath; // The XPath expression is invalid
    }
1227428
public function dontSeeXmlResponseMatchesXpath($xpath)
    {
        $structure = new XmlStructure($this->connectionModule->_getResponseContent());
        $this->assertFalse($structure->matchesXpath($xpath), 'accidentally matched xpath');
    }
760755
private function mapAllInlineStylesToHtmlAttributes(\DOMXPath $xPath)
    {
        /** @var \DOMElement $node */
        foreach ($this->getAllNodesWithStyleAttribute($xPath) as $node) {
            $inlineStyleDeclarations = $this->parseCssDeclarationsBlock($node->getAttribute('style'));
            $this->mapCssToHtmlAttributes($inlineStyleDeclarations, $node);
        }
    }
316843
static function xpathQuery($html, $xpath) {
		$ddoc = new \DOMDocument();
		@$ddoc->loadHTML($html);
	
		$dxpath = new \DOMXPath($ddoc);
		return $dxpath->query($xpath);
	}
442267
protected function _deserializeDateTimeExtractionPaths(DOMXPath $xpath)
	{
		foreach ($this->_dateTimeExtractionPaths as $setter => $path) {
			$value = $xpath->evaluate($path);
			if ($value) {
				$this->$setter(new DateTime($value));
			}
		}
		return $this;
	}
1361310
private function loadParam(\DOMXPath $xpath, \DOMNode $node)
    {
        $result = [
            'name' => $this->getValueFromXPath('@name', $xpath, $node),
            'type' => $this->getValueFromXPath('@type', $xpath, $node, 'string'),
            'meta' => $this->loadMeta($xpath, $node),
        ];

        switch ($result['type']) {
            case 'collection':
                $result['value'] = $this->loadParams('x:param', $xpath, $node);
                break;
            default:
                $result['value'] = $this->getValueFromXPath('@value', $xpath, $node);
                break;
        }

        return $result;
    }
1138862
public function prepend($xpath, $prefix)
    {
        $expressions = array();

        // If the xpath prefix contains a union we need to wrap it in parentheses.
        if (preg_match(self::UNION_PATTERN, $prefix)) {
            $prefix = '('.$prefix.')';
        }

        // Split any unions into individual expressions.
        foreach ($this->splitUnionParts($xpath) as $expression) {
            $expression = trim($expression);
            $parenthesis = '';

            // If the union is inside some braces, we need to preserve the opening braces and apply
            // the prefix only inside it.
            if (preg_match('/^[\(\s*]+/', $expression, $matches)) {
                $parenthesis = $matches[0];
                $expression = substr($expression, strlen($parenthesis));
            }

            // add prefix before element selector
            if (0 === strpos($expression, '/')) {
                $expression = $prefix.$expression;
            } else {
                $expression = $prefix.'/'.$expression;
            }
            $expressions[] = $parenthesis.$expression;
        }

        return implode(' | ', $expressions);
    }