Wyciąganie danych z xml - nokogiri

Hej

Mam plik xml w formacie:

<?xml version="1.0" encoding="UTF-8"?>
<teryt>
<catalog name="ULIC" type="all">
<row>
<col name="SYM_UL">18316</col>
<col name="CECHA">ul.</col>
<col name="NAZWA_1">Radomska</col>
</row>
<row>
<col name="SYM_UL">19002</col>
<col name="CECHA">ul.</col>
<col name="NAZWA_1">Różanostocka</col>
<col name="NAZWA_2"/>
</row>

itd.Jest to plik z bazy TERYT - dla danej miejscowości. Potrzebuję wyciągnąć z niego symbol ulicy mając jej nazwę. Chcę to zrobic elegandzko. Ale moja wiedza z nokogiri kończy się na
content.xpath(’//row’).each do |row|
i tu mam oddzielnie każdy

Mogę to zrobić ręcznie, ale myślę, że da się po prostu jakoś to zrobić tym gemem.

Nokogiri::XML(xml).at('row:has(col[name="NAZWA_1"][text()="Radomska"]) col[name="SYM_UL"]').text

Piękne. Dziękuję.

Można się bawić nokogiri, czasami jest to bardziej użyteczne niż inne rozwiązania. W twoim rozwiązaniu, może multi_xml by się nadało.

Dołożę swoje pytanie do tego tematu - powyższy kod jak i zaproponowany dalej wymaga jakiejś zmiennej gdzie będzie załadowany cały plik xml. Czasem jest on wielki, więc zdarzyło mi się już, że brakło pamięci.

Co zrobić by xml był odczytywany po jednym tagu “row”?

W samym nokogiri możesz użyć albo pełnego sax parsera
http://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/SAX/Parser

albo dużo lżejszego readera
http://www.rubydoc.info/github/sparklemotion/nokogiri/Nokogiri/XML/Reader

Tej drugiej opcji używałem, iterujesz po każdym tagu (przy czym dostajesz i otwierający i zamykający) i jest to dość proste i szybkie.

Niestety też “dotknął” mnie TERYT.
Chcę pliki - na początek TERC.xml - załadować do bazy. Napisałem taki fragment:

require 'nokogiri'

file = File.open(File.join("db/seeds/files", "TERC.xml"))
doc = Nokogiri::XML(file)
doc.xpath('//row').each do |row_element|
  puts row_element
  puts row_element.text
end

i dostaję dla poszczególnych wierszy coś takiego:

<row>
<col name="WOJ">32</col>
<col name="POW">63</col>
<col name="GMI">01</col>
<col name="RODZ">1</col>
<col name="NAZWA">Świnoujście</col>
<col name="NAZDOD">gmina miejska</col>
<col name="STAN_NA">2016-01-01</col>
</row>

32
63
01
1
Świnoujście
gmina miejska
2016-01-01

Chciałbym do swojej bazy wprowadzać te wartości z tej pętli jakoś tak
MyTable.new()
MyTable.woj = …
MyTable.pow = …

MyTable.save

ale nie potrafię wybrać atrybutu z czegoś takiego "<col name="WOJ">32</col>" , gdyż za słabo znam Nokogiri, a przykłady tam zamieszczone przeważnie odnoszą się do takich wpisów <woj>32</woj>"
Ktoś może mi pomóc?

Ja potrzebowałem Do miejscowości zrobić spis nazw ulic z kodami ulic itp. Mam to zrobione tak:

City.all.each do |c|
      next unless File.exist?("ulic/ulic_#{c.name.gsub(/ /, '_')}.xml")
      file = File.open("ulic/ulic_#{c.name.gsub(/ /, '_')}.xml")
      content = Nokogiri::XML(file)
      content.search("row:has(col[name=\"NAZWA\"][text()=\"#{c.name}\"])").each do |t|
        name_1 = t.at("col[name=\"NAZWA_1\"]").text
        name_2 = t.at("col[name=\"NAZWA_2\"]").text
        property = t.at("col[name=\"CECHA\"]").text
        ulic = t.at("col[name=\"SYM_UL\"]").text
        
(...)

      end
    end

Gdzie jednym z miast była ‘Sokółka’ (City.name) a jeden row z pliku xml to:

<row>
<col name="WOJ">20</col>
<col name="NAZWA_WOJ">PODLASKIE</col>
<col name="POW">11</col>
<col name="NAZWA_POW">sokólski</col>
<col name="GMI">08</col>
<col name="NAZWA_GMN">Sokółka</col>
<col name="RODZ_GMN">4</col>
<col name="NAZWA_RODZ_GMN">miasto w gminie miejsko-wiejskiej</col>
<col name="NAZWA">Sokółka</col>
<col name="SYM">0923443</col>
<col name="SYMPOD">0923443</col>
<col name="KOD_RM">96</col>
<col name="NAZWA_RM">miasto                  </col>
<col name="SYM_UL">25107</col>
<col name="CECHA">ul.</col>
<col name="NAZWA_1">Wyszyńskiego</col>
<col name="NAZWA_2">kard. Stefana </col>
</row>

Myślę, że sobie poradzisz.

Dzięki :slight_smile: