2

I am trying to filter html tables with regex matching their id attribute. What am i doing wrong? Code i am trying to implement:

        $this->xpath = new DOMXPath($this->dom); 
            $this->xpath->registerNamespace("php", "http://php.net/xpath");
            $this->xpath->registerPHPFunctions();
        foreach($xpath->query("//table[php:function('preg_match', '/post\d+/', @id)]") as $key => $row)
    {

}

Error that i get: preg_match expects second param to be a string, array given.

2 Answers 2

2

An attribute is still a complex element according to DOM (has a namespace etc.). Use:

//table[php:function('preg_match', '/post\d+/', string(@id))]

Now, we need a boolean return, so:

function booleanPregMatch($match,$string){
    return preg_match($match,$string)>0;
}
$xpath->registerPHPFunctions();
foreach($xpath->query("//table[@id and php:function('booleanPregMatch', '/post\d+/', string(@id))]") as $key => $row){
     echo $row->ownerDocument->saveXML($row);
}

BTW: for more complex issues, you can of course sneakily check what's happening with this:

//table[php:function('var_dump',@id)]

It's a shame we don't have XPATH 2.0 functions available, but if you can handle this requirement with a more unreliable starts-with, I'd always prefer that over importing PHP functions.

Sign up to request clarification or add additional context in comments.

17 Comments

No errors, but the preg_match is not filtering.If i use this foreach($xpath->query("//table[@id]") as $key => $row) i get 16 tables, but the above query gives 68 tables!!
I did a print_r and got some domObject stuff. that seems to be taken care of with string(@id), but the preg_match is running true even when it should not!
Ah, you're right, a proper boolean is required. I'll edit it in.
@sam: calm down. See the function I put above there? Put it in.
@sam: compare against 1 = php:function('preg_match', ..., returns only those tables that preg_match the id.
|
2

What am i doing wrong?

The xpath expression @id (second parameter) returns an array but preg_match expects a string.

Convert it to string first: string(@id).

Next to that you need to actually compare the output to 1 as preg_match returns 1 when found:

foreach($xpath->query("//table[@id and 1 = php:function('preg_match', '/post\d+/', string(@id))]") as $key => $row)
{
    var_dump($key, $row, $row->ownerDocument->saveXml($row));
}

Explanation/What happens here?:

A xpath expression will by default return a node-list (more precisely node-set). If you map a PHP function onto such expressions these sets are represented in form of an array. You can easily tests that by using var_dump:

$xpath->query("php:function('var_dump', //table)");

array(1) {
  [0]=>
  object(DOMElement)#3 (0) {
  }
}

Same for the xpath expression @id in the context of each table element:

$xpath->query("//table[php:function('var_dump', @id)]");

array(1) {
  [0]=>
  object(DOMAttr)#3 (0) {
  }
}

You can change that into a string typed result by making use of the xpath string function:

A node-set is converted to a string by returning the string-value of the node in the node-set that is first in document order. If the node-set is empty, an empty string is returned.

$xpath->query("//table[php:function('var_dump', string(@id))]");

string(4) "test"

(the table has id="test")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.