doujie7497 2016-09-29 21:37
浏览 84
已采纳

Golang XML自定义输出

I'm trying to create an XML implementing the MarshalXML output. But currently i'm facing several issues.

The structure i'm using for storing the data is:

type Edition struct {
    Launch         string             `xml:"launch" json:"launch"`
    Code           string             `xml:"code" json:"code"`
    Names          []NameNode         `xml:"names>name"`
    Cards          CardsComposition   `xml:"cards" json:"cards,omitempty"`
    Preconstructed PreconstructedInfo `xml:"preconstructed" json:"preconstructed,omitempty"`
    Vault          *struct{}          `xml:"vault" json:"vault"`
    Online         *struct{}          `xml:"online" json:"online"`
}

What i want is: If the Preconstructed field is not set, don't put the <preconstructed> tag (using the standard marshaler it put it even if it is empty).

So what i did is:

func (preconstructed PreconstructedInfo) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
    if (PreconstructedInfo{} == preconstructed) {
        return nil
    }
    return e.EncodeElement(preconstructed, start)
}

And it apparently works, if I use it for encoding a single Edition entity. But if I try to encode an array of Edition entities, I get the following error:

runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow

(the array is ~200 entries)

So what I don't understand is:

  • Why the stack overflow issue happens only when I try to customize the xml, that in this case is also trying to remove empty tags, so "saving space"
  • What is the best way to do it? And someone can explain me how to implement a custom XML Marshaler for go? I found plenty for JSON marshal, but nearly nothing for XML)
  • 写回答

1条回答 默认 最新

  • douzhao7445 2016-10-29 13:52
    关注

    Ok, i'll answer myself since i finally solved that issue.

    So apparently one of the problem is that EncodeElement is making use of MarshalXML, and with a huge file it cause an explosion function calls.

    Anyway the solution is to manually encode all components of the element.

    So in that case i did that:

    // MarshalXML generate XML output for PrecsontructedInfo
    func (preconstructed PreconstructedInfo) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
        if (PreconstructedInfo{} == preconstructed) {
            return nil
        }
        if preconstructed.Decks > 0 {
            start.Attr = []xml.Attr{xml.Attr{Name: xml.Name{Local: "decks"}, Value: strconv.Itoa(preconstructed.Size)}}
        }
        if strings.Compare(preconstructed.Type, "") != 0 {
            start.Attr = append(start.Attr, xml.Attr{Name: xml.Name{Local: "type"}, Value: preconstructed.Type})
        }
    
        err = e.EncodeToken(start)
        e.EncodeElement(preconstructed.Size, xml.StartElement{Name: xml.Name{Local: "size"}})
        return e.EncodeToken(xml.EndElement{Name: start.Name})
    }
    

    So what i did is:

    1. Check if the field is empty or not, if yes return null (the same as in my question)
    2. If not empty, check for the values contained in PreconstructedInfo, and add them in their relevant position, add first attributes to the start element. start.Attr will contain the xml attributes for the tag being Marshalled, the syntax for it is quite easy, you specify the name and the value. This has to be done before calling e.EncodeToken(start).
    3. After that encode the other elements of the tag into the current start Element. As you can see you must encode the tag using the xml.StartElement, in a similar way as for the attribute.
    4. Finally you can close the start Tag.

    In that way it will generate the xml tag only if data is available, and add attributes/childs only if they have a value, if they are empty or 0 it will not be added.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 如何在scanpy上做差异基因和通路富集?
  • ¥20 关于#硬件工程#的问题,请各位专家解答!
  • ¥15 关于#matlab#的问题:期望的系统闭环传递函数为G(s)=wn^2/s^2+2¢wn+wn^2阻尼系数¢=0.707,使系统具有较小的超调量
  • ¥15 FLUENT如何实现在堆积颗粒的上表面加载高斯热源
  • ¥30 截图中的mathematics程序转换成matlab
  • ¥15 动力学代码报错,维度不匹配
  • ¥15 Power query添加列问题
  • ¥50 Kubernetes&Fission&Eleasticsearch
  • ¥15 報錯:Person is not mapped,如何解決?
  • ¥15 c++头文件不能识别CDialog