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

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

Go: promoted fields in nested struct for XML decoding

问题

我有一个如下所示的XML转换结构:

  1. type urlset struct {
  2. XMLName xml.Name `xml:"urlset"`
  3. URL []struct {
  4. Loc string `xml:"loc"`
  5. News struct {
  6. Publishdate string `xml:"publication_date"`
  7. Title string `xml:"title"`
  8. Summary string `xml:"keywords"`
  9. } `xml:"news"`
  10. } `xml:"url"`
  11. }

如果我想提升嵌套结构News中的字段,我应该怎么做?

我希望能直接访问News的字段并打印出值,如下所示:

  1. var URLset urlset
  2. if xmlBytes, err := getXML(url); err != nil {
  3. fmt.Printf("Failed to get XML: %v", err)
  4. } else {
  5. xml.Unmarshal(xmlBytes, &URLset)
  6. }
  7. /************************** XML解析器 *************************/
  8. for _, URLElement := range URLset.URL {
  9. fmt.Println(
  10. "[Element]:",
  11. "\nTitle #", URLElement.News.Title,
  12. "\nPublicationDate #", URLElement.News.Publishdate,
  13. "\nSummary#", URLElement.News.Summary,
  14. "\nLoc #", URLElement.Loc, "\n")
  15. }

这是我的完整代码Go Playground

英文:

I have a XML transfered struct as below :

  1. type urlset struct {
  2. XMLName xml.Name `xml:"urlset"`
  3. URL []struct {
  4. Loc string `xml:"loc"`
  5. News struct {
  6. Publishdate string `xml:"publication_date"`
  7. Title string `xml:"title"`
  8. Summary string `xml:"keywords"`
  9. } `xml:"news"`
  10. } `xml:"url"`
  11. }

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

  1. var URLset urlset
  2. if xmlBytes, err := getXML(url); err != nil {
  3. fmt.Printf("Failed to get XML: %v", err)
  4. } else {
  5. xml.Unmarshal(xmlBytes, &URLset)
  6. }
  7. /************************** XML parser *************************/
  8. for _, URLElement := range URLset.URL {
  9. fmt.Println(
  10. "[Element]:",
  11. "\nTitle #", URLElement.title,
  12. "\nPublicationDate #", URLElement.Publishdate,
  13. "\nSummary#", URLElement.Summary,
  14. "\nLoc #", URLElement.Loc, "\n")
  15. }

Here is the complete code of mine Go Playground

答案1

得分: 1

省略名称将嵌入到自身。

示例:

  1. package main
  2. import "fmt"
  3. type Animal struct {
  4. Name string
  5. }
  6. type Cat struct {
  7. Animal // ⠀ Omit name
  8. }
  9. type Dog struct {
  10. A Animal // ⠀ have name "A"
  11. }
  12. func main() {
  13. cat := Cat{Animal{"Kitty"}}
  14. fmt.Println(cat.Name) // OK
  15. fmt.Println(cat.Animal.Name) // OK too
  16. dog := Dog{Animal{"Snoopy"}}
  17. // fmt.Println(dog.Name) // Error: type Dog has no field or method Name
  18. fmt.Println(dog.A.Name) // OK too
  19. }

<kbd>go playground</kbd>


你的情况

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

  1. package main
  2. import (
  3. "encoding/xml"
  4. "fmt"
  5. "io/ioutil"
  6. "net/http"
  7. )
  8. type News struct { // ⠀ move to here
  9. 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
  10. Title string `xml:"news>title"`
  11. Summary string `xml:"news>keywords"`
  12. }
  13. type urlset struct {
  14. XMLName xml.Name `xml:"urlset"`
  15. URL []struct {
  16. Loc string `xml:"loc"`
  17. News `xml:"news"` // ⠀ do not give the name
  18. } `xml:"url"`
  19. }
  20. func getXML(url string) ([]byte, error) {
  21. resp, err := http.Get(url)
  22. if err != nil {
  23. return []byte{}, fmt.Errorf("GET error: %v", err)
  24. }
  25. defer resp.Body.Close()
  26. if resp.StatusCode != http.StatusOK {
  27. return []byte{}, fmt.Errorf("Status error: %v", resp.StatusCode)
  28. }
  29. data, err := ioutil.ReadAll(resp.Body)
  30. if err != nil {
  31. return []byte{}, fmt.Errorf("Read body: %v", err)
  32. }
  33. return data, nil
  34. }
  35. func main() {
  36. var URLset urlset
  37. /* To avoid the link not working in the future, I write the value directly.
  38. url := "https://www.dw.com/de/news-sitemap.xml"
  39. if xmlBytes, err := getXML(url); err != nil {
  40. fmt.Printf("Failed to get XML: %v", err)
  41. } else {
  42. xml.Unmarshal(xmlBytes, &URLset)
  43. }
  44. */
  45. xmlBytes := []byte(`
  46. <urlset>
  47. <url>
  48. <loc>https://www.dw.com/de/kopf-an-kopf-rennen-bei-parlamentswahl-in-australien/a-61887162</loc>
  49. <news:news>
  50. <news:publication>
  51. <news:name>Deutsche Welle</news:name>
  52. <news:language>de</news:language>
  53. </news:publication>
  54. <news:publication_date>2022-05-21T11:28:55.875Z</news:publication_date>
  55. <news:title>Kopf-an-Kopf-Rennen bei Parlamentswahl in Australien</news:title>
  56. <news:keywords>Australien,Parlamentswahl,Scott Morrison,Anthony Albanese,Labor-Partei,Liberale</news:keywords>
  57. </news:news>
  58. <image:image>
  59. <image:loc>https://static.dw.com/image/61872101_403.jpg</image:loc>
  60. <image:caption>Der australische Premierminister Scott Morrison (r.) und sein Herausforderer, Oppositionsführer Anthony Albanese</image:caption>
  61. </image:image>
  62. </url>
  63. <url>
  64. <loc>https://www.dw.com/de/ukraine-aktuell-selenskyj-verlangt-entsch%C3%A4digungsfonds/a-61885143</loc>
  65. <news:news>
  66. <news:publication>
  67. <news:name>Deutsche Welle</news:name>
  68. <news:language>de</news:language>
  69. </news:publication>
  70. <news:publication_date>2022-05-21T11:10:21.813Z</news:publication_date>
  71. <news:title>Ukraine aktuell: Selenskyj verlangt Entschädigungsfonds</news:title>
  72. <news:keywords>Ukraine,Krieg,Russland,Wolodymyr Selenskyj,Wladimir Putin,Mariupol</news:keywords>
  73. </news:news>
  74. <image:image>
  75. <image:loc>https://static.dw.com/image/61885205_403.jpg</image:loc>
  76. <image:caption>75. Filmfestival Cannes | Rede von Wolodymyr Selenskyj</image:caption>
  77. </image:image>
  78. </url>
  79. <urlset>
  80. `)
  81. xml.Unmarshal(xmlBytes, &URLset)
  82. /************************** XML parser *************************/
  83. for _, URLElement := range URLset.URL {
  84. /*
  85. fmt.Println(
  86. "[Element]:",
  87. "\nTitle #", URLElement.News.Title,
  88. "\nPublicationDate #", URLElement.News.Publishdate,
  89. "\nSummary#", URLElement.News.Summary,
  90. "\nLoc #", URLElement.Loc, "\n")
  91. */
  92. fmt.Println( // ⠀ Now, this work!
  93. "[Element]:",
  94. "\nTitle #", URLElement.Title,
  95. "\nPublicationDate #", URLElement.Publishdate,
  96. "\nSummary#", URLElement.Summary,
  97. "\nLoc #", URLElement.Loc, "\n")
  98. }
  99. }

关于 XML 命名空间:

更多示例:

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

Omit name will embed to self.

example

  1. package main
  2. import &quot;fmt&quot;
  3. type Animal struct {
  4. Name string
  5. }
  6. type Cat struct {
  7. Animal // &#128072; Omit name
  8. }
  9. type Dog struct {
  10. A Animal // &#128072; have name &quot;A&quot;
  11. }
  12. func main() {
  13. cat := Cat{Animal{&quot;Kitty&quot;}}
  14. fmt.Println(cat.Name) // OK
  15. fmt.Println(cat.Animal.Name) // OK too
  16. dog := Dog{Animal{&quot;Snoopy&quot;}}
  17. // fmt.Println(dog.Name) // Error: type Dog has no field or method Name
  18. fmt.Println(dog.A.Name) // OK too
  19. }

<kbd>go playground</kbd>


your case

see &#128072; are enough (others same as yours.)

  1. package main
  2. import (
  3. &quot;encoding/xml&quot;
  4. &quot;fmt&quot;
  5. &quot;io/ioutil&quot;
  6. &quot;net/http&quot;
  7. )
  8. type News struct { // &#128072; move to here
  9. 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
  10. Title string `xml:&quot;news&gt;title&quot;`
  11. Summary string `xml:&quot;news&gt;keywords&quot;`
  12. }
  13. type urlset struct {
  14. XMLName xml.Name `xml:&quot;urlset&quot;`
  15. URL []struct {
  16. Loc string `xml:&quot;loc&quot;`
  17. News `xml:&quot;news&quot;` // &#128072; do not give the name
  18. } `xml:&quot;url&quot;`
  19. }
  20. func getXML(url string) ([]byte, error) {
  21. resp, err := http.Get(url)
  22. if err != nil {
  23. return []byte{}, fmt.Errorf(&quot;GET error: %v&quot;, err)
  24. }
  25. defer resp.Body.Close()
  26. if resp.StatusCode != http.StatusOK {
  27. return []byte{}, fmt.Errorf(&quot;Status error: %v&quot;, resp.StatusCode)
  28. }
  29. data, err := ioutil.ReadAll(resp.Body)
  30. if err != nil {
  31. return []byte{}, fmt.Errorf(&quot;Read body: %v&quot;, err)
  32. }
  33. return data, nil
  34. }
  35. func main() {
  36. var URLset urlset
  37. /* To avoid the link not working in the future, I write the value directly.
  38. url := &quot;https://www.dw.com/de/news-sitemap.xml&quot;
  39. if xmlBytes, err := getXML(url); err != nil {
  40. fmt.Printf(&quot;Failed to get XML: %v&quot;, err)
  41. } else {
  42. xml.Unmarshal(xmlBytes, &amp;URLset)
  43. }
  44. */
  45. xmlBytes := []byte(`
  46. &lt;urlset&gt;
  47. &lt;url&gt;
  48. &lt;loc&gt;https://www.dw.com/de/kopf-an-kopf-rennen-bei-parlamentswahl-in-australien/a-61887162&lt;/loc&gt;
  49. &lt;news:news&gt;
  50. &lt;news:publication&gt;
  51. &lt;news:name&gt;Deutsche Welle&lt;/news:name&gt;
  52. &lt;news:language&gt;de&lt;/news:language&gt;
  53. &lt;/news:publication&gt;
  54. &lt;news:publication_date&gt;2022-05-21T11:28:55.875Z&lt;/news:publication_date&gt;
  55. &lt;news:title&gt;Kopf-an-Kopf-Rennen bei Parlamentswahl in Australien&lt;/news:title&gt;
  56. &lt;news:keywords&gt;Australien,Parlamentswahl,Scott Morrison,Anthony Albanese,Labor-Partei,Liberale&lt;/news:keywords&gt;
  57. &lt;/news:news&gt;
  58. &lt;image:image&gt;
  59. &lt;image:loc&gt;https://static.dw.com/image/61872101_403.jpg&lt;/image:loc&gt;
  60. &lt;image:caption&gt;Der australische Premierminister Scott Morrison (r.) und sein Herausforderer, Oppositionsf&#252;hrer Anthony Albanese&lt;/image:caption&gt;
  61. &lt;/image:image&gt;
  62. &lt;/url&gt;
  63. &lt;url&gt;
  64. &lt;loc&gt;https://www.dw.com/de/ukraine-aktuell-selenskyj-verlangt-entsch%C3%A4digungsfonds/a-61885143&lt;/loc&gt;
  65. &lt;news:news&gt;
  66. &lt;news:publication&gt;
  67. &lt;news:name&gt;Deutsche Welle&lt;/news:name&gt;
  68. &lt;news:language&gt;de&lt;/news:language&gt;
  69. &lt;/news:publication&gt;
  70. &lt;news:publication_date&gt;2022-05-21T11:10:21.813Z&lt;/news:publication_date&gt;
  71. &lt;news:title&gt;Ukraine aktuell: Selenskyj verlangt Entsch&#228;digungsfonds&lt;/news:title&gt;
  72. &lt;news:keywords&gt;Ukraine,Krieg,Russland,Wolodymyr Selenskyj,Wladimir Putin,Mariupol&lt;/news:keywords&gt;
  73. &lt;/news:news&gt;
  74. &lt;image:image&gt;
  75. &lt;image:loc&gt;https://static.dw.com/image/61885205_403.jpg&lt;/image:loc&gt;
  76. &lt;image:caption&gt;75. Filmfestival Cannes | Rede von Wolodymyr Selenskyj&lt;/image:caption&gt;
  77. &lt;/image:image&gt;
  78. &lt;/url&gt;
  79. &lt;urlset&gt;
  80. `)
  81. xml.Unmarshal(xmlBytes, &amp;URLset)
  82. /************************** XML parser *************************/
  83. for _, URLElement := range URLset.URL {
  84. /*
  85. fmt.Println(
  86. &quot;[Element]:&quot;,
  87. &quot;\nTitle #&quot;, URLElement.News.Title,
  88. &quot;\nPublicationDate #&quot;, URLElement.News.Publishdate,
  89. &quot;\nSummary#&quot;, URLElement.News.Summary,
  90. &quot;\nLoc #&quot;, URLElement.Loc, &quot;\n&quot;)
  91. */
  92. fmt.Println( // &#128072; Now, this work!
  93. &quot;[Element]:&quot;,
  94. &quot;\nTitle #&quot;, URLElement.Title,
  95. &quot;\nPublicationDate #&quot;, URLElement.Publishdate,
  96. &quot;\nSummary#&quot;, URLElement.Summary,
  97. &quot;\nLoc #&quot;, URLElement.Loc, &quot;\n&quot;)
  98. }
  99. }

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:

确定