Using regex to filter attributes in xpath with php
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.
Solution 1:
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.
Solution 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"
)