Производительность XPath с объединенными Nokogiri::XML::NodeSets?

Я получаю данные от веб-службы, 100 <row> на страницу. Мой скрипт соединяет эти страницы с Nokogiri::XML::Nodeset. Поиск набора узлов через XPath выполняется очень медленно.

Этот код заменяет вызов веб-службы и синтаксический анализ XML, но симптом тот же:

rows = []
(1..500).to_a.each_slice(100) { |slice|
  rows << Nokogiri::XML::Builder.new { |xml|
    xml.root {
      xml.rows {
        slice.each { |num|
          xml.row {
            xml.NUMBER {
              xml.text num
            }
          }
        }
      }
    }
  }.doc.at('/root/rows')
}

rows = rows.map { |a| a.children }.inject(:+)

Результирующий NodeSet содержит узлы из пяти документов. Это кажется проблемой:

rows.map { |r| r.document.object_id }.uniq
  => [21430080, 21732480, 21901100, 38743080, 40472240]

Проблема. Следующий код выполняется примерно за десять секунд. С неслитным набором узлов это делается в мгновение ока:

(1..500).to_a.sample(100).each do |sample|
  rows.at('//row[./NUMBER="%d"]' % sample)
end

Есть ли у кого-нибудь решение, как лучше объединить наборы узлов или объединить документы?

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


person krissi    schedule 19.03.2013    source источник
comment
Почему вы пытаетесь собрать набор узлов? Почему бы просто не собрать необходимые данные?   -  person Mark Thomas    schedule 19.03.2013
comment
Часть сбора и сборки данных выполняется классом интерфейса веб-сервиса (построитель должен продемонстрировать поведение). Этот метод возвращает NodeSet. Код xpath запускается кодом, использующим этот класс. Было бы неплохо, если бы мне не пришлось менять интерфейс методов класса.   -  person krissi    schedule 20.03.2013
comment
Nokogiri работает очень быстро и основан на стандартном синтаксическом анализаторе XML. Вы не дали нам пример XML, который вы анализируете, или наборов узлов, которые вы добавляете вместе, и для меня попытка сравнить скорость синтаксического анализа и сборки на самом деле недействительна - вы сравниваете яблоки с апельсины. Как таковой, ваш вопрос не имеет большого смысла для меня.   -  person the Tin Man    schedule 21.03.2013
comment
Вопрос не в сборке, а просто в примере генерации набора узлов. Речь идет о запросе xpath. Я добавил отметку, чтобы уточнить. Похоже, что пример — сброс ядра в некоторых средах. В настоящее время я пытаюсь изолировать код проблемы   -  person krissi    schedule 21.03.2013


Ответы (1)


Ключом к объединению наборов узлов является отсоединение узлов с помощью Node#remove и добавление их к другому набору узлов:

nodeset = nil
rows.each do |slice|
  if nodeset.nil?
    nodeset = slice
  else
    slice.children.each do |row|
      nodeset.add_child(row.remove)
    end
  end
end
person krissi    schedule 27.03.2013