Original post

Hi everyone,

I’m new to , and so far I’m loving it!

I’ve got a real-life work project that I use to learn the language, and within the last 2 days I’ve learned a ton of new stuff. I’m, however, struggling with a specific subject; unmarshaling a custom time attribute from XML files. So far, I’ve implemented the following:

type Program struct {
    ...
        Timestamp     customTime `xml:"timestamp,attr"`
    ...
}

type customTime struct {
        Timestamp time.Time
}

func (c *customTime) UnmarshalXMLAttr(attr xml.Attr) error {
        date := attr.Value + " CET"
        parse, _ := time.Parse("2006-01-02T15:04:05 MST", date)
        *c = customTime{parse}
        return nil
}

This kind of works, however, this saved the Timestamp as an object in MongoDB:

_id: ObjectId(235235235235)
timestamp: Object
  timestamp: 2020-02-04T17:46:37.000+00:00

This all makes sense, but I don’t want that object, I just want the timestamp as the value of the first timestamp. I’ve been reading a lot, but I can’t find the documentation I need to achieve this.

Help would be appreciated!

Kind regards,
Derk

Hey Derk!

I’m a beginner in Go too, so I may not be as helpful as I’d like to be, but I think I have an idea that could help.

Instead of making your customTime a struct, if you just made it a time.Time, maybe that would remove the extra wrapping object when you’re storing it in MongoDB.

I’m thinking something like this

type Program struct {
        Timestamp customTime `xml:"timestamp,attr"`
}

type customTime time.Time

func (c *customTime) UnmarshalXMLAttr(attr xml.Attr) error {
        date := attr.Value
        fmt.Println("DATE", date)
        location, _ := time.LoadLocation("MST")
        parse, err := time.ParseInLocation("2006-01-02", date, location)
        if err != nil {
                panic(err)
        }
        fmt.Println("PARSE", parse)
        *c = customTime(parse)
        return nil
}

func main() {
        testXML := []byte(`<Program timestamp="2021-05-15"></Program>`)

        var v Program
        if err := xml.Unmarshal(testXML, &v); err != nil {
                panic(err)
        }

        fmt.Println(v.Timestamp)
}

Thank you for your time and reply!

I’ve tried that as well (after making this post), and I think that puts me on the right track. However, it outputs as (note v.Timestamp):

DATE 2021-05-15
PARSE 2021-05-15 00:00:00 -0700 MST
{0 63756658800 0xc000052240}

I think it’s a pointer thing, but coming from Python and Javascript pointers are new to me (if it’s a pointer thing at all).

Hi, Derk,

Your XML unmarshaling looks right. How are you using your customTime type when you’re saving to Mongo?

Hi Sean,

I’m passing the reference of the unmarshalled struct:

package main

import (
        "context"
        "encoding/xml"
        "fmt"
        "go.mongodb.org/mongo-driver/mongo"
        "go.mongodb.org/mongo-driver/mongo/options"
        "io/ioutil"
        "log"
        "time"
)

type Program struct {
        Guci    string `xml:"guci"`
        Prid string `xml:"prid"`
        Pridexport    string `xml:"pridexport"`
        Titel    string `xml:"titel"`
        Wsrid    string `xml:"wsrid"`
        Type    string `xml:"type"`
        Platform    string `xml:"platform"`
        Puboptie    string `xml:"puboptie"`
        Videofile    string `xml:"videofile"`
        Timestamp     customTime `xml:"timestamp,attr"`
}

type customTime struct {
        Timestamp time.Time
}

func (c *customTime) UnmarshalXMLAttr(attr xml.Attr) error {
        date := attr.Value + " CET"
        parse, _ := time.Parse("2006-01-02T15:04:05 MST", date)
        *c = customTime{parse}
        return nil
}


func main() {
        client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"))
        ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
        err = client.Connect(ctx)
        collection := client.Database("scooter").Collection("Programs")

        files, err := ioutil.ReadDir("xmls/")
        if err != nil {log.Fatal(err)}

        for _, file := range files {
                data, err := ioutil.ReadFile("xmls/" + file.Name())
                if err != nil {log.Fatal(err)}

                program :=  &Program{}

                _ = xml.Unmarshal([]byte(data), &program)

                fmt.Println(*program)

                _, err = collection.InsertOne(ctx, *program)
                if err != nil {log.Fatal(err)}
        }
}

This is the entire main.go file I’m using right now

EDIT:

Of it works to insert it like this, but it feels redundant. I think I should be able to pass-in the whole struct:

           _, err = collection.InsertOne(ctx, bson.M{
                        "guci": program.Guci,
                        "prid": program.Prid,
                        "pridexport": program.Pridexport,
                        "titel": program.Titel,
                        "wsrid": program.Wsrid,
                        "type": program.Type,
                        "platform": program.Platform,
                        "puboptie": program.Puboptie,
                        "videofile": program.Videofile,
                        "timestamp": program.Timestamp.Timestamp,
                })

Eventually I went with:

                     _, err = collection.InsertOne(ctx, bson.M{
                        "guci":       notifyXml.Guci,
                        "prid":       notifyXml.Prid,
                        "pridexport": notifyXml.Pridexport,
                        "titel":      notifyXml.Titel,
                        "wsrid":      notifyXml.Wsrid,
                        "type":       notifyXml.Type,
                        "platform":   notifyXml.Platform,
                        "puboptie": append(pubSlice, PubOptie{
                                Puboptie:  notifyXml.Puboptie,
                                Videofile: notifyXml.Videofile,
                                CreatedAt: time.Now(),
                        }),
                        "timestamp": notifyXml.Timestamp.Timestamp,
                        "starttijd": notifyXml.Timestamp.Timestamp,
                        "eindtijd":  notifyXml.Timestamp.Timestamp.AddDate(0, 0, 7),
                        "createdAt": time.Now(),
                        "updatedAt": time.Now(),
                })

I had to do some actions like time.Now() stuff anyway so this works :slight_smile:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.