-
Notifications
You must be signed in to change notification settings - Fork 18.1k
encoding/xml: allow avoiding infinite recursion in EncodeElement #6474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Labels
Milestone
Comments
I have a struct with many fields in it: type TransactionRequest struct { .... } Some are strings, some are other structs, etc... Inside of MarshalXML if I do this (where "tr" is an instance of "TransactionRequest"): return e.EncodeElement(tr, start) "EncodeElement" causes the same MarshalXML function to be called recursively. What I want to do is change "start" (add attributes, change the name, etc...) but marshal the fields normally. In order to do this, without statically/manually marshaling each field, I have to change the type, where "_TransactionRequest" is just a type from "TransactionRequest": return e.EncodeElement(_TransactionRequest(tr), start) This prevents the recursion, but requires a new type to reflect. Ideally what I would like to do is simply call EncodeElement like this and not have it call MarshalXML again: return e.EncodeElement(tr, start) Or have some way of telling it to marshal just the fields inside: e.EncodeToken(start) // <TransactionResponse ...> e.EncodeBody(tr) // ... <field>...</field>... e.EncodeToken(EndElement{start.Name}); // </TransactionResponse> |
On second thought I think the second type definition is actually a pretty good way to handle this. It is the canonical way to change the method set in Go, and changing the method set is exactly what you are trying to do. We could add new API but using the types is more general and avoids needing new API in every use case. Note that if you are using pointer methods then you can still do the conversion from (*TransactionRequest) to (*rawTransactionRequest). Go allows that specifically because it enables changing the methods associated with a particular piece of data. Status changed to WorkingAsIntended. |
Having to redeclare types is very messy, especially when I have many structs that need to be defined this way. I also have to incur the cost of having twice the reflection. Would something like this work? type printer struct { *bufio.Writer encoder *Encoder seq int indent string prefix string depth int indentedIn bool putNewline bool attrNS map[string]string // map prefix -> name space attrPrefix map[string]string // map name space -> prefix prefixes []string tags []Name lastValue reflect.Value } if p.lastValue != val { // Ensure MarshalXML isn't called a second time p.lastValue = val // Check for marshaler. if val.CanInterface() && typ.Implements(marshalerType) { return p.marshalInterface(val.Interface().(Marshaler), defaultStart(typ, finfo, startTemplate)) } if val.CanAddr() { pv := val.Addr() if pv.CanInterface() && pv.Type().Implements(marshalerType) { return p.marshalInterface(pv.Interface().(Marshaler), defaultStart(pv.Type(), finfo, startTemplate)) } } } If if it did it would allow me to call EncodeElement inside MarhsalXML and prevent the recursion. |
This issue was closed.
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
The text was updated successfully, but these errors were encountered: