Nokogiri SAX игнорирует пустые символы - PullRequest
2 голосов
/ 24 июня 2019

Я пытаюсь проанализировать большой XML-файл с помощью синтаксического анализатора саксофона. Когда парсер достигает пустого узла, метод символов не запускается. Вот пример ...

require 'nokogiri'

class Parser < Nokogiri::XML::SAX::Document
  def initialize
    @count=1
  end
  def start_element(name, attrs = [])
    puts name
  end
  def characters(string)
    string.strip!
    puts "#{@count} #{string}"
    @count += 1
  end
  def end_element(name)
    puts name
  end
end

Nokogiri::XML::SAX::Parser.new(Parser.new).parse(File.open('sax_example3.xml'))

Вот пример XML-документа.

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <ISA type="array">
        <ISA>
            <I02>
                <name>Information1</name>
                <value>
                    <raw>00</raw>
                    <description></description>
                </value>
            </I02>
            <I02>
                <name>Information2</name>
                <value>
                    <raw></raw>
                    <description nil="true"/>
                </value>
            </I02>
        </ISA>
    </ISA>
</root>

Мне пришлось использовать sax, потому что файл имеет около 6.5 million lines.

Я пытаюсь собрать все значения name, а затем значения raw в отдельные массивы, и позже я могу сжать оба массива, чтобы получить пары ключ-значение.

Правильно ли я подхожу к этому? Есть ли другой способ сделать это?

Edit:

То, что я ожидал

array1 = ["Information1","Information2"]  
array2 = ["00", ""]  

Все значения name назначены массиву1, а значения raw массиву2, как показано выше.

Что я получаю

array1 = ["Information1","Information2"]  
array2 = ["00"]  

array2 не имеет того же количества элементов, что и array1, что означает, что невозможно сопоставить имена с массивом. Я думаю, что причина этого в том, что метод characters не вызывается, если узел пуст.

Вот вывод вышеприведенной программы (отредактировал вышеуказанный скрипт и добавил номера строк)

root           
1              
ISA            
2              
ISA            
3              
I02            
4              
name           
5 Information1 
name           
6              
value          
7              
raw            
8 00           
raw            
9              
description    
description    
10             
value          
11             
I02            
12             
I02            
13             
name           
14 Information2
name           
15             
value          
16             
raw            
raw            
17             
description    
description    
18             
value          
19             
I02            
20             
ISA            
21             
ISA            
22             
root       

Как видите, между строками (9 и 10), (16 и 17) и (17 и 18) выполняются методы start_element & end_element, а метод characters - нет.

1 Ответ

1 голос
/ 25 июня 2019

Поскольку characters может не вызываться, вам нужно вместо этого следить за самими элементами <name> и <raw>. Если мы можем предположить, что <name> и <raw> всегда идут парами и в этом порядке, мы можем создать новую «пустую» пару (например, { name: nil, raw: nil }) каждый раз, когда сталкиваемся с первым, а затем заполнить значения, когда (а если) characters называется:

class Parser < Nokogiri::XML::SAX::Document
  def initialize(*args)
    @vals = []
    @current_el = nil
    super
  end

  def start_element(el_name, attrs = [])
    if el_name == "name"
      @vals << { name: nil, raw: nil }
      @current_el = "name"
    elsif el_name == "raw"
      @current_el = "raw"
    else
      @current_el = nil
    end
  end

  def end_element(el_name)
    if el_name == "name" || el_name == "raw"
      @current_el = nil
    end
  end

  def characters(str)
    str = str.strip
    if @current_el == "name"
      @vals.last[:name] = str
    elsif @current_el == "raw"
      @vals.last[:raw] = str
    end
  end

  def end_document
    pp @vals
  end
end

Вы можете увидеть это в действии на repl.it (но будьте предупреждены, для запуска в первый раз требуется вечность, потому что Нокогири): https://repl.it/@jrunning/SpitefulRichLists

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...