2011-01-30 8 views
10

स्पष्ट रूप से Nokogiri की add_class विधि केवल NodeList s पर काम करती है, इस कोड को अमान्य बनाते हैं:नोकोगिरी के साथ एक तत्व में एक वर्ग जोड़ें

doc.search('a').each do |anchor| 
    anchor.inner_text = "hello!" 
    anchor.add_class("whatever") # WHOOPS! 
end 

इस कोड को काम करने के लिए मैं क्या कर सकता हूं? मुझे लगा कि यह

doc.search('a').each do |anchor| 
    anchor.inner_text = "hello!" 
    Nokogiri::XML::NodeSet.new(anchor).add_class("whatever") 
end 

जैसा कुछ होगा लेकिन यह या तो काम नहीं करता है। कृपया मुझे बताएं मुझे एकल नोड्स के लिए अपना खुद का add_class लागू करने की ज़रूरत नहीं है!

उत्तर

12

एक CSS वर्ग सिर्फ एक तत्व पर एक और विशेषता है:

doc.search('a').each do |anchor| 
    anchor.inner_text = "hello!" 
    anchor['class']="whatever" 
end 

सीएसएस वर्गों के बाद से, अंतरिक्ष-सीमांकित विशेषता में हैं यदि आप सुनिश्चित एक या अधिक वर्गों पहले से ही मौजूद हो सकता है अगर आप हूँ नहीं कर रहे हैं जैसे

anchor['class'] ||= "" 
anchor['class'] = anchor['class'] << " whatever" 

कुछ आप स्पष्ट रूप से करने के बजाय = का उपयोग कर बस परिवर्तनशील स्ट्रिंग विशेषता के लिए लौट आए विशेषता निर्धारित करने की आवश्यकता की जरूरत है। यह, उदाहरण के लिए, डोम नहीं बदलेगा:

anchor['class'] ||= "" 
anchor['class'] << " whatever" 

यहां तक ​​कि इसे और अधिक काम में परिणाम है किया जा रहा है, हालांकि, मैं शायद इसलिए की तरह ऐसा करने चाहते हैं:

class Nokogiri::XML::Node 
    def add_css_class(*classes) 
    existing = (self['class'] || "").split(/\s+/) 
    self['class'] = existing.concat(classes).uniq.join(" ") 
    end 
end 

आप नहीं चाहते हैं करने के लिए वर्ग बंदर-पैच, आप वैकल्पिक रूप से किए जा सकेंगे:

module ClassMutator 
    def add_css_class(*classes) 
    existing = (self['class'] || "").split(/\s+/) 
    self['class'] = existing.concat(classes).uniq.join(" ") 
    end 
end 

anchor.extend ClassMutator 
anchor.add_css_class "whatever" 

संपादित: आप देख सकते हैं कि यह मूल रूप से क्या Nokogiriके लिए आंतरिक रूप से करता हैविधि आप स्रोत देखने के लिए वर्ग पर क्लिक करके पाया:

# File lib/nokogiri/xml/node_set.rb, line 136 
def add_class name 
    each do |el| 
    next unless el.respond_to? :get_attribute 
    classes = el.get_attribute('class').to_s.split(" ") 
    el.set_attribute('class', classes.push(name).uniq.join(" ")) 
    end 
    self 
end 
+0

क्लासमुटर बड़ा! धन्यवाद! – flunder

1

Nokogiri के add_class, एक nodeset पर काम करता है, जैसे आप मिल गया। each ब्लॉक के अंदर कक्षा जोड़ने की कोशिश कर रहा है हालांकि, उस बिंदु पर आप एक व्यक्तिगत नोड पर काम कर रहे हैं।

बजाय:

require 'nokogiri' 

html = '<p>one</p><p>two</p>' 
doc = Nokogiri::HTML(html) 

doc.search('p').tap{ |ns| ns.add_class('boo') }.each do |n| 
    puts n.text 
end 
puts doc.to_html 

आउटपुट कौन सा:

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

tap विधि, रूबी 1.9+ में लागू, nodelist ही पहुँच देता है, की अनुमति देता है "बू" जोड़ने के लिए add_class विधि कक्षा <p> टैग्स।

+2

आप केवल 'doc.search (' p ') क्यों नहीं कर सकते हैं। Add_class (' बू ')। प्रत्येक करें ... ' –

+1

आप' doc = Nokogiri :: HTML.fragment (html)' का उपयोग कर सकते हैं यदि आप नोकोगिरी को डॉक्टरेट और अन्य एचटीएमएल और बॉडी टैग जोड़ने की इच्छा नहीं है – Archonic

संबंधित मुद्दे