LINUX.ORG.RU

Оптимизация скрипта парсера xml на Golang

 , ,


1

3

Доброго дня! Я недавно в Golang, поэтому прошу не бить сразу ногами. Я хочу распарсить XML файл, и получить набор данных для последующей записи в БД. Есть XML с примерной структурой:

<?xml version="1.0" encoding="UTF-8" ?> 
<countries>
 <country>
  <code>CH</code>
  <name>Schweiz</name>
  <regions>
   <region>
    <code>10</code>
    <name>Mittelland</name>
    <subregions>
     <subregion>
      <code>11</code>
      <name>Blah blah</name>

Код, который наговнокодил для разбора:

package main

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
)

type Destination struct {
	CountryCode   string   `xml:"code"`
	CountryName   string   `xml:"name"`
	RegionCode    []int    `xml:"regions>region>code"`
	RegionName    []string `xml:"regions>region>name"`
	SubregionCode []int    `xml:"regions>region>subregions>subregion>code"`
	SubregionName []string `xml:"regions>region>subregions>subregion>name"`
}

type Destinations struct {
	Destinations []Destination `xml:"country"`
}

func main() {

	d := Destinations{}

	data, _ := ioutil.ReadFile("xml/countryregion.xml")

	err := xml.Unmarshal(data, &d)
	if err != nil {
		fmt.Printf("error: ", err)
		return
	}

	for i, e := range d.Destinations {
		fmt.Printf("Country: %s - %s\n", e.CountryCode, e.CountryName)

		for ri, r := range d.Destinations[i].RegionCode {
			fmt.Printf("Region: %d - %s\n", r, d.Destinations[i].RegionName[ri])

		}
		if len(d.Destinations[i].SubregionCode) != 0 {
			for sri, sr := range d.Destinations[i].SubregionCode {
				fmt.Printf("SubRegion: %d - %s, Parent region?  \n", sr, d.Destinations[i].SubregionName[sri])

			}

		}

	}

}

Всё хорошо, но как получить код региона, для подрегиона?
В итоге, хочу получить что-то подобное.
Если это регион (не подрегион):
[Код страны][Номер региона][Имя региона][Номер региона]


Если это подрегион:
[Код страны][Номер подрегиона][Имя подрегиона][Номер родительского региона]

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



Последнее исправление: CYB3R (всего исправлений: 1)

У меня получилось вот так:

fmt.Printf("SubRegion: %d - %s, Parent region? %s \n", sr, d.Destinations[i].SubregionName[sri], d.Destinations[i].RegionName[sri])
На моем примере всё вывелось правильно.

Weres ★★★
()
Ответ на: комментарий от Jomaster

Спасибо. Да, что-то не так. Надо будет повнимательнее посмотреть.

Weres ★★★
()
Ответ на: комментарий от Jomaster

Таки живое, вот и шевелиться.

Язык без генериков — безделушка.

anonymous
()

Если я правильно понял твою проблему, надо просто парсить каждый элемент в отдельную структуру и получить правильное дерево:

package main

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
)

type Destination struct {
	CountryCode string    `xml:"code"`
	CountryName string    `xml:"name"`
	Regions     []*Region `xml:"regions>region"`
}

type Region struct {
	Code       int          `xml:"code"`
	Name       string       `xml:"name"`
	Subregions []*Subregion `xml:"subregions>subregion"`
}

type Subregion struct {
	Code int    `xml:"code"`
	Name string `xml:"name"`
}

type Destinations struct {
	Destinations []Destination `xml:"country"`
}

func main() {
	d := Destinations{}

	data, _ := ioutil.ReadFile("xml/countryregion.xml")

	err := xml.Unmarshal(data, &d)
	if err != nil {
		fmt.Printf("error: ", err)
		return
	}

	for _, e := range d.Destinations {
		fmt.Printf("Country: %s - %s\n", e.CountryCode, e.CountryName)
		for _, r := range e.Regions {
			fmt.Printf("Region: %d - %s\n", r.Code, r.Name)
			for _, subr := range r.Subregions {
				//Если len(r.Subregions) == 0, то и так ничего не будет
				fmt.Printf("\tSubregion of %s: %d - %s\n", r.Name, subr.Code, subr.Name)
			}
		}
	}
}

Вывод:

$ go run regions.go
Country: CH - Schweiz
Region: 10 - Mittelland
	Subregion of Mittelland: 11 - Blah blah

proud_anon ★★★★★
()
Ответ на: комментарий от proud_anon

Да, то что надо! Спасибо!

Надо было не экономить на структурах =)

Jomaster
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.