Search code examples
phpxpathdomxpath

How do I select only the "top nodes" in this XPath query?


I'm using this XPath query to select elements that do not have input descendants in an Xhtml document:

//*[not(descendant-or-self::input | descendant-or-self::textarea | descendant-or-self::select | ancestor::select)]

With the following example XHtml document:

<html>
    <head>
        <title>Title</title>
    </head>
    <body>
        <div id="one">
            <input type="text" />
        </div>
        <div id="two">
            <textarea></textarea>
        </div>
        <div id="three">
            <div id="four">
                Text
            </div>
        </div>
        <div id="five">
            <select>
                <option>One</option>
                <option>Two</option>
            </select>
        </div>
        <div id="six">
            <input type="text" />
        </div>
        <div id="seven">
            <div id="eight"></div>
        </div>
    </body>
</html>

...And this PHP code:

// Populate $html and $query with above

$dom = new DOMDocument('1.0', 'UTF-8');
$dom->loadXML($html);

$xpath = new DOMXPath($dom);
$nodes = $xpath->query($query);

foreach($nodes as $node)
{
    echo $node->tagName;

    if($node->hasAttribute('id'))
        echo '#' . $node->getAttribute('id');

    echo ' ';
}

I get this: head title div#three div#four div#seven div#eight

But I want this instead: head div#three div#seven

I will be taking the results of the XPath query and removing the elements from DOMDocument. title div#four div#eight are children of head div#three div#seven, which are already in the result.

Keeping in mind this query will be used on any XHtml document, how would I change my XPath 1.0 query to get the desired results?


Solution

  • Just repeat the condition for the parent:

    [not(descendant-or-self::input | descendant-or-self::textarea | descendant-or-self::select | ancestor-or-self::select)
    and 
    (../descendant-or-self::input | ../descendant-or-self::textarea | ../descendant-or-self::select | ../ancestor-or-self::select)]