Search code examples
phpxmlxpathsimplexml

Comparing two strings in XPath lexicographically


I have an XML document with items book with attributes .id, for example .id 'bk100', 'bk102', 'bk105', 'bk112', 'bk130'. I want to create an xpath that will return only those items which satisfy this condition:

.id > 'bk104'

That should return items with the .id 'bk105', 'bk112', 'bk130'. I have this:

xpath("//book[@id>'bk112']");

But it doesn't seem to do the trick. Is there any modifier to make this happen, or do I have to implement this manually?


Solution

  • The compare function was added in XPath 2, which sadly isn't available.

    With the DOM extension you can register PHP functions for use in XPath expressions and strcmp does the trick there.


    Example:

    $xml = <<<'XML'
    <books>
        <book id="bk100"/>
        <book id="bk102"/>
        <book id="bk105"/>
        <book id="bk112"/>
        <book id="bk130"/>
    </books>
    XML;
    
    $dom = new DOMDocument();
    $dom->loadXML($xml);
    $xpath = new DOMXPath($dom);
    $xpath->registerPhpFunctions('strcmp');
    $xpath->registerNamespace("php", "http://php.net/xpath");
    
    foreach ($xpath->query("//book[php:functionString('strcmp', @id, 'bk104') > 0]") as $node) {
        echo $dom->saveXML($node), "\n";
    }
    

    Output:

    <book id="bk105"/>
    <book id="bk112"/>
    <book id="bk130"/>
    

    Otherwise you'll need to implement it manually.