如何让golang区分带有命名空间和不带命名空间的XML元素?

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

How to let golang distinguish XML elements with and without namespaces?

问题

假设我有以下的XML数据:

  1. <image>
  2. <url>http://sampleUrl.com</url>
  3. </image>
  4. <itunes:image url="http://sampleItunesUrl.com" /> //xmlData

我使用以下结构体对其进行解码:

  1. type Response struct {
  2. XMLName xml.Name `xml:"resp"`
  3. Image []struct {
  4. URL string `xml:"url"`
  5. } `xml:"image"`
  6. ItunesImage struct {
  7. URL string `xml:"url,attr"`
  8. } `xml:"http://www.itunes.com/dtds/podcast-1.0.dtd image"`
  9. }

我有如下代码:

  1. var resp Response
  2. err := xml.Unmarshal([]byte(xmlData), &resp)
  3. if err != nil {
  4. fmt.Printf("Error decoding XML: %s\n", err)
  5. return
  6. }
  7. for _, img := range resp.Image{
  8. if img.URL != "" {
  9. //<image>,而不是<itunes:image>
  10. }
  11. }

来处理解码。

我遇到的问题是,Image []struct似乎将<image><itunes:image>都视为<image>元素,因为它们都有"image"。为了过滤掉<itunes:image>,我使用的方法是让Image []struct中的每个元素检查它们的url是否为空字符串(因为对于<itunes:image>,它的url是属性)。

另一种方法是编写自己的Unmarshal函数来区分带有和不带有itunes命名空间的XML元素。基本上,我希望Image []struct只包含<image>元素。

我想知道Go语言是否有一些内置的功能可以区分它们?还是我必须编写代码来过滤掉<itunes:image>

英文:

suppose I have the following XML data:

  1. &lt;image&gt;
  2. &lt;url&gt; http://sampleUrl.com
  3. &lt;/url&gt;
  4. &lt;/image&gt;
  5. &lt;itunes:image url=&quot;http://sampleItunesUrl.com&quot; /&gt; //xmlData

I use this struct to decode it:

  1. type Response struct {
  2. XMLName xml.Name `xml:&quot;resp&quot;`
  3. Image []struct {
  4. URL string `xml:&quot;url&quot;`
  5. } `xml:&quot;image&quot;`
  6. ItunesImage struct {
  7. URL string `xml:&quot;url,attr&quot;`
  8. } `xml:&quot;http://www.itunes.com/dtds/podcast-1.0.dtd image&quot;`
  9. }

and I have codes like:

  1. var resp Response
  2. err := xml.Unmarshal([]byte(xmlData), &amp;resp)
  3. if err != nil {
  4. fmt.Printf(&quot;Error decoding XML: %s\n&quot;, err)
  5. return
  6. }
  7. for _, img := range resp.Image{
  8. if img.URL != &quot;&quot; {
  9. //&lt;image&gt;, not &lt;itunes:image&gt;
  10. }
  11. }

to process decoding

The problem I am having is that looks like Image []struct considers both &lt;image&gt; and &lt;itunes:image to be &lt;image&gt; element, since they both have "image". To filter out &lt;itunes:image, the approach I am using is to let each one in Image []struct examine if their url are empty strings (because for &lt;itunes:image its url is attribute).

Another approach is to write my own Unmarshal function to distinguish between XML elements with and without itunes namespace. Basically I want Image []struct to only hold elements &lt;image&gt;

I am wondering if go has some built-in functionalities to distinguish? Or I have to write my codes to filter out &lt;itunes:image&gt; ?

答案1

得分: 2

请注意,字段的顺序很重要。ItunesImage具有更具体的标签,因此应该在Image之前。

  1. package main
  2. import (
  3. "encoding/xml"
  4. "fmt"
  5. )
  6. func main() {
  7. type Response struct {
  8. XMLName xml.Name `xml:"resp"`
  9. ItunesImage struct {
  10. URL string `xml:"url,attr"`
  11. } `xml:"http://www.itunes.com/dtds/podcast-1.0.dtd image"`
  12. Image []struct {
  13. URL string `xml:"url"`
  14. } `xml:"image"`
  15. }
  16. xmlData := `
  17. <resp xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
  18. <image>
  19. <url>http://sampleUrl.com</url>
  20. </image>
  21. <itunes:image url="http://sampleItunesUrl.com/" />
  22. </resp>
  23. `
  24. var resp Response
  25. err := xml.Unmarshal([]byte(xmlData), &resp)
  26. if err != nil {
  27. fmt.Printf("解码XML时出错:%s\n", err)
  28. return
  29. }
  30. fmt.Printf("ItunesImage:%v\n", resp.ItunesImage)
  31. fmt.Printf("Images:%v\n", resp.Image)
  32. }

如果你只需要从<image>标签中获取image/url,你可以像这样定义Response结构体:

  1. type Response struct {
  2. XMLName xml.Name `xml:"resp"`
  3. Image []string `xml:"image>url"`
  4. }

关于标题中的一般问题(如何让golang区分带有命名空间和不带命名空间的XML元素),你可以使用名为XMLName的字段捕获元素名称,并检查该字段的Space成员。请参考下面的示例:

  1. package main
  2. import (
  3. "encoding/xml"
  4. "fmt"
  5. )
  6. func main() {
  7. type Response struct {
  8. XMLName xml.Name `xml:"resp"`
  9. Image []struct {
  10. XMLName xml.Name
  11. URL string `xml:"url"`
  12. } `xml:"image"`
  13. }
  14. xmlData := `
  15. <resp xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
  16. <image>
  17. <url>http://sampleUrl.com</url>
  18. </image>
  19. <itunes:image>
  20. <url>http://sampleItunesUrl.com/</url>
  21. </itunes:image>
  22. </resp>
  23. `
  24. var resp Response
  25. err := xml.Unmarshal([]byte(xmlData), &resp)
  26. if err != nil {
  27. fmt.Printf("解码XML时出错:%s\n", err)
  28. return
  29. }
  30. for _, img := range resp.Image {
  31. fmt.Printf("命名空间:%q, URL:%s\n", img.XMLName.Space, img.URL)
  32. }
  33. }

上述示例的输出结果为:

  1. 命名空间:"", URLhttp://sampleUrl.com
  2. 命名空间:"http://www.itunes.com/dtds/podcast-1.0.dtd", URLhttp://sampleItunesUrl.com/
英文:

Please note that the field order matters. ItunesImage has a more specific tag, so it should go before Image.

  1. package main
  2. import (
  3. &quot;encoding/xml&quot;
  4. &quot;fmt&quot;
  5. )
  6. func main() {
  7. type Response struct {
  8. XMLName xml.Name `xml:&quot;resp&quot;`
  9. ItunesImage struct {
  10. URL string `xml:&quot;url,attr&quot;`
  11. } `xml:&quot;http://www.itunes.com/dtds/podcast-1.0.dtd image&quot;`
  12. Image []struct {
  13. URL string `xml:&quot;url&quot;`
  14. } `xml:&quot;image&quot;`
  15. }
  16. xmlData := `
  17. &lt;resp xmlns:itunes=&quot;http://www.itunes.com/dtds/podcast-1.0.dtd&quot;&gt;
  18. &lt;image&gt;
  19. &lt;url&gt;http://sampleUrl.com&lt;/url&gt;
  20. &lt;/image&gt;
  21. &lt;itunes:image url=&quot;http://sampleItunesUrl.com/&quot; /&gt;
  22. &lt;/resp&gt;
  23. `
  24. var resp Response
  25. err := xml.Unmarshal([]byte(xmlData), &amp;resp)
  26. if err != nil {
  27. fmt.Printf(&quot;Error decoding XML: %s\n&quot;, err)
  28. return
  29. }
  30. fmt.Printf(&quot;ItunesImage: %v\n&quot;, resp.ItunesImage)
  31. fmt.Printf(&quot;Images: %v\n&quot;, resp.Image)
  32. }

And if you only need image/url from the &lt;image&gt; tag, you could define the Response struct like this:

  1. type Response struct {
  2. XMLName xml.Name `xml:&quot;resp&quot;`
  3. Image []string `xml:&quot;image&gt;url&quot;`
  4. }

Regarding the general question in the title (How to let golang distinguish XML elements with and without namespaces?), you can capture the element name with a field named XMLName and examine the Space member of this field. See the demo below:

  1. package main
  2. import (
  3. &quot;encoding/xml&quot;
  4. &quot;fmt&quot;
  5. )
  6. func main() {
  7. type Response struct {
  8. XMLName xml.Name `xml:&quot;resp&quot;`
  9. Image []struct {
  10. XMLName xml.Name
  11. URL string `xml:&quot;url&quot;`
  12. } `xml:&quot;image&quot;`
  13. }
  14. xmlData := `
  15. &lt;resp xmlns:itunes=&quot;http://www.itunes.com/dtds/podcast-1.0.dtd&quot;&gt;
  16. &lt;image&gt;
  17. &lt;url&gt;http://sampleUrl.com&lt;/url&gt;
  18. &lt;/image&gt;
  19. &lt;itunes:image&gt;
  20. &lt;url&gt;http://sampleItunesUrl.com/&lt;/url&gt;
  21. &lt;/itunes:image&gt;
  22. &lt;/resp&gt;
  23. `
  24. var resp Response
  25. err := xml.Unmarshal([]byte(xmlData), &amp;resp)
  26. if err != nil {
  27. fmt.Printf(&quot;Error decoding XML: %s\n&quot;, err)
  28. return
  29. }
  30. for _, img := range resp.Image {
  31. fmt.Printf(&quot;namespace: %q, url: %s\n&quot;, img.XMLName.Space, img.URL)
  32. }
  33. }

The output of the above demo is:

  1. namespace: &quot;&quot;, url: http://sampleUrl.com
  2. namespace: &quot;http://www.itunes.com/dtds/podcast-1.0.dtd&quot;, url: http://sampleItunesUrl.com/

huangapple
  • 本文由 发表于 2023年4月1日 06:39:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/75903249.html
匿名

发表评论

匿名网友

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

确定