如何在反序列化时跳过元素?

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

How to skip elements when unmarshalling?

问题

如何在解组 XML 时删除 <Text Language="de">...</Text>(如下所示)?

我尝试使用 UnmarshalXML 方法跳过元素,但是这样做会跳过整个元素。

Play Golang 链接中的示例

package main
    
import (
	"encoding/xml"
	"fmt"
)

type Root struct {
	Translation []Text `xml:"Texts>Text>Text"`
}

type Text struct {
	Language string `xml:"Language,attr"`
	Value    string `xml:"Value"`
}

func main() {
	foo := `
        <Root>
            <Texts>
                <Text>
                    <Text Language="EN">
                        <Value>One</Value>
                    </Text>
                    <Text Language="de">
                        <Value>Eins</Value>
                    </Text>
                </Text>
            </Texts>
        </Root>
        `

	var root Root
	e := xml.Unmarshal([]byte(foo), &root)
	if e != nil {
		panic(e)
	}

	fmt.Printf("%+v\n", root)
}

func (t *Text) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	tx := struct{ Language, Value string }{}
	
	if start.Attr[0].Value == "EN" {
		d.DecodeElement(&tx, &start)

        // 在这里无法获取 Language 属性
		*t = Text{tx.Language, tx.Value}
 		// fmt.Printf("hey: %+v %s\n", tx, start.Attr[0].Value)
	} else {
	    // 它输出了带有空字段的 DE 元素
	    d.Skip()
	}

	return nil
}

当前输出:

{Translation:[{Language: Value:One} {Language: Value:}]}

我想要的输出:

{Translation:[{Language:EN Value:One}]}
英文:

How can I remove &lt;Text Language=&quot;de&quot;&gt;...&lt;/Text&gt; (as shown below) when unmarshaling XML?

I tried to skip the element with UnmarshalXML method, however, it's skipping the whole element when I do that.

Example in Play Golang Link

package main

import (
	&quot;encoding/xml&quot;
	&quot;fmt&quot;
)

type Root struct {
	Translation []Text `xml:&quot;Texts&gt;Text&gt;Text&quot;`
}

type Text struct {
	Language string `xml:&quot;Language,attr&quot;`
	Value    string `xml:&quot;Value&quot;`
}

func main() {
	foo := `
        &lt;Root&gt;
            &lt;Texts&gt;
                &lt;Text&gt;
                    &lt;Text Language=&quot;EN&quot;&gt;
                        &lt;Value&gt;One&lt;/Value&gt;
                    &lt;/Text&gt;
                    &lt;Text Language=&quot;de&quot;&gt;
                        &lt;Value&gt;Eins&lt;/Value&gt;
                    &lt;/Text&gt;
                &lt;/Text&gt;
            &lt;/Texts&gt;
        &lt;/Root&gt;
        `

	var root Root
	e := xml.Unmarshal([]byte(foo), &amp;root)
	if e != nil {
		panic(e)
	}

	fmt.Printf(&quot;%+v\n&quot;, root)
}

func (t *Text) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	tx := struct{ Language, Value string }{}
	
	if start.Attr[0].Value == &quot;EN&quot; {
		d.DecodeElement(&amp;tx, &amp;start)

        // I couldn&#39;t got Language attr here
		*t = Text{tx.Language, tx.Value}
 		// fmt.Printf(&quot;hey: %+v %s\n&quot;, tx, start.Attr[0].Value)
	} else {
	    // It outputs DE element with empty fields
	    d.Skip()
	}

	return nil
}

Current Output:

{Translation:[{Language: Value:One} {Language: Value:}]}

What I Want:

{Translation:[{Language:EN Value:One}]}

答案1

得分: 2

你的代码中存在问题,导致第二个元素为空。你可以尝试以下修改:

package main

import (
	"encoding/xml"
	"fmt"
)

type Root struct {
	Translation Text `xml:"Texts>Text>Text"`
}

type Text []struct {
	Language string `xml:"Language,attr"`
	Value    string `xml:"Value"`
}

func main() {
	foo := `
        <Root>
            <Texts>
                <Text>
                    <Text Language="EN">
                        <Value>One</Value>
                    </Text>
                    <Text Language="de">
                        <Value>Eins</Value>
                    </Text>
                </Text>
            </Texts>
        </Root>
        `

	var root Root
	e := xml.Unmarshal([]byte(foo), &root)
	if e != nil {
		panic(e)
	}

	fmt.Printf("%+v\n", root)
}

func (t *Text) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	tx := []struct {
		Language string `xml:"Language,attr"`
		Value    string `xml:"Value"`
	}{}
	d.DecodeElement(&tx, &start)

	tSl := *t
	for _, elem := range tx {
		switch elem.Language {
		case "EN":
			tSl = append(tSl, struct {
				Language string `xml:"Language,attr"`
				Value    string `xml:"Value"`
			}{elem.Language, elem.Value})
		default:
			d.Skip()
		}
	}
	*t = tSl
	return nil
}

输出结果应为:

{Translation:[{Language:EN Value:One}]}
英文:

You're operating too low by unmarshalling at the Text Level - you're still Unmarshalling 2 Texts elements which is why you are seeing an empty second element. You could try something like this:

package main
import (
&quot;encoding/xml&quot;
&quot;fmt&quot;
)
type Root struct {
Translation Text `xml:&quot;Texts&gt;Text&gt;Text&quot;`
}
type Text []struct {
Language string `xml:&quot;Language,attr&quot;`
Value    string `xml:&quot;Value&quot;`
}
func main() {
foo := `
&lt;Root&gt;
&lt;Texts&gt;
&lt;Text&gt;
&lt;Text Language=&quot;EN&quot;&gt;
&lt;Value&gt;One&lt;/Value&gt;
&lt;/Text&gt;
&lt;Text Language=&quot;de&quot;&gt;
&lt;Value&gt;Eins&lt;/Value&gt;
&lt;/Text&gt;
&lt;/Text&gt;
&lt;/Texts&gt;
&lt;/Root&gt;
`
var root Root
e := xml.Unmarshal([]byte(foo), &amp;root)
if e != nil {
panic(e)
}
fmt.Printf(&quot;%+v\n&quot;, root)
}
func (t *Text) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
tx := []struct{
Language string `xml:&quot;Language,attr&quot;`
Value    string `xml:&quot;Value&quot;`
}{}
d.DecodeElement(&amp;tx, &amp;start)
tSl := *t
for _, elem := range tx {
switch elem.Language {
case &quot;EN&quot;:
tSl = append(tSl, struct{
Language string `xml:&quot;Language,attr&quot;`
Value    string `xml:&quot;Value&quot;`}{elem.Language, elem.Value})
default:
d.Skip()
}
}
*t = tSl
return nil
}

Output:

{Translation:[{Language:EN Value:One}]}

huangapple
  • 本文由 发表于 2017年6月9日 18:48:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/44455853.html
匿名

发表评论

匿名网友

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

确定