I'm wondering what is the best way to iterate over some conditionals to generate a complete XML response for an adTag.
I am building an array of elements using a single type of struct that would represent a single Adbreak and then I need to wrap them all in vmap:VMAP element. This would be very easy for me to solve in Node.js but I have delegated my ad server to Golang and am having some trouble with generating XML's.
I want to do a loop through each condition. For example: preRoll := 1, midRoll1 := 3, midRoll2 := 3, midRoll3 := 1, postRoll := 1. And I would be iterating based on those numbers, so preRoll := 1 would result with
<vmap:AdBreak timeOffset="start" breakType="linear" breakId="preroll">
<vmap:AdSource id="preroll-ad-1" allowMultipleAds="false" followRedirects="true">
<vmap:AdTagURI templateType="vast3">
<![CDATA[ https://pubads.g.doubleclick.net/gampad/ads?slotname=/21775744923/external/vmap_ad_samples&sz=640x480&ciu_szs=300x250&cust_params=sample_ar%3Dpremidpostpod&url=&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&useragent=Mozilla/5.0+(Windows+NT+10.0%3B+Win64%3B+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/103.0.0.0+Safari/537.36,gzip(gfe)&vad_type=linear&vpos=preroll&pod=1&ppos=1&lip=true&min_ad_duration=0&max_ad_duration=30000&vrid=1270234&cmsid=496&video_doc_id=short_onecue&kfa=0&tfcd=0 ]]>
</vmap:AdTagURI>
</vmap:AdSource>
</vmap:AdBreak>
and then I would append the next AdBreak element after that. I do not want to generate a file, I am simply responding and serving the file when a get request is made to the endpoint. Im also wondering how I would conditionally change the attributes for each element because it seems I can only define them within the struct object literal ``
type Vmap struct {
AdBreak string
}
func marshallVmap() ([]byte, error) {
temp := struct {
vmap string `vmap:Adbreak`
}{
vmap: "a",
}
return xml.MarshalIndent(temp, "", " ")
}
func GenerateAndServeVmap(r *http.Request) ([]byte, error) {
vmaps := make([]interface{}, 0)
preRoll := true
// midRoll1 := 3
// postRoll := true
if preRoll {
t, _ := marshallVmap()
vmaps = append(vmaps, t)
}
xml.MarshalIndent(vmaps, "", " ")
fmt.Printf(" %v", vmaps)
return []byte(vmaps), nil
}
func handleAdRequests(w http.ResponseWriter, r *http.Request) {
vmap, err := ad_queue.GenerateAndServeVmap(r)
if err != nil {
return
}
w.Header().Set("Content-Type", "application/xml")
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Write(vmap)
}
Update: I've since made some progress using the following method:
type Vmap struct {
XMLName xml.Name `xml:"vmap:VMAP"`
VmapAttr string `xml:"xmlns:vmap,attr"`
Version string `xml:"version,attr"`
AdBreaks []AdBreak `xmlns:"vmap,namespace"`
}
type AdBreak struct {
XMLName xml.Name `xml:"vmap:AdBreak"`
TimeOffset string `xml:"timeOffset,attr"`
BreakType string `xml:"breakType,attr"`
BreakId string `xml:"breakId,attr"`
AdSource AdSource `xmlns:"vmap,namespace"`
}
type AdSource struct {
XMLName xml.Name `xml:"vmap:AdSource"`
Id string `xml:"id,attr"`
AllowMultipleAds string `xml:"allowMultipleAds,attr"`
FollowRedirects string `xml:"followRedirects,attr"`
AdTagUri AdTagUri `xmlns:"vmap,namespace"`
}
type AdTagUri struct {
XMLName xml.Name `xml:"vmap:AdTagURI"`
TemplateType string `xml:"templateType,attr"`
Url string `xml:",innerxml"`
}
func GenerateAndServeVmap(r *http.Request) ([]byte, error) {
response := Vmap{
xml.Name{},
"http://www.iab.net/videosuite/vmap",
"1.0",
[]AdBreak{
{xml.Name{}, "start", "linear", "preroll",
AdSource{xml.Name{}, "preroll-ad-1", "false", "true",
AdTagUri{xml.Name{}, "vast3", "<![CDATA[ https://pubads.g.doubleclick.net/gampad/ads?slotname=/21775744923/external/vmap_ad_samples&sz=640x480&ciu_szs=300x250&cust_params=sample_ar%3Dpremidpostpod&url=&unviewed_position_start=1&output=xml_vast3&impl=s&env=vp&gdfp_req=1&ad_rule=0&useragent=Mozilla/5.0+(Windows+NT+10.0%3B+Win64%3B+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/103.0.0.0+Safari/537.36,gzip(gfe)&vad_type=linear&vpos=preroll&pod=1&ppos=1&lip=true&min_ad_duration=0&max_ad_duration=30000&vrid=1270234&cmsid=496&video_doc_id=short_onecue&kfa=0&tfcd=0 ]]>"},
},
},
{xml.Name{}, "00:00:15", "linear", "midroll-1",
AdSource{xml.Name{}, "midroll-1-ad-1", "false", "true",
AdTagUri{xml.Name{}, "vast3", "yup"},
},
},
},
}
x, err := xml.MarshalIndent(response, "", " ")
if err != nil {
return nil, err
}
return []byte(x), nil
}
func handleAdRequests(w http.ResponseWriter, r *http.Request) {
// log.Printf("%v", r)
origin := r.Header.Get("Origin")
supportedOrigins := []Origin{{"https://imasdk.googleapis.com"}, {"imasdk.googleapis.com"}, {"http://localhost:3000"}, {"localhost:3000"}}
match := false
for i := range supportedOrigins {
if supportedOrigins[i].Name == origin {
w.Header().Set("Access-Control-Allow-Origin", origin)
match = true
}
}
if match == false {
w.Header().Set("Access-Control-Allow-Origin", "*")
}
vmap, err := ad_queue.GenerateAndServeVmap(r)
if err != nil {
return
}
w.Header().Set("Content-Type", "application/xml")
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Write(vmap)
}