Question

I made a script using phpQuery. The script finds td's that contain a certain string:

$match = $dom->find('td:contains("'.$clubname.'")');

It worked good until now. Because one clubname is for example Austria Lustenau and the second club is Lustenau. It will select both clubs, but it only should select Lustenau (the second result), so I need to find a td containing an exact match.

I know that phpQuery are using jQuery selectors, but not all. Is there a way to find an exact match using phpQuery?

Was it helpful?

Solution

Update: It is possible, see the answer from @ pguardiario


Original answer. (at least an alternative):

No, unfortunately it is not possible with phpQuery. But it can be done easily with XPath.

Imagine you have to following HTML:

$html = <<<EOF
<html>
  <head><title>test</title></head>
  <body>
    <table>
      <tr>
        <td>Hello</td>
        <td>Hello World</td>
      </tr>
    </table>
  </body>
</html>
EOF;

Use the following code to find exact matches with DOMXPath:

// create empty document 
$document = new DOMDocument();

// load html
$document->loadHTML($html);

// create xpath selector
$selector = new DOMXPath($document);

// selects all td node which's content is 'Hello'
$results = $selector->query('//td[text()="Hello"]');

// output the results 
foreach($results as $node) {
    $node->nodeValue . PHP_EOL;
}

However, if you really need a phpQuery solution, use something like this:

require_once 'phpQuery/phpQuery.php';

// the search string
$needle = 'Hello';

// create phpQuery document
$document = phpQuery::newDocument($html);

// get matches as you suggested
$matches = $document->find('td:contains("' . $needle . '")');

// empty array for final results
$results = array();

// iterate through matches and check if the search string
// is the same as the node value
foreach($matches as $node) {
    if($node->nodeValue === $needle) {
        // put to results
        $results []= $node;
    }
}

// output results
foreach($results as $result) {
    echo $node->nodeValue . '<br/>';
}

OTHER TIPS

It can be done with filter, but it's not pretty:

$dom->find('td')->filter(function($i, $node){return 'foo' == $node->nodeValue;});

But then, neither is switching back and forth between css and xpath

I've no experience of phpQuery but the jQuery would be something like this :

var clubname = 'whatever';
var $match = $("td").map(function(index, domElement) {
    return ($(domElement).text() === clubname) ? domElement : null;
});

The phpQuery documentation indicates that ->map() is available and that it accepts a callback function in the same way as in jQuery.

I'm sure you will be able to perform the translation into phpQuery.

Edit

Here's my attempt based on 5 minutes' reading - probably rubbish but here goes :

$match = $dom->find("td")->map(function($index, $domElement) {
    return (pq($domElement)->text() == $clubname) ? $domElement : null;
});

Edit 2

Here's a demo of the jQuery version.

If phpQuery does what it says in its documentation, then (correctly translated from javascript) it should match the required element in the same way.

Edit 3

After some more reading about the phpQuery callback system, the following code stands a better chance of workng :

function textFilter($i, $el, $text) {
    return (pq($el)->text() == $text) ? $el : null;
}};
$match = $dom->find("td")->map('textFilter', new CallbackParam, new CallbackParam, $clubname);

Note that ->map() is preferred over ->filter() as ->map() supports a simpler way to define pararameter "places" (see Example 2 in the referenced page).

I know this question is old, but I've written a function based on answer from hek2mgl

<?php

// phpQuery contains function

/**
* phpQuery contains method, this will be able to locate nodes
* relative to the NEEDLE
* @param string element_pattern
* @param string needle
* @return array
*/
function contains($element_pattern, $needle) {

    $needle = (string) $needle;
    $needle = trim($needle);

    $element_haystack_pattern = "{$element_pattern}:contains({$needle})";
    $element_haystack_pattern = (string) $element_haystack_pattern;

    $findResults = $this->find($element_haystack_pattern);

    $possibleResults = array();

    if($findResults && !empty($findResults)) {
        foreach($findResults as $nodeIndex => $node) {
            if($node->nodeValue !== $needle) {
                continue;
            }
            $possibleResults[$nodeIndex] = $node;
        }
    }

    return $possibleResults;

}

?>

Usage

<?php

$nodes = $document->contains("td.myClass", $clubname);

?>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top