Filling out the form fields in docx using golang library unioffice - go

I'm trying to fill out the form fields using unioffice library. The document that i'm working with, contains several paragraphs. The paragraphs contains several form fields.
I want to fill out all of the form fields in the document. And here is the code i'm running:
doc, err := document.Open("form.docx")
if err != nil {
log.Fatalf("error opening form: %s", err)
}
for i := range doc.FormFields() {
doc.FormFields()[i].SetValue("test")
}
doc.SaveToFile("filled-form.docx")
However, not all of the form fields were filled out.

Looks to me like a bug in func (d *Document) Save(w io.Writer) error{}. I can read and write to every of the FormFields but only the last FormField value in the paragraph gets actually saved to the file.
Below code works like expected until you save to file. (That means it prints out the previously set value). I saw you already opened a new issue on github (link) i hope you have more luck with that.
package main
import (
"github.com/unidoc/unioffice/document"
"io/ioutil"
"log"
"os"
)
func main() {
_, err := ioutil.ReadFile("filled-form.docx")
if err == nil {
err = os.Remove("filled-form.docx")
if err != nil {
log.Fatal(err)
}
}
doc, err := document.Open("form.docx")
if err != nil {
log.Fatalf("error opening form: %s", err)
}
for _, f := range doc.FormFields() {
if f.Type() == document.FormFieldType(1) {
f.SetValue("test")
}
}
for _, f := range doc.FormFields() {
log.Println("-------------------")
log.Println(f.Name())
log.Println(f.Value())
}
err = doc.SaveToFile("filled-form.docx")
if err != nil {
log.Fatal(err)
}
}

Related

How to get the git tags for a particular hash in go using go-git package to get an output similar to git describe --tags --always

I am using the go-git package to get the tags, on using the function "TagObject", it is returning null.
How should I write it?
Actual file:
hashCommit, _ := r.Head()
tagObj, _ := r.TagObject(hashCommit.Hash())
Test file:
tags, err := testAppDir.Tags()
h.AssertNil(t, err)
tags.ForEach(func(t *plumbing.Reference) error {
fmt.Println("the tag inside test", t)
return nil
})
How do I get the tags in my actual file?
Error:
- "describe": string(""),
+ "describe": (*object.Tag)(nil)
I think this will work for that particular case.
Since tags have a reference to the commit they tagged but there is no reference back, the getTags function returns a map that inverts that relation and allows us to find the tag that is attached to a commit (note that it is assumed that there is only one tag for a commit which may not be true).
We then take that map and see if the head has a tag and if so print it. Otherwise we'll go through the log starting on the head and searching for the first tagged commit. If we find any we'll print the tag and a short version of the commit (there doesn't seem to be a method to get a reliable short hash so I took the first 8 chars)
Finally if nothing is found the short hash is printed using the method described before.
This is a naive implementation that may have problems with repositories with a large amount of tags.
Please note that I used an updated version of go-git.
package main
import (
"errors"
"fmt"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"io"
"log"
)
func getTags(r *git.Repository) (map[plumbing.Hash]string, error) {
tags := make(map[plumbing.Hash]string)
iter, err := r.Tags()
if err != nil {
return nil, err
}
for {
ref, err := iter.Next()
if errors.Is(err, io.EOF) {
break
}
if err != nil{
return nil, err
}
tags[ref.Hash()] = ref.Name().Short()
}
return tags, nil
}
func main() {
appPath := ""
r, err := git.PlainOpen(appPath)
if err != nil {
log.Fatal(err)
}
hashCommit, err := r.Head()
if err != nil {
log.Fatal("head", err)
}
fmt.Println("hash", hashCommit)
tags, err := getTags(r)
// check if last commit is tagged
if str, ok := tags[hashCommit.Hash()]; ok {
fmt.Println(str)
return
}
// check if any commit is tagged
cIter, err := r.Log(&git.LogOptions{From: hashCommit.Hash()})
for {
commit, err := cIter.Next()
if errors.Is(err, io.EOF) {
break
}
if err != nil{
log.Fatal(err)
}
if str, ok := tags[commit.Hash]; ok {
fmt.Printf("%s-%s\n", str, hashCommit.Hash().String()[:8])
return
}
}
fmt.Println(hashCommit.Hash().String()[:8])
}

Can I read Google Sheet as CSV file

Using Go language, is there a way that I can read the date saved at GoolgeSheets as CSV file, without downloading offline copy of the file?
Yes, this is possible, with the below steps:
In Googlesheets:
Publish the sheet under consideration as csv file, using File -> Publish to the web, make sure to select the option "Automatically republish when changes are made"
Copy the link provided by googleSheets for the csv connectivity
In Go lang
Use the below code:
// file main.go
package main
import (
"encoding/csv"
"fmt"
"net/http"
)
func readCSVFromURL(url string) ([][]string, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
reader := csv.NewReader(resp.Body)
reader.Comma = ','
data, err := reader.ReadAll()
if err != nil {
return nil, err
}
return data, nil
}
func main() {
url := "https://docs.google.com/spreadsheets/d/e/xxxxxsingle=true&output=csv"
data, err := readCSVFromURL(url)
if err != nil {
panic(err)
}
for idx, row := range data {
// skip header
if idx == 0 {
continue
}
if idx == 6 {
break
}
fmt.Println(row[2])
}
}

Receiving an empty map with no errors when trying to unmarshal a string read from a file (Answer: unmarshal into the data structure itself)

I have a file, 'test.txt', containing the following data. This file was created from the same structures from the code below using marshaling.
{"VLETXGJM":{"attrib1":"test1","attrib2":"test2"}}
I am trying to read it back from the file and unmarshal it into a map using the same structures. I can successfully read the data from the file. I receive no errors when I try to unmarshal it into the map. However, my map is empty.
The mutex is used to protect the map since my real implementation (this is an extracted test) needs to use a protected map for concurrency. I have tried this same code removing the sync library and received the same negative result.
The test code:
package main
import (
"encoding/json"
"fmt"
"sync"
"os"
)
type TestObject struct {
Attrib1 string `json:"attrib1"`
Attrib2 string `json:"attrib2"`
}
type TestMap map[string]TestObject
type TestList struct {
sync.RWMutex
list TestMap
}
func main() {
tl := TestList{ list: make(TestMap) }
// Read the list back out of the file
fi, err := os.Open("test.txt")
if os.IsNotExist(err) {
fmt.Println("data file does not exist")
panic(nil)
}
if err != nil {
panic(err)
}
defer func() {
if err := fi.Close(); err != nil {
panic(err)
}
}()
data := make([]byte, 1024 * 1024)
count, err := fi.Read(data)
if err != nil {
panic(err)
}
fmt.Printf("read from file: \"%s\"\n",data[:count])
tl.Lock()
err = json.Unmarshal(data[:count], &tl)
if err != nil {
panic(err)
}
tl.Unlock()
// List it out
tl.Lock()
if len(tl.list) == 0 {
fmt.Println("Empty list")
} else {
for key, _ := range tl.list {
fmt.Printf("%s: %s\n", tl.list[key].Attrib1, tl.list[key].Attrib2)
}
}
tl.Unlock()
}
The output of the run is:
read from file: "{"VLETXGJM":{"attrib1":"test1","attrib2":"test2"}}"
Empty list
Thank you for your help. I have searched for similar issues and not yet found an exact duplicate of this scenario.
I think you want to unmarshal into tl.list instead of tl:
err = json.Unmarshal(data[:count], &tl.list)
tl has no exported fields, so Unmarshal into tl won't do anything. tl.list (i.e., type TestMap) matches your data.

How can I check for an element is present in the page using golang knq/chromedp

I am creating an app to using [chromedp][1]
How can I check for an element is present in the page?
I tried to use cdp.WaitVisible() but it didn't give me what I wanted.
I need this so I can make dictions if the application will do one thing or the other.
For this example, suppose I need to know if the search input is present or not
How can I do that?
[1]: https://github.com/knq/chromedp
package main
import (
"context"
"fmt"
"io/ioutil"
"log"
"time"
cdp "github.com/knq/chromedp"
cdptypes "github.com/knq/chromedp/cdp"
)
func main() {
var err error
// create context
ctxt, cancel := context.WithCancel(context.Background())
defer cancel()
// create chrome instance
c, err := cdp.New(ctxt, cdp.WithLog(log.Printf))
if err != nil {
log.Fatal(err)
}
// run task list
var site, res string
err = c.Run(ctxt, googleSearch("site:brank.as", "Easy Money Management", &site, &res))
if err != nil {
log.Fatal(err)
}
// shutdown chrome
err = c.Shutdown(ctxt)
if err != nil {
log.Fatal(err)
}
// wait for chrome to finish
err = c.Wait()
if err != nil {
log.Fatal(err)
}
log.Printf("saved screenshot of #testimonials from search result listing `%s` (%s)", res, site)
}
func googleSearch(q, text string, site, res *string) cdp.Tasks {
var buf []byte
sel := fmt.Sprintf(`//a[text()[contains(., '%s')]]`, text)
return cdp.Tasks{
cdp.Navigate(`https://www.google.com`),
cdp.Sleep(2 * time.Second),
cdp.WaitVisible(`#hplogo`, cdp.ByID),
cdp.SendKeys(`#lst-ib`, q+"\n", cdp.ByID),
cdp.WaitVisible(`#res`, cdp.ByID),
cdp.Text(sel, res),
cdp.Click(sel),
cdp.Sleep(2 * time.Second),
cdp.WaitVisible(`#footer`, cdp.ByQuery),
cdp.WaitNotVisible(`div.v-middle > div.la-ball-clip-rotate`, cdp.ByQuery),
cdp.Location(site),
cdp.Screenshot(`#testimonials`, &buf, cdp.ByID),
cdp.ActionFunc(func(context.Context, cdptypes.Handler) error {
return ioutil.WriteFile("testimonials.png", buf, 0644)
}),
}
}
Here is my answer.
The web page is www.google.co.in. The element used is lst-ib, Text box present on the page.
Navigate the page.
Wait until the element is visible.
Read the value of the element. This is first time page is being loaded so obviously value will be "".
Assume, you have modified the value of the element by typing in the text box. Now, if we try to read the value of the same element lst-ib then we should get the updated value.
My code is below,
package main
import (
"context"
"log"
cdp "github.com/knq/chromedp"
)
func main() {
var err error
// create context
ctxt, cancel := context.WithCancel(context.Background())
defer cancel()
// create chrome instance
c, err := cdp.New(ctxt)
if err != nil {
log.Fatal(err)
}
// run task list
var res, value, newValue string
err = c.Run(ctxt, text(&res, &value, &newValue))
if err != nil {
log.Fatal(err)
}
// shutdown chrome
err = c.Shutdown(ctxt)
if err != nil {
log.Fatal(err)
}
// wait for chrome to finish
err = c.Wait()
if err != nil {
log.Fatal(err)
}
if len(value) > 1 {
log.Println("Search Input is present.")
} else {
log.Println("Search Input is NOT present.")
}
log.Println("New updated value: ", newValue);
}
func text(res, value, newValue *string) cdp.Tasks {
return cdp.Tasks{
cdp.Navigate(`https://www.google.co.in`),
cdp.WaitVisible(`lst-ib`, cdp.ByID),
cdp.EvaluateAsDevTools("document.getElementById('lst-ib').value", value),
cdp.EvaluateAsDevTools("document.getElementById('lst-ib').value='Hello';document.getElementById('lst-ib').value", newValue),
}
}
To run code use go run <FileName>.go
I am getting following output which was expected:
$ go run main.go
2017/09/28 20:05:20 Search Input is NOT present.
2017/09/28 20:05:20 New updated value: Hello
NOTE:
First I checked with Google Chrome Developer Tools to get exact Javascripts for my need. It helps a lot.
I have added the screenshot of the Javascript I tried on Chrome Developer Tools.
I hope it helps you. :)

os.Create and os.Open not working with gomobile and react native

package component
import (
"encoding/json"
"io/ioutil"
"os"
)
type LastComponent struct {
Name string
}
const fname = "componentfiles"
func Persist(comp string) string {
lcomp := LastComponent{Name: comp}
b, err := json.Marshal(lcomp)
if err != nil {
return "err-MARSHAL"
}
file, err := os.Create(fname)
if err != nil {
return "err-CREATE-FILE"
}
defer file.Close()
_, err = file.Write(b)
if err != nil {
return "err-FILE-WRITE-PROB"
}
return ""
}
func Component() string {
f, err := os.Open(fname)
if err != nil {
return "err-FILE-NOT-OPEN"
}
defer f.Close()
b, err := ioutil.ReadAll(f)
if err != nil {
return ""
}
var v LastComponent
json.Unmarshal(b, v)
return v.Name
}
}
The code above works fine and so does the javascript side of code. I keep receiving err-CREATE-FILE inside my javascript. So os.Create and os.Open are not working as expected.
Although it is an internal storage, permissions are not required, but I also turned on the permissions in manifest file, but with no avail.
What could be the correct way to Open and Create files in android using gomobile when using along side React Native?
Update:
In adb logcat, I keep getting this all over the place
E/Vold ( 276): Failed to find mounted volume for /storage/sdcard1/Android/data/com.gotest/cache/
So you should have some success if you pass this in as a parameter - something like the following is working for me:
go:
func Component(folderPath string) string {
f, err := os.Open(path.Join(folderPath, fname))
...
Java:
Component.Component(getApplicationContext().getFilesDir().getAbsolutePath())
Alternatively, you could use something like getExternalStorageDirectory().getAbsolutePath(). They key is that you need to get somewhere storagewise that is writable by your process/user.

Resources