开发者

Can't assign value to Variable: undefined method `[]' for nil:NilClass (NoMethodError)

I am completely stumped on this one.

I have the following code:

puts block.at_xpath("*/img")["width"].to_i

but when I change it to

width = block.at_xpath("*/img")["width"].to_i

I get this error:

NokogiriTUT.rb:70:in `blockProcessor': undefined method `[]' for nil:NilClass (NoMethodError)

When I have the puts in there it returns the expected value.

Update:

        def blockProcessor(block)
    header = block.xpath('td[@class="default"]/*/span[@class="comhead"]')
    array = header.text.split
    if array[0] != nil #checks to make sure we aren't at the top of the parent list
        ### Date and Time ###
        if array[2] == 'hours' || array[2] == 'minutes'
            date = Time.now
        else
            days = (array[1].to_i * 24 * 60 * 60)
            date = Time.now - days
        end

        ##Get Comment##
        comment = block.at_xpath('*/span[@class="comment"]')

        hash = comment.text.hash
        #puts hash

        ##Manage Parent Here##

            width = block.at_xpath("*/img")["width"].to_i



            prevlevel = @parent_array[@parent_array.length-1][1]
            if width == 0 #has parents
                parentURL = header.xpath('a[@href][3]').to_s
                parentURL = parentURL[17..23]
                parentURL =  "http://news.ycombinator.com/item?id=#{parentURL}"
                parentdoc = Nokogiri::HTML(open(parentURL))
                a = parentdoc.at_xpath("//html/body/center/tabl开发者_开发技巧e/tr[3]/td/table/tr")
                nodeparent = blockProcessor(a) 
                @parent_array = []
                node = [hash, width, nodeparent] #id, level, parent
                @parent_array.push node     
            elsif width > prevlevel 
                nodeparent =  @parent_array[@parent_array.length-1][0]
                node = [hash, width, nodeparent]
                @parent_array.push node 
            elsif width == prevlevel
                nodeparent =  @parent_array[@parent_array.length-1][2]
                node = [hash, width, nodeparent]
                @parent_array.push node
            elsif width < prevlevel
                until prevlevel == w do
                    @parent_array.pop
                    prevlevel = @parent_array[@parent_array.length-1][1]
                end
                nodeparent = @parent_array[@parent_array.length-1][2]
                node = [hash, width, nodeparent]
                @parent_array.push node
            end
        puts "Author: #{array[0]} with hash #{hash} with parent: #{nodeparent}"

        ##Handles Any Parents of Existing Comments ##
        return hash
    end
end
   end

Here is the block that it is acting on.

 <tr>
    <td><img src="http://ycombinator.com/images/s.gif" height="1" width="0"></td>
    <td valign="top"><center>
    <a id="up_3004849" href="vote?for=3004849&amp;dir=up&amp;whence=%2f%78%3f%66%6e%69%64%3d%34%6b%56%68%71%6f%52%4d%38%44"><img src="http://ycombinator.com/images/grayarrow.gif" border="0" vspace="3" hspace="2"></a><span id="down_3004849"></span>
    </center></td>
    <td class="default">
    <div style="margin-top:2px; margin-bottom:-10px; "><span class="comhead"><a href="user?id=patio11">patio11</a> 12 days ago  | <a href="item?id=3004849">link</a> | <a href="item?id=3004793">parent</a> | on: <a href="item?id=3004471">Ask HN: What % of your job interviewees pass FizzB...</a></span></div>
    <br><span class="comment"><font color="#000000">Every time FizzBuzz problems come up among engineers, people race to solve them and post their answers, then compete to see who can write increasingly more nifty answers for a question which does not seek niftiness at all.<p>I'm all for intellectual gamesmanship, but these are our professional equivalent of a doctor being asked to identify the difference between blood and water.  You can do it.  <i>We know</i>.  Demonstrating that you can do it is not the point of the exercise.  We do it to have a cheap-to-administer test to exclude people-who-cannot-actually-program-despite-previous-job-titles from the expensive portions of the hiring process.</p></font></span><p><font size="1"><u><a href="reply?id=3004849&amp;whence=%2f%78%3f%66%6e%69%64%3d%34%6b%56%68%71%6f%52%4d%38%44">reply</a></u></font></p>
    </td>
</tr>


Your basic problem is that you don't understand XPath. (You are in good company there; XPath is quite confusing.) Your selectors simply don't match what you think they match. In particular, the one that blows up

*/img

should be

//img

or something like that.

Now, because the xpath selector doesn't match anything, the value of this Ruby statement

block.at_xpath("*/img")

is nil. And nil doesn't support [], so when you try to call ["width"] on it, Ruby complains with a undefined method [] for nil:NilClass error.

And as for why it only blows up when you assign it to a variable... yeah, that's not actually what's happening. You probably changed something else too.


And now, please allow me to make some other hopefully constructive code criticisms:

  • Your question was apparently designed to make it difficult to answer. In the future, please isolate the code in question, don't just paste in your whole homework assignment (or whatever this screen scraper is for).

  • It would be extra great if you made it into a single runnable Ruby file that we can execute verbatim on our computers, e.g.:

.

require "nokogiri"
doc = Nokogiri.parse <<-HTML
<tr>
  <td><img src="http://ycombinator.com/images/s.gif" height="1" width="0"></td>
  <td valign="top"><center>
    <a id="up_3004849" href="vote?for=3004849&amp;dir=up&amp;whence=%2f%78%3f%66%6e%69%64%3d%34%6b%56%68%71%6f%52%4d%38%44"><img src="http://ycombinator.com/images/grayarrow.gif" border="0" vspace="3" hspace="2"></a><span id="down_3004849"></span>
  </center></td>
  <td class="default">
    <div style="margin-top:2px; margin-bottom:-10px; ">
      <span class="comhead">
        <a href="user?id=patio11">patio11</a> 12 days ago  | <a href="item?id=3004849">link</a> | <a href="item?id=3004793">parent</a> | on: <a href="item?id=3004471">Ask HN: What % of your job interviewees pass FizzB...</a>
      </span>
    </div>
    <br><span class="comment"><font color="#000000">Every time FizzBuzz problems come up among engineers, people race to solve them and post their answers, then compete to see who can write increasingly more nifty answers for a question which does not seek niftiness at all.<p>I'm all for intellectual gamesmanship, but these are our professional equivalent of a doctor being asked to identify the difference between blood and water.  You can do it.  <i>We know</i>.  Demonstrating that you can do it is not the point of the exercise.  We do it to have a cheap-to-administer test to exclude people-who-cannot-actually-program-despite-previous-job-titles from the expensive portions of the hiring process.</p></font></span><p><font size="1"><u><a href="reply?id=3004849&amp;whence=%2f%78%3f%66%6e%69%64%3d%34%6b%56%68%71%6f%52%4d%38%44">reply</a></u></font></p>
  </td>
</tr>
HTML

width = doc.at_xpath("*/img")["width"].to_i

That way we can debug with our computers, not just with our minds.

  • You're writing Ruby now, not Java, so conform to Ruby's spacing and naming conventions: file names are snake_case, indentation is 2 spaces, no tabs, etc. It really is difficult to read code that's formatted wrong -- where "wrong" means "non-standard."

  • Everywhere you have one of those descriptive comments (### Date and Time ###) is an opportunity to extract a method (def date_and_time(array)) and make your code cleaner and easier to debug.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜