Не удается получить значение XML-атрибута с помощью Go

Вопрос или проблема

Я пытаюсь разобрать метаданные EPUB с использованием языка программирования Go. XML, который я сейчас разбираю, очень простой:

<?xml version="1.0" encoding="UTF-8"?>
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
    <rootfiles>
        <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>
   </rootfiles>
</container>

Я хочу получить атрибуты full-path и media-type, и код на Go выглядит так:

package main                                                                                                                                                 

import (
    "fmt"
    "encoding/xml"
)

type RootFile struct {
    FullPath    string  `xml:"full-path,attr"`
    MediaType   string  `xml:"media-type,attr"`
}

func main() {
    xmlData := `
    <?xml version="1.0" encoding="UTF-8"?>
    <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
        <rootfiles>
            <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>
       </rootfiles>
    </container>
    `

    var rootFile RootFile
    xml.Unmarshal([]byte(xmlData), &rootFile)
    fmt.Println(rootFile)
}

Но я получаю пустой результат:

{ }

Что не так с моим кодом?

Я не верю, что Go поддерживает тег container “из коробки”, поэтому я думаю, что вы просто не разбираете XML полностью.

Эти типы должны быть полным разбором:

type Container struct {
    Version string `xml:"version,attr"`
    Xmlns string `xml:"xmlns,attr"`
    RootFiles RootFiles `xml:"rootfiles"`
}

type RootFiles struct {
    Rootfile RootFile `xml:"rootfile"`
}

type RootFile struct {
    FullPath string `xml:"full-path,attr"`
    MediaType string `xml:"media-type,attr"`
}

Но вам не нужно объявлять поля, которые вас не интересуют, такие как version и xmlns. Тем не менее, вам все равно нужно выразить всю структуру дерева XML. Вот полный рабочий пример:

package main

import (
    "encoding/xml"
    "fmt"
)

type Container struct {
    Version string `xml:"version,attr"`
    Xmlns string `xml:"xmlns,attr"`
    RootFiles RootFiles `xml:"rootfiles"`
}

type RootFiles struct {
    RootFile RootFile `xml:"rootfile"`
}

type RootFile struct {
    FullPath string `xml:"full-path,attr"`
    MediaType string `xml:"media-type,attr"`
}

func main() {
    xmlData := `
    <?xml version="1.0" encoding="UTF-8"?>
    <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
        <rootfiles>
            <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>
       </rootfiles>
    </container>
    `

    var rootFile Container
    err := xml.Unmarshal([]byte(xmlData), &rootFile)
    if err != nil {
        fmt.Printf("Что-то пошло не так: %v", err)
    }
    fmt.Printf("RootFile->full-path %v\nRootFile->media-type %v\n",
        rootFile.RootFiles.RootFile.FullPath,
        rootFile.RootFiles.RootFile.MediaType)
}

Ответ или решение

Конечно! Давайте разберёмся с вашей проблемой, связанной с парсингом XML в языке Go. Ваша задача состоит в том, чтобы извлечь атрибуты full-path и media-type из XML-документа, однако исходный код не обеспечивает полного разбора структуры XML.

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

package main

import (
    "encoding/xml"
    "fmt"
)

// Определяем структуры для представления XML
type Container struct {
    Version   string   `xml:"version,attr"`
    Xmlns     string   `xml:"xmlns,attr"`
    RootFiles RootFiles `xml:"rootfiles"`
}

type RootFiles struct {
    RootFile RootFile `xml:"rootfile"`
}

type RootFile struct {
    FullPath  string `xml:"full-path,attr"`
    MediaType string `xml:"media-type,attr"`
}

func main() {
    xmlData := `
    <?xml version="1.0" encoding="UTF-8"?>
    <container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
        <rootfiles>
            <rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>
        </rootfiles>
    </container>
    `

    var container Container
    err := xml.Unmarshal([]byte(xmlData), &container)
    if err != nil {
        fmt.Printf("Что-то пошло не так: %v\n", err)
        return
    }

    fmt.Printf("Полный путь: %v\nТип медиа: %v\n",
        container.RootFiles.RootFile.FullPath,
        container.RootFiles.RootFile.MediaType)
}

Объяснение кода:

  1. Структура Container: Это основная структура, которая представляет корневой элемент <container>. В ней указаны атрибуты version и xmlns, а также содержимое RootFiles.

  2. Структура RootFiles: Представляет элемент <rootfiles> и содержит структуру RootFile.

  3. Структура RootFile: В этой структуре представлена информация, которую вы хотите извлечь, включая атрибуты full-path и media-type.

  4. Функция main: Здесь мы объявляем XML-строку, парсим её с помощью xml.Unmarshal, и выводим на экран желаемые атрибуты.

Примечание:

В вашем исходном коде вы не разбирали древовидную структуру XML. Важно создавать структуры, соответствующие иерархии XML для корректной работы с Unmarshal. Обратите внимание, что в XML в вашем примере использовались символы &lt; и &gt;, которые являются HTML-сущностями для «<» и «>». Они должны быть заменены соответствующими символами, как показано в исправленном коде.

Теперь вы должны получить корректные значения атрибутов full-path и media-type. Надеюсь, что это поможет вам успешно решить вашу задачу с парсингом EPUB-метаданных!

Оцените материал
Добавить комментарий

Капча загружается...