Why do I get “undefined method `von=' for nil:

2019-08-01 02:04发布

问题:

I wrote this little program:

require 'open-uri'
require 'nokogiri'

class Kapitel
  attr_accessor :von, :bis, :bezeichnung
end

class SubKapitel
  attr_accessor :von, :bis, :bezeichnung
end

def parse_file 
  doc = Nokogiri::XML(File.open("test.xml"))
  parse_xml(doc)
end

def parse_xml(doc)
  doc.root.elements.each do |node|
    parse_kapitel(node)
  end
end

def parse_kapitel(node)
  if node.node_name.eql? 'nummer'
    tmp_kapitel = Kapitel.new 
  end
  if node.node_name.eql? 'gruppe'
    tmp_kapitel = SubKapitel.new
  end
  tmp_kapitel.von = node['V'] if node.node_name.eql? 'von_icd_code'
  tmp_kapitel.bis = node['V'] if node.node_name.eql? 'bis_icd_code'
end

puts parse_file

Using that, I parse this XML file:

 <kapitel>
      <nummer V="1"/>
      <von_icd_code V="A00"/>
      <bis_icd_code V="B99"/>
      <bezeichnung V="Bestimmte infektiöse und parasitäre Krankheiten"/>
      <gruppen_liste>
        <gruppe>
          <von_icd_code V="A00"/>
          <bis_icd_code V="A09"/>
          <bezeichnung V="Infektiöse Darmkrankheiten"/>
          <diagnosen_liste>
            <diagnose>
              <icd_code V="A00.-"/>
              <bezeichnung V="Cholera"/>
              <abrechenbar V="n"/>

But somehow I get this error:

 test.rb:32:in `parse_kapitel': undefined method `von=' for nil:NilClass(NoMethodError)

I think the problem is that von-icd-code appears twice in the XML document.

Can somebody help me to solve this problem?

回答1:

require 'nokogiri'
doc = Nokogiri::XML(' <kapitel>
      <nummer V="1"/>
      <von_icd_code V="A00"/>
      <bis_icd_code V="B99"/>
      <bezeichnung V="Bestimmte infektise und parasitre Krankheiten"/>FFC3\U+FFA4re Krankheiten"/>
      <gruppen_liste>
        <gruppe>
          <von_icd_code V="A00"/>
          <bis_icd_code V="A09"/>
          <bezeichnung V="Infektise Darmkrankheiten"/>krankheiten"/>
          <diagnosen_liste>
            <diagnose>
              <icd_code V="A00.-"/>
              <bezeichnung V="Cholera"/>
              <abrechenbar V="n"/>')

doc.errors

Which outputs:

[
    [0] #<Nokogiri::XML::SyntaxError: Premature end of data in tag diagnose line 12>,
    [1] #<Nokogiri::XML::SyntaxError: Premature end of data in tag diagnosen_liste line 11>,
    [2] #<Nokogiri::XML::SyntaxError: Premature end of data in tag gruppe line 7>,
    [3] #<Nokogiri::XML::SyntaxError: Premature end of data in tag gruppen_liste line 6>,
    [4] #<Nokogiri::XML::SyntaxError: Premature end of data in tag kapitel line 1>
]

If we look at what Nokogiri had to do to fix-up the XML:

puts doc.to_xml

We see that it added closing tags.

<?xml version="1.0"?>
<kapitel>
      <nummer V="1"/>
      <von_icd_code V="A00"/>
      <bis_icd_code V="B99"/>
      <bezeichnung V="Bestimmte infektise und parasitre Krankheiten"/>
      <gruppen_liste>
        <gruppe>
          <von_icd_code V="A00"/>
          <bis_icd_code V="A09"/>
          <bezeichnung V="Infektise Darmkrankheiten"/>
          <diagnosen_liste>
            <diagnose>
              <icd_code V="A00.-"/>
              <bezeichnung V="Cholera"/>
              <abrechenbar V="n"/></diagnose></diagnosen_liste></gruppe></gruppen_liste></kapitel>

It was able to do so correctly for this XML, but in XML that is malformed, or has more complicated data it might not do as well. And, at that point, any subsequent work on the resulting DOM would be suspect.



回答2:

Inside the method

def parse_kapitel(node)
   if node.node_name.eql? 'nummer'
   tmp_kapitel = Kapitel.new 
   end
   if node.node_name.eql? 'gruppe'
   tmp_kapitel = SubKapitel.new
   end
   tmp_kapitel.von = node['V'] if node.node_name.eql? 'von_icd_code'
   tmp_kapitel.bis = node['V'] if node.node_name.eql? 'bis_icd_code'
end

The error undefined method 'von=' for nil:NilClass(NoMethodError) means at that time node name is 'von_icd_code', not the 'nummer'. That's why the if node.node_name.eql? 'nummer' evaluated as false. But in Ruby local variables are created at parse time,whenever any such assignment statement encountered like, tmp_kapitel = Kapitel.new.Now due to flase evluation of the if node.node_name.eql? 'nummer',as I said earlier,tmp_kapitel local variable holds nil,not the object of Kapitel.new. And NilClass doesn't have any method called #von,so the legitimate error thrown to you.



标签: ruby nokogiri