2017-01-12 1 views
0

J'ai une structure HTML comme ceci:Comment supprimer un nœud à l'aide Nokogiri

<div> 
    This is 
    <p> very 
    <script> 
     some code 
    </script> 
    </p> 
    important. 
</div> 

Je sais comment obtenir un Nokogiri::XML::NodeSet de ceci:

dom.xpath("//div") 

Je veux maintenant filtrer les script tag:

dom.xpath("//script") 

Je peux donc obtenir quelque chose comme:

<div> 
    This is 
    <p> very</p> 
    important. 
</div> 

Alors que je peux appeler div.text pour obtenir:

"This is very important." 

J'ai essayé récursive/aller itérativement sur tous les nœuds enfants et essayer de faire correspondre chaque nœud que je veux filtrer un nœud Je ne veux pas , mais j'ai rencontré des problèmes comme trop d'espace ou pas assez d'espace. Je suis sûr qu'il y a une manière assez agréable et rubyesque.

Quel serait un bon moyen de le faire?

+0

S'il vous plaît lire "[demander]", y compris les pages liées, ainsi que "[mcve]". Nous devons voir le code minimum que vous avez écrit qui démontre le problème. Sans cela, on dirait que vous n'avez pas essayé.Si vous connaissez un NodeSet, alors vous devriez avoir vu ['unlink' AKA' remove'] (http://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/NodeSet#remove-instance_method) dans la documentation NodeSet. –

Répondre

0

1er problème

Pour supprimer tous les nœuds de script:

require 'nokogiri' 

html = "<div> 
    This is 
    <p> very 
    <script> 
     some code 
    </script> 
    </p> 
    important. 
</div>" 

doc = Nokogiri::HTML(html) 

doc.xpath("//script").remove 

p doc.text 
#=> "\n This is\n very\n \n \n important.\n" 

Merci à @theTinMan pour sa pointe (appelant remove sur un NodeSet au lieu de chaque nœud).

2ème problème

Pour supprimer les espaces blancs inutiles, vous pouvez utiliser:

  • strip pour supprimer les espaces (espaces blancs, des onglets, des sauts de ligne, ...) au début et à la fin de la chaîne
  • gsub pour remplacer mutiple espaces par un seul des espaces


p doc.text.strip.gsub(/[[:space:]]+/,' ') 
#=> "This is very important." 
+0

Réponse très claire, merci. Je vais y regarder. – Seims

+1

Vous pouvez utiliser 'remove' sur le NodeSet résultant sans itéter dessus avec' each' et le bloc. http://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/NodeSet#remove-instance_method –

0

NodeSet contient la méthode remove qui le rend facile à enlever tout correspondant à votre sélection:

require 'nokogiri' 

doc = Nokogiri::HTML(<<EOT) 
<html> 
    <body> 
    <div><p>foo</p><p>bar</p></div> 
    </body> 
</html> 
EOT 

doc.search('p').remove 
puts doc.to_html 

# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
# >> <html> 
# >> <body> 
# >>  <div></div> 
# >> </body> 
# >> </html> 

appliquée à votre entrée exemple:

require 'nokogiri' 

doc = Nokogiri::HTML(<<EOT) 
<div> 
    This is 
    <p> very 
    <script> 
     some code 
    </script> 
    </p> 
    important. 
</div> 
EOT 

doc.search('script').remove 
puts doc.to_html 

# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd"> 
# >> <html><body> 
# >> <div> 
# >> This is 
# >> <p> very 
# >>  
# >> </p> 
# >> important. 
# >> </div> 
# >> </body></html> 

À ce moment-là le texte dans le <div> est:

doc.at('div').text # => "\n This is\n very\n \n \n important.\n" 

normalisant qui est facile:

doc.at('div').text.gsub(/[\n ]+/,' ').strip # => "This is very important."