On Tue, 11 Oct 2016 10:00:33 -0700 (PDT)
sm...@brillig.org wrote:
[...]
> > > I'm trying to Marshal XML where an element has mixed content:
> > >
https://www.w3.org/TR/REC-xml/#sec-mixed-content
> > >
> > > I tried just using []interface{} but if I put in just a string,
> > > Marshal surrounds each string with the name of the slice:
[...]
> > Yes. "\nhello\n" and "\nworld\n" are what is called "character
> > data" in XML parlance. So if you go with the standard approach to
> > marshaling data to XML -- via a struct type with properly annotated
> > fields -- you should annotate the fields for your character data
> > chunks with the ",chardata" modifiers.
> >
> > See the docs on encoding/xml.Marshal function for more info.
[...]
> Sorry, I should have been more clear. The reason I used a slice was
> because I need an arbitrary number of elements. So I can't just use a
> static struct with the chardata tags.
OK, doable with custom marshaler code:
----------------8<----------------
package main
import (
"encoding/xml"
"fmt"
"os"
)
type Elements []interface{}
func (es Elements) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
for _, v := range es {
if s, ok := v.(string); ok {
err = e.EncodeToken(xml.CharData([]byte(s)))
if err != nil {
break
}
continue
}
err = e.Encode(v)
if err != nil {
break
}
}
return
}
func main() {
type Root struct {
XMLName xml.Name `xml:"root"`
Elements Elements
}
type E1 struct {
XMLName xml.Name `xml:"element1"`
Source string `xml:",chardata"`
}
type E2 struct {
XMLName xml.Name `xml:"element2"`
Source string `xml:",chardata"`
}
var doc = &Root{
Elements: Elements{
&E1{Source: "foo"}, "hello",
&E2{Source: "bar"}, "world"},
}
output, err := xml.MarshalIndent(doc, " ", " ")
if err != nil {
fmt.Printf("error: %v\n", err)
}
os.Stdout.Write(output)
}
----------------8<----------------
Playground link: <
https://play.golang.org/p/twSkrZIVY9>