2010-09-28 6 views
1

Je suis nouveau sur Nokogiri et XPath, et j'essaie d'accéder à tous les commentaires dans un fragment HTML ou XML. Les XPaths .//comment() et //comment() fonctionnent lorsque je n'utilise pas la fonction fragment, mais ils ne trouvent rien avec un fragment. Avec une balise au lieu d'un commentaire, cela fonctionne avec le premier XPath. Par essais et erreurs, j'ai réalisé que dans ce cas comment() trouve seulement les commentaires de niveau supérieur et .//comment() et d'autres ne trouvent que des commentaires internes. Est-ce que je fais quelque chose de mal? Qu'est-ce que je rate? Quelqu'un peut-il expliquer ce qui se passe?Utilisation de XPath avec un fragment HTML ou XML?

Quelle XPath dois-je utiliser pour obtenir tous les commentaires dans un fragment HTML analysé par Nokogiri?

Cet exemple peut aider à comprendre le problème:

str = "<!-- one --><p><!-- two --></p>" 

# this works: 
Nokogiri::HTML(str).xpath("//comment()") 
=> [#<Nokogiri::XML::Comment:0x3f8535d71d5c " one ">, #<Nokogiri::XML::Comment:0x3f8535d71cf8 " two ">] 
Nokogiri::HTML(str).xpath(".//comment()") 
=> [#<Nokogiri::XML::Comment:0x3f8535cc7974 " one ">, #<Nokogiri::XML::Comment:0x3f8535cc7884 " two ">] 

# with fragment, it does not work: 
Nokogiri::HTML.fragment(str).xpath("//comment()") 
=> [] 
Nokogiri::HTML.fragment(str).xpath("comment()") 
=> [#<Nokogiri::XML::Comment:0x3f8535d681a8 " one ">] 
Nokogiri::HTML.fragment(str).xpath(".//comment()") 
=> [#<Nokogiri::XML::Comment:0x3f8535d624d8 " two ">] 
Nokogiri::HTML.fragment(str).xpath("*//comment()") 
=> [#<Nokogiri::XML::Comment:0x3f8535d5cb8c " two ">] 
Nokogiri::HTML.fragment(str).xpath("*/comment()") 
=> [#<Nokogiri::XML::Comment:0x3f8535d4e104 " two ">] 

# however it does if it is a tag instead of a comment: 
str = "<a desc='one'/> <p><a>two</a><a desc='three'/></p>" 
Nokogiri::HTML.fragment(str).xpath(".//a") 
=> [#<Nokogiri::XML::Element:0x3f8535cb44c8 name="a" attributes=[#<Nokogiri::XML::Attr:0x3f8535cb4194 name="desc" value="one">]>, #<Nokogiri::XML::Element:0x3f8535cb4220 name="a" children=[#<Nokogiri::XML::Text:0x3f8535cb3ba4 "two">]>, #<Nokogiri::XML::Element:0x3f8535cb3a3c name="a" attributes=[#<Nokogiri::XML::Attr:0x3f8535cb3960 name="desc" value="three">]>] 

PS: Sans fragment il fait ce que je veux, mais il ajoute aussi des trucs comme « DOCTYPE » et j'ai vraiment seulement un fragment de HTML fichier que je suis en train d'éditer (en supprimant certaines balises, en en remplaçant d'autres). Fonctionne bien dans tous les cas, mais je ne comprends toujours pas ces différences.

Répondre

7

//comment() est une forme courte de /descendant-or-self::node()/child::comment()

utilisant ce XPath avec un fragment ne tient pas compte des commentaires de la racine (ils sont sélectionnés par /descendant-or-self::node() mais ils n'ont pas les enfants). Si vous utilisez HTML(str), vous créez un nœud de document en tant que racine de tous les autres éléments. Par conséquent, /descendant-or-self::node()/child::comment() n'ignore pas les commentaires de niveau supérieur, car ils sont les enfants du nœud de document (lui-même sélectionné par /descendant-or-self::node()).

Je ne sais pas pourquoi descendant::comment() fonctionne dans tous les cas, je dirais que cela devrait être descendant-or-self::comment(), mais peu importe.

espérons que cela aide?

+1

Oui, cela aide! Je vous remercie! Je ne comprends pas très bien ce que serait 'self' (le nœud de contexte). 'descendant-or-self' est le même que 'descendant' mais inclut également le noeud contextuel. J'ai essayé avec seulement un commentaire dans la chaîne ('str = ''') et même dans ce cas c'est un descendant et juste 'descendant :: comment()' fonctionne. – dbarbosa

Questions connexes