英文:
Go: promoted fields in nested struct for XML decoding
问题
我有一个如下所示的XML转换结构:
type urlset struct {
XMLName xml.Name `xml:"urlset"`
URL []struct {
Loc string `xml:"loc"`
News struct {
Publishdate string `xml:"publication_date"`
Title string `xml:"title"`
Summary string `xml:"keywords"`
} `xml:"news"`
} `xml:"url"`
}
如果我想提升嵌套结构News中的字段,我应该怎么做?
我希望能直接访问News的字段并打印出值,如下所示:
var URLset urlset
if xmlBytes, err := getXML(url); err != nil {
fmt.Printf("Failed to get XML: %v", err)
} else {
xml.Unmarshal(xmlBytes, &URLset)
}
/************************** XML解析器 *************************/
for _, URLElement := range URLset.URL {
fmt.Println(
"[Element]:",
"\nTitle #", URLElement.News.Title,
"\nPublicationDate #", URLElement.News.Publishdate,
"\nSummary#", URLElement.News.Summary,
"\nLoc #", URLElement.Loc, "\n")
}
这是我的完整代码Go Playground。
英文:
I have a XML transfered struct as below :
type urlset struct {
XMLName xml.Name `xml:"urlset"`
URL []struct {
Loc string `xml:"loc"`
News struct {
Publishdate string `xml:"publication_date"`
Title string `xml:"title"`
Summary string `xml:"keywords"`
} `xml:"news"`
} `xml:"url"`
}
What I should do if I want to promote fields in the nested structure News ?
I hope I can directly access News' fields and print the value as below
var URLset urlset
if xmlBytes, err := getXML(url); err != nil {
fmt.Printf("Failed to get XML: %v", err)
} else {
xml.Unmarshal(xmlBytes, &URLset)
}
/************************** XML parser *************************/
for _, URLElement := range URLset.URL {
fmt.Println(
"[Element]:",
"\nTitle #", URLElement.title,
"\nPublicationDate #", URLElement.Publishdate,
"\nSummary#", URLElement.Summary,
"\nLoc #", URLElement.Loc, "\n")
}
Here is the complete code of mine Go Playground
答案1
得分: 1
省略名称将嵌入到自身。
示例:
package main
import "fmt"
type Animal struct {
Name string
}
type Cat struct {
Animal // ⠀ Omit name
}
type Dog struct {
A Animal // ⠀ have name "A"
}
func main() {
cat := Cat{Animal{"Kitty"}}
fmt.Println(cat.Name) // OK
fmt.Println(cat.Animal.Name) // OK too
dog := Dog{Animal{"Snoopy"}}
// fmt.Println(dog.Name) // Error: type Dog has no field or method Name
fmt.Println(dog.A.Name) // OK too
}
<kbd>go playground</kbd>
你的情况
看到 👈
就足够了(其他与你的情况相同)
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
)
type News struct { // ⠀ move to here
Publishdate string `xml:"news>publication_date"` // ⠀ Use ">" to tell its parent. https://github.com/golang/go/blob/0a1a092c4b56a1d4033372fbd07924dad8cbb50b/src/encoding/xml/typeinfo.go#L198-L199
Title string `xml:"news>title"`
Summary string `xml:"news>keywords"`
}
type urlset struct {
XMLName xml.Name `xml:"urlset"`
URL []struct {
Loc string `xml:"loc"`
News `xml:"news"` // ⠀ do not give the name
} `xml:"url"`
}
func getXML(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return []byte{}, fmt.Errorf("GET error: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return []byte{}, fmt.Errorf("Status error: %v", resp.StatusCode)
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return []byte{}, fmt.Errorf("Read body: %v", err)
}
return data, nil
}
func main() {
var URLset urlset
/* To avoid the link not working in the future, I write the value directly.
url := "https://www.dw.com/de/news-sitemap.xml"
if xmlBytes, err := getXML(url); err != nil {
fmt.Printf("Failed to get XML: %v", err)
} else {
xml.Unmarshal(xmlBytes, &URLset)
}
*/
xmlBytes := []byte(`
<urlset>
<url>
<loc>https://www.dw.com/de/kopf-an-kopf-rennen-bei-parlamentswahl-in-australien/a-61887162</loc>
<news:news>
<news:publication>
<news:name>Deutsche Welle</news:name>
<news:language>de</news:language>
</news:publication>
<news:publication_date>2022-05-21T11:28:55.875Z</news:publication_date>
<news:title>Kopf-an-Kopf-Rennen bei Parlamentswahl in Australien</news:title>
<news:keywords>Australien,Parlamentswahl,Scott Morrison,Anthony Albanese,Labor-Partei,Liberale</news:keywords>
</news:news>
<image:image>
<image:loc>https://static.dw.com/image/61872101_403.jpg</image:loc>
<image:caption>Der australische Premierminister Scott Morrison (r.) und sein Herausforderer, Oppositionsführer Anthony Albanese</image:caption>
</image:image>
</url>
<url>
<loc>https://www.dw.com/de/ukraine-aktuell-selenskyj-verlangt-entsch%C3%A4digungsfonds/a-61885143</loc>
<news:news>
<news:publication>
<news:name>Deutsche Welle</news:name>
<news:language>de</news:language>
</news:publication>
<news:publication_date>2022-05-21T11:10:21.813Z</news:publication_date>
<news:title>Ukraine aktuell: Selenskyj verlangt Entschädigungsfonds</news:title>
<news:keywords>Ukraine,Krieg,Russland,Wolodymyr Selenskyj,Wladimir Putin,Mariupol</news:keywords>
</news:news>
<image:image>
<image:loc>https://static.dw.com/image/61885205_403.jpg</image:loc>
<image:caption>75. Filmfestival Cannes | Rede von Wolodymyr Selenskyj</image:caption>
</image:image>
</url>
<urlset>
`)
xml.Unmarshal(xmlBytes, &URLset)
/************************** XML parser *************************/
for _, URLElement := range URLset.URL {
/*
fmt.Println(
"[Element]:",
"\nTitle #", URLElement.News.Title,
"\nPublicationDate #", URLElement.News.Publishdate,
"\nSummary#", URLElement.News.Summary,
"\nLoc #", URLElement.Loc, "\n")
*/
fmt.Println( // ⠀ Now, this work!
"[Element]:",
"\nTitle #", URLElement.Title,
"\nPublicationDate #", URLElement.Publishdate,
"\nSummary#", URLElement.Summary,
"\nLoc #", URLElement.Loc, "\n")
}
}
关于 XML 命名空间:
- XML 命名空间提供了一种避免元素名称冲突的方法。
- marshal.go
- read.go
- typeinfo.go:准备字段名称和父级。 现在你知道为什么是
">"
了。
更多示例:
- ExampleUnmarshal 这个链接来自
go/src/encoding/xml/example_test.go
实际上,所有的示例都很容易理解。所以它很适合学习。
英文:
Omit name will embed to self.
example
package main
import "fmt"
type Animal struct {
Name string
}
type Cat struct {
Animal // 👈 Omit name
}
type Dog struct {
A Animal // 👈 have name "A"
}
func main() {
cat := Cat{Animal{"Kitty"}}
fmt.Println(cat.Name) // OK
fmt.Println(cat.Animal.Name) // OK too
dog := Dog{Animal{"Snoopy"}}
// fmt.Println(dog.Name) // Error: type Dog has no field or method Name
fmt.Println(dog.A.Name) // OK too
}
<kbd>go playground</kbd>
your case
see 👈
are enough (others same as yours.)
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
"net/http"
)
type News struct { // 👈 move to here
Publishdate string `xml:"news>publication_date"` // 👈 Use ">" to tell its parent. https://github.com/golang/go/blob/0a1a092c4b56a1d4033372fbd07924dad8cbb50b/src/encoding/xml/typeinfo.go#L198-L199
Title string `xml:"news>title"`
Summary string `xml:"news>keywords"`
}
type urlset struct {
XMLName xml.Name `xml:"urlset"`
URL []struct {
Loc string `xml:"loc"`
News `xml:"news"` // 👈 do not give the name
} `xml:"url"`
}
func getXML(url string) ([]byte, error) {
resp, err := http.Get(url)
if err != nil {
return []byte{}, fmt.Errorf("GET error: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return []byte{}, fmt.Errorf("Status error: %v", resp.StatusCode)
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return []byte{}, fmt.Errorf("Read body: %v", err)
}
return data, nil
}
func main() {
var URLset urlset
/* To avoid the link not working in the future, I write the value directly.
url := "https://www.dw.com/de/news-sitemap.xml"
if xmlBytes, err := getXML(url); err != nil {
fmt.Printf("Failed to get XML: %v", err)
} else {
xml.Unmarshal(xmlBytes, &URLset)
}
*/
xmlBytes := []byte(`
<urlset>
<url>
<loc>https://www.dw.com/de/kopf-an-kopf-rennen-bei-parlamentswahl-in-australien/a-61887162</loc>
<news:news>
<news:publication>
<news:name>Deutsche Welle</news:name>
<news:language>de</news:language>
</news:publication>
<news:publication_date>2022-05-21T11:28:55.875Z</news:publication_date>
<news:title>Kopf-an-Kopf-Rennen bei Parlamentswahl in Australien</news:title>
<news:keywords>Australien,Parlamentswahl,Scott Morrison,Anthony Albanese,Labor-Partei,Liberale</news:keywords>
</news:news>
<image:image>
<image:loc>https://static.dw.com/image/61872101_403.jpg</image:loc>
<image:caption>Der australische Premierminister Scott Morrison (r.) und sein Herausforderer, Oppositionsführer Anthony Albanese</image:caption>
</image:image>
</url>
<url>
<loc>https://www.dw.com/de/ukraine-aktuell-selenskyj-verlangt-entsch%C3%A4digungsfonds/a-61885143</loc>
<news:news>
<news:publication>
<news:name>Deutsche Welle</news:name>
<news:language>de</news:language>
</news:publication>
<news:publication_date>2022-05-21T11:10:21.813Z</news:publication_date>
<news:title>Ukraine aktuell: Selenskyj verlangt Entschädigungsfonds</news:title>
<news:keywords>Ukraine,Krieg,Russland,Wolodymyr Selenskyj,Wladimir Putin,Mariupol</news:keywords>
</news:news>
<image:image>
<image:loc>https://static.dw.com/image/61885205_403.jpg</image:loc>
<image:caption>75. Filmfestival Cannes | Rede von Wolodymyr Selenskyj</image:caption>
</image:image>
</url>
<urlset>
`)
xml.Unmarshal(xmlBytes, &URLset)
/************************** XML parser *************************/
for _, URLElement := range URLset.URL {
/*
fmt.Println(
"[Element]:",
"\nTitle #", URLElement.News.Title,
"\nPublicationDate #", URLElement.News.Publishdate,
"\nSummary#", URLElement.News.Summary,
"\nLoc #", URLElement.Loc, "\n")
*/
fmt.Println( // 👈 Now, this work!
"[Element]:",
"\nTitle #", URLElement.Title,
"\nPublicationDate #", URLElement.Publishdate,
"\nSummary#", URLElement.Summary,
"\nLoc #", URLElement.Loc, "\n")
}
}
About the XML Namespaces
- XML Namespaces provide a method to avoid element name conflicts.
- marshal.go
- read.go
- typeinfo.go: Prepare field name and parents. Now you know why it is ">"
More Examples
- ExampleUnmarshal This link is from
go/src/encoding/xml/example_test.go
In fact, all the examples are easy to understand. So it's good for learning.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论