Go:在XML解码中提升嵌套结构的字段

huangapple go评论89阅读模式
英文:

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>


你的情况

看到 &#128072; 就足够了(其他与你的情况相同)

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 命名空间:

更多示例:

  • ExampleUnmarshal 这个链接来自 go/src/encoding/xml/example_test.go 实际上,所有的示例都很容易理解。所以它很适合学习。
英文:

Omit name will embed to self.

example

package main
import &quot;fmt&quot;
type Animal struct {
Name string
}
type Cat struct {
Animal // &#128072; Omit name
}
type Dog struct {
A Animal // &#128072; have name &quot;A&quot;
}
func main() {
cat := Cat{Animal{&quot;Kitty&quot;}}
fmt.Println(cat.Name)        // OK
fmt.Println(cat.Animal.Name) // OK too
dog := Dog{Animal{&quot;Snoopy&quot;}}
// 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 &#128072; are enough (others same as yours.)

package main

import (
	&quot;encoding/xml&quot;
	&quot;fmt&quot;
	&quot;io/ioutil&quot;
	&quot;net/http&quot;
)

type News struct { // &#128072; move to here
	Publishdate string `xml:&quot;news&gt;publication_date&quot;` // &#128072; Use &quot;&gt;&quot; to tell its parent. https://github.com/golang/go/blob/0a1a092c4b56a1d4033372fbd07924dad8cbb50b/src/encoding/xml/typeinfo.go#L198-L199
	Title       string `xml:&quot;news&gt;title&quot;`
	Summary     string `xml:&quot;news&gt;keywords&quot;`
}

type urlset struct {
	XMLName xml.Name `xml:&quot;urlset&quot;`
	URL     []struct {
		Loc  string `xml:&quot;loc&quot;`
		News `xml:&quot;news&quot;` // &#128072; do not give the name
	} `xml:&quot;url&quot;`
}

func getXML(url string) ([]byte, error) {
	resp, err := http.Get(url)
	if err != nil {
		return []byte{}, fmt.Errorf(&quot;GET error: %v&quot;, err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return []byte{}, fmt.Errorf(&quot;Status error: %v&quot;, resp.StatusCode)
	}

	data, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return []byte{}, fmt.Errorf(&quot;Read body: %v&quot;, err)
	}
	return data, nil
}

func main() {

	var URLset urlset
	/* To avoid the link not working in the future, I write the value directly.
	url := &quot;https://www.dw.com/de/news-sitemap.xml&quot;
	if xmlBytes, err := getXML(url); err != nil {
		fmt.Printf(&quot;Failed to get XML: %v&quot;, err)
	} else {
		xml.Unmarshal(xmlBytes, &amp;URLset)
	}
	*/

	xmlBytes := []byte(`
&lt;urlset&gt;
	&lt;url&gt;
		&lt;loc&gt;https://www.dw.com/de/kopf-an-kopf-rennen-bei-parlamentswahl-in-australien/a-61887162&lt;/loc&gt;
		&lt;news:news&gt;
			&lt;news:publication&gt;
				&lt;news:name&gt;Deutsche Welle&lt;/news:name&gt;
				&lt;news:language&gt;de&lt;/news:language&gt;
			&lt;/news:publication&gt;
			&lt;news:publication_date&gt;2022-05-21T11:28:55.875Z&lt;/news:publication_date&gt;
			&lt;news:title&gt;Kopf-an-Kopf-Rennen bei Parlamentswahl in Australien&lt;/news:title&gt;
			&lt;news:keywords&gt;Australien,Parlamentswahl,Scott Morrison,Anthony Albanese,Labor-Partei,Liberale&lt;/news:keywords&gt;
		&lt;/news:news&gt;
		&lt;image:image&gt;
			&lt;image:loc&gt;https://static.dw.com/image/61872101_403.jpg&lt;/image:loc&gt;
			&lt;image:caption&gt;Der australische Premierminister Scott Morrison (r.) und sein Herausforderer, Oppositionsf&#252;hrer Anthony Albanese&lt;/image:caption&gt;
		&lt;/image:image&gt;
	&lt;/url&gt;
	&lt;url&gt;
		&lt;loc&gt;https://www.dw.com/de/ukraine-aktuell-selenskyj-verlangt-entsch%C3%A4digungsfonds/a-61885143&lt;/loc&gt;
		&lt;news:news&gt;
			&lt;news:publication&gt;
				&lt;news:name&gt;Deutsche Welle&lt;/news:name&gt;
				&lt;news:language&gt;de&lt;/news:language&gt;
			&lt;/news:publication&gt;
			&lt;news:publication_date&gt;2022-05-21T11:10:21.813Z&lt;/news:publication_date&gt;
			&lt;news:title&gt;Ukraine aktuell: Selenskyj verlangt Entsch&#228;digungsfonds&lt;/news:title&gt;
			&lt;news:keywords&gt;Ukraine,Krieg,Russland,Wolodymyr Selenskyj,Wladimir Putin,Mariupol&lt;/news:keywords&gt;
		&lt;/news:news&gt;
		&lt;image:image&gt;
			&lt;image:loc&gt;https://static.dw.com/image/61885205_403.jpg&lt;/image:loc&gt;
			&lt;image:caption&gt;75. Filmfestival Cannes | Rede von Wolodymyr Selenskyj&lt;/image:caption&gt;
		&lt;/image:image&gt;
	&lt;/url&gt;
&lt;urlset&gt;
`)

	xml.Unmarshal(xmlBytes, &amp;URLset)
	/************************** XML parser *************************/
	for _, URLElement := range URLset.URL {
		/*
		   fmt.Println(
		       &quot;[Element]:&quot;,
		       &quot;\nTitle #&quot;, URLElement.News.Title,
		       &quot;\nPublicationDate #&quot;, URLElement.News.Publishdate,
		       &quot;\nSummary#&quot;, URLElement.News.Summary,
		       &quot;\nLoc #&quot;, URLElement.Loc, &quot;\n&quot;)
		*/

		fmt.Println( // &#128072; Now, this work!
			&quot;[Element]:&quot;,
			&quot;\nTitle #&quot;, URLElement.Title,
			&quot;\nPublicationDate #&quot;, URLElement.Publishdate,
			&quot;\nSummary#&quot;, URLElement.Summary,
			&quot;\nLoc #&quot;, URLElement.Loc, &quot;\n&quot;)
	}
}

About the XML Namespaces

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.

huangapple
  • 本文由 发表于 2022年5月20日 08:33:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/72312384.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定