Brian Voelker
Brian Voelker

Reputation: 859

Dynamically parsing files

For parsing files i have setup a variable for template.ParseFiles and i currently have to manually set each file.

Two things:

How would i be able to walk through a main folder and a multitude of subfolders and automatically add them to ParseFiles so i dont have to manually add each file individually?

How would i be able to call a file with the same name in a subfolder because currently I get an error at runtime if i add same name file in ParseFiles.

var templates = template.Must(template.ParseFiles(
    "index.html", // main file
    "subfolder/index.html" // subfolder with same filename errors on runtime
    "includes/header.html", "includes/footer.html",
))


func main() {
    // Walk and ParseFiles
    filepath.Walk("files", func(path string, info os.FileInfo, err error) {
        if !info.IsDir() {
            // Add path to ParseFiles


        }
        return
    })

    http.HandleFunc("/", home)
    http.ListenAndServe(":8080", nil)
}

func home(w http.ResponseWriter, r *http.Request) {
    render(w, "index.html")
}

func render(w http.ResponseWriter, tmpl string) {
    err := templates.ExecuteTemplate(w, tmpl, nil)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

Upvotes: 2

Views: 5112

Answers (2)

Brian Voelker
Brian Voelker

Reputation: 859

So basically i set New("path name i want").Parse("String from read file") while walking through the folders.

var templates = template.New("temp")

func main() {
    // Walk and ParseFiles
    parseFiles()

    http.HandleFunc("/", home)
    http.ListenAndServe(":8080", nil)
}

//////////////////////
// Handle Functions //
//////////////////////
func home(w http.ResponseWriter, r *http.Request) {
    render(w, "index.html")
    render(w, "subfolder/index.html")
}

////////////////////////
// Reusable functions //
////////////////////////
func parseFiles() {
    filepath.Walk("files", func(path string, info os.FileInfo, err error) error {
        if !info.IsDir() {
            filetext, err := ioutil.ReadFile(path)
        if err != nil {
                return err
        }
        text := string(filetext)
            templates.New(path).Parse(text)
        }
        return nil
    })
}

func render(w http.ResponseWriter, tmpl string) {
    err := templates.ExecuteTemplate(w, tmpl, nil)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}

Upvotes: 0

Jeremy Wall
Jeremy Wall

Reputation: 25275

To walk a directory looking for files see: http://golang.org/pkg/path/filepath/#Walk or http://golang.org/pkg/html/template/#New and http://golang.org/pkg/html/template/#Template.Parse

As for your other question ParseFiles uses the base name of the file as the template name which results in a collision in your template. You have two choices

  1. Rename the file.
  2. use t := template.New("name of your choice") to create an initial template
    1. Use the walk function you already have started and call t.Parse("text from file") for each template file. You'll have to open and read the contents of the template files yourself to pass in here.

Edit: Code example.

func main() {
    // Walk and ParseFiles
    t = template.New("my template name")
    filepath.Walk("files", func(path string, info os.FileInfo, err error) {
        if !info.IsDir() {
            // Add path to ParseFiles
            content := ""
            // read the file into content here
            t.Parse(content)
        }
        return
    })

    http.HandleFunc("/", home)
    http.ListenAndServe(":8080", nil)
}

Upvotes: 4

Related Questions