Разбор большого файла xml [дубликат]

Связанный .lib-файл связан с .dll

У меня была такая же проблема. Скажем, у меня есть проекты MyProject и TestProject. Я эффективно связал файл lib для MyProject с TestProject. Однако этот файл lib был создан, так как была построена DLL для MyProject. Кроме того, я не содержал исходный код для всех методов в MyProject, но только доступ к точкам входа DLL.

Чтобы решить проблему, я построил MyProject как LIB и связал TestProject с этим .lib-файлом (скопируйте вложенный файл .lib в папку TestProject). Затем я смогу снова создать MyProject как DLL. Он компилируется, поскольку lib, с которым связан TestProject, содержит код для всех методов в классах MyProject.

1
задан Night Train 8 November 2013 в 20:37
поделиться

4 ответа

Я вижу несколько возможных проблем. Прежде всего, это:

@doc = Nokogiri::XML(sympFile)

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

Затем вы делаете такие вещи:

@doc.xpath(...).each

Это может быть недостаточно умным для создания перечислителя, который просто поддерживает указатель на внутреннюю форму XML, он может создавать копию всего, когда это создает NodeSet, который возвращает xpath. Это даст вам еще одну копию большей части расширенной версии XML. Я не уверен, сколько копий и построений массивов происходит здесь, но есть место для справедливого разряда памяти и процессора, даже если он не копирует дубликаты всего.

Затем вы делаете свою копию того, что вас интересует:

symptomsList.push([signId, name])

и, наконец, итерация по этому массиву:

symptomsList.each do |x|
    Symptom.where(:name => x[1], :signid => Integer(x[0])).first_or_create
end

Я обнаружил, что анализаторы SAX работают лучше с большими данными но они более громоздки для работы. Вы можете попытаться создать свой собственный парсер SAX примерно так:

class D < Nokogiri::XML::SAX::Document
  def start_element(name, attrs = [ ])
    if(name == 'DisorderSign')
      @data = { }
    elsif(name == 'ClinicalSign')
      @key        = :sign
      @data[@key] = ''
    elsif(name == 'SignFreq')
      @key        = :freq
      @data[@key] = ''
    elsif(name == 'Name')
      @in_name = true
    end
  end

  def characters(str)
    @data[@key] += str if(@key && @in_name)
  end

  def end_element(name, attrs = [ ])
    if(name == 'DisorderSign')
      # Dump @data into the database here.
      @data = nil
    elsif(name == 'ClinicalSign')
      @key = nil
    elsif(name == 'SignFreq')
      @key = nil
    elsif(name == 'Name')
      @in_name = false
    end
  end
end

Структура должна быть довольно четкой: вы наблюдаете за открытием интересующих вас элементов и выполняете набор бухгалтерии когда делаете, затем кешируйте строки, если вы находитесь внутри элемента, который вас интересует, и, наконец, очистите и обработайте данные по мере закрытия элементов. Вы работаете с базой данных, замените комментарий

# Dump @data into the database here.

.

Эта структура упрощает просмотр элементов <Disorder id="17601">, чтобы вы могли отслеживать, насколько далеко вы ушли. Таким образом, вы можете остановить и перезапустить импорт с небольшими изменениями в вашем скрипте.

4
ответ дан mu is too short 24 August 2018 в 23:26
поделиться

Вероятно, у вас не хватает памяти, потому что symptomsList становится слишком большим в размере памяти. Почему бы не выполнить SQL в цикле xpath?

require 'nokogiri'

sympFile = File.open("Temp.xml")
@doc = Nokogiri::XML(sympFile)
sympFile.close()

@doc.xpath("////DisorderSign").each do |x|
  signId = x.at('ClinicalSign').attribute('id').text()      
  name = x.at('ClinicalSign').element_children().text()
  Symptom.where(:name => name, :signid => signId.to_i).first_or_create
end

Возможно также, что файл слишком велик для обработки буфера. В этом случае вы можете нарезать его на более мелкие временные файлы и обрабатывать их по отдельности.

2
ответ дан CDub 24 August 2018 в 23:26
поделиться

Вы также можете использовать Nokogiri::XML::Reader. Это более интенсивный объем памяти, чем Nokogiri::XML::SAX парсер, но вы можете сохранить структуру XML, e.x.

class NodeHandler < Struct.new(:node)
  def process
    # Node processing logic
    #e.x.
    signId = node.at('ClinicalSign').attribute('id').text()      
    name = node.at('ClinicalSign').element_children().text()

  end
end


Nokogiri::XML::Reader(File.open('./test/fixtures/example.xml')).each do |node|
  if node.name == 'DisorderSign' && node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
    NodeHandler.new(
        Nokogiri::XML(node.outer_xml).at('./DisorderSign')
    ).process
  end
end

На основании этого blog

0
ответ дан eldi 24 August 2018 в 23:26
поделиться

SAX Parser определенно то, что вы хотите использовать. Если вы что-то вроде меня и не можете дживить с документацией Nokogiri, есть удивительный камень, названный Saxerator , который делает этот процесс очень легким.

Пример того, что вы пытаются сделать -

require 'saxerator'

parser = Saxerator.parser(Temp.xml)


parser.for_tag(:DisorderSign).each do |sign|
  signId = sign[:ClinicalSign][:id]
  name = sign[:ClinicalSign][:name]
  Symtom(:name => name, :id => signId).create!
end
3
ответ дан Noah Davis 24 August 2018 в 23:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: