2012-02-14 3 views
1

Я использую этот запрос XPath для выбора элементов, которые не имеют входных потомков в документе Xhtml:Как выбрать только «верхние узлы» в этом запросе XPath?

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

следующим примером Xhtml документа:

<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> 

... И это PHP код:

// 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 ' '; 
} 

я получаю это: head title div#three div#four div#seven div#eight

Но я хочу это вместо: head div#three div#seven

Я буду брать результаты запроса XPath и удалять элементы из DOMDocument. title div#four div#eight являются дочерью пользователя head div#three div#seven, которые уже поступили в результат.

Помните, что этот запрос будет использоваться в любом документе XHtml, как бы изменить свой запрос XPath 1.0 для получения желаемых результатов?

ответ

1

Просто повторить условие для родителей:

[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)] 
+0

Это работает! Кажется, этого достаточно, чтобы повторное условие было 'и (../descendant::input | ../descendant::textarea | ../ descendant :: select)'. Часть 'ancestor-or-self :: select' первого условия гарантирует, что внутренняя часть' select' оставлена ​​в покое. Часть '../', если я правильно понимаю, выбирает «родитель корня», что именно то, что я хотел, спасибо :). Я также добавил резерв, чтобы выбрать корневой узел 'html', если нет элементов поля. – Luke

+0

Я обнаружил проблему с тем, что запрос не работает, когда атрибут 'xmlns' присутствовал в элементе' html'. По какой причине вы не можете просто просто '$ xpath-> registerNamespace (NULL, 'http://www.w3.org/1999/xhtml')' ... Поэтому вместо этого вы должны изменить 'NULL' на' 'html'' и do '$ query = str_replace (' :: ',' :: input: ', $ query)' когда присутствует xmlns. Вы можете использовать '$ xmlns = $ document-> lookupNamespaceURI (NULL)', чтобы узнать, присутствует ли он. Желание было лучше. Если есть, пожалуйста, дайте мне знать! – Luke

0

В этом случае, как представляется, будет достаточно, чтобы расширить свой текущий XPath дополнительно сказать, что не должно быть div или head в ancestor оси:

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

На образце XML, это возвращает только head и div s three и seven, по желанию.

+0

К сожалению, это не будет работать для каждого документа XHTML/html5. Это слишком специфично. Я могу указать только на поля формы. Есть тонны блоков/встроенных элементов, которые могут содержать поле формы, которое должно быть указано здесь. Отсутствие одного из них может привести к ошибке (попытка удалить тег, родитель которого уже удален). – Luke

Смежные вопросы