triopsidae
@triopsidae

Как правильно распарсить XML в JSON?

День добрый, есть XML файл:
<profile>
    <profile_name>Profile 1</profile_name>
    <field>
        <name>role</name>
        <type>string</type>
        <value>user</value>
    </field>
    <field>
        <name>age</name>
        <type>int</type>
        <value>30</value>
    </field>
</profile>
<profile>
    <profile_name>Profile 2</profile_name>
    <field>
        <name>role</name>
        <type>string</type>
        <value>user</value>
    </field>
    <field>
        <name>age</name>
        <type>int</type>
        <value>30</value>
    </field>
</profile>
<profile>
    <profile_name>Profile 3</profile_name>
    <field>
        <name>role</name>
        <type>string</type>
        <value>admin</value>
    </field>
</profile>

Его нужно распарсить в файл формата JSON, что бы получился такой результат:
{
    "Profile 1": {
        "role": "user",
        "age": 30
    },
    "Profile 2": {
        "role": "user",
        "age": 30
    },
    "Profile 3": {
        "role": "admin"
    }
}

Вот фрагмент кода, который парсит данный XML файл:
type XMLProfile struct {
	XMLName     xml.Name    `xml:"profile,omitempty"`
	ProfileName string      `xml:"profile_name",omitempty`
	Fields      []*XMLField `xml:"field,omitempty"`
}

type XMLField struct {
	Name  string `xml:"name,omitempty"`
	Type  string `xml:"type,omitempty"`
	Value string `xml:"value,omitempty"`
}

func main() {
	file, err := os.Open("example.xml")
	if err != nil {
		log.Println(err)
	}

	defer file.Close()

	decoder := xml.NewDecoder(file)
	for {
		t, _ := decoder.Token()
		if t == nil {
			break
		}

		switch et := t.(type) {
		case xml.StartElement:
			if et.Name.Local == "profile" {
				var object XMLProfile
				decoder.DecodeElement(&object, &et)

				resultData := map[string]map[string]string{
					object.ProfileName: map[string]string{},
				}

				for _, val := range object.Fields {
					resultData[object.ProfileName][val.Name] = val.Value
				}
				if out, err := json.MarshalIndent(resultData, "", " "); err != nil {
					panic(err)
				} else {
					_ = ioutil.WriteFile("test.json", out, 0644)
				}
			}
		}
	}
}

И результат:
{
 "Profile 3": {
  "role": "admin"
 }
}

Как правильно распарсить данный XML в JSON, что бы вышел правильный результат?
  • Вопрос задан
  • 722 просмотра
Пригласить эксперта
Ответы на вопрос 3
@Sinu5oid
Хоть и некропост, но я всё же дам ответ
В описании типа есть опечатка
type XMLProfile struct {
  XMLName     xml.Name    `xml:"profile,omitempty"`
  ProfileName string      `xml:"profile_name",omitempty`
  Fields      []*XMLField `xml:"field,omitempty"`
}

Конкретно здесь: `xml:"profile_name",omitempty`
Go не позволяет ошибаться в мета-информации структур, вот правильный вариант:
`xml:"profile_name,omitempty"` - сначала бэктик, затем без пробелов: метка типа данных (xml), двоеточие, кавычки, имя в xml, запятая, дополнительные теги, кавычки (если нужно задать описание и для json - ставим пробел, повторяем всё то же самое), в завершении снова бэктик

Вот и весь фикс :)
Финальный код:
package main

import (
	"encoding/json"
	"encoding/xml"
	"io/ioutil"
	"log"
	"os"
)

type XMLProfile struct {
	XMLName     xml.Name    `xml:"profile,omitempty"`
	ProfileName string      `xml:"profile_name,omitempty"`
	Fields      []*XMLField `xml:"field,omitempty"`
}

type XMLField struct {
	Name  string `xml:"name,omitempty"`
	Type  string `xml:"type,omitempty"`
	Value string `xml:"value,omitempty"`
}

func main() {
	file, err := os.Open("example.xml")
	if err != nil {
		log.Println(err)
	}

	defer file.Close()

	decoder := xml.NewDecoder(file)
	for {
		t, _ := decoder.Token()
		if t == nil {
			break
		}

		switch et := t.(type) {
		case xml.StartElement:
			if et.Name.Local == "profile" {
				var object XMLProfile
				decoder.DecodeElement(&object, &et)

				resultData := map[string]map[string]string{
					object.ProfileName: map[string]string{},
				}

				for _, val := range object.Fields {
					resultData[object.ProfileName][val.Name] = val.Value
				}
				if out, err := json.MarshalIndent(resultData, "", " "); err != nil {
					panic(err)
				} else {
					_ = ioutil.WriteFile("test.json", out, 0644)
				}
			}
		}
	}
}
Ответ написан
NoSure
@NoSure
Hindu master coder
Заинтриговал...
www.cihanozhan.com/converting-xml-data-to-json-wit...
или
Как распарсить XML в Go?
немного допилить и будет самое то
Ответ написан
Комментировать
profesor08
@profesor08
Как-то так: https://profesor08.github.io/XmlJson/
Единственно надо для себя решить, как будешь обозначать атрибуты.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

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