GO: html / template 를 통 해 include 서브 템 플 릿 실현

3222 단어
liquid 지원 라 이브 러 리 를 도입 하지 않 고 기 존의 html / template 를 통 해 include 서브 템 플 릿 기능 을 지원 합 니 다.
생각:
  • Django 를 모방 하여 템 플 릿 폴 더 에서 템 플 릿 을 읽 습 니 다. 이미 가 져 온 템 플 릿 은 map 구조의 간단 한 cache 에 캐 시
  • 를 추가 합 니 다.
  • 정규 표현 식 을 이용 하여 템 플 릿 에서 {% include xxx%} 을 발 견 했 을 때 현재 템 플 릿 에 파일 로 재 귀적 으로 불 러 옵 니 다. 불 러 오 는 데 실 패 했 을 경우 (파일 이 존재 하지 않 는 등) 그대로 유지 합 니 다
  • html / template 를 이용 하여 변수 등의 불 러 오기
  • 형식 을 정할 때 {{}} 을 사용 할 수 없습니다. template 는 지원 하 는 명령 이 라 고 생각 하기 때문에 두 번 째 단계 에서 불 러 오 는 데 실패 하면 그대로 template parser 에 전 달 됩 니 다.
    또한 관찰 치 를 설정 하여 재 귀적 include 를 진행 할 때 재 귀적 으로 자신 을 포함 하 는 순환 이 나타 나 지 않도록 해 야 합 니 다.
    코드 구현:
    func RenderWithTemplate(writer io.Writer, templateName string, data map[string]interface{}) error {
        rawTemplate, err := LoadTemplate(templateName)
        if err != nil {
            return err
        }
        tmpl, err := template.New("new").Parse(rawTemplate)
        if err != nil {
            return err
        }
        return tmpl.Execute(writer, data)
    }
    
    var TemplateCache map[string]string = nil
    var gRecursiveLoadTemplateCount = 0
    // Load template with file name templateName under 'templates' dir
    // If it contains {% include xxx %}, it will load content of that
    // template into current template.
    // **Note**: template name inside include directive should not be wrapped with ''
    func LoadTemplate(templateName string) (string, error) {
        if result, ok := TemplateCache[templateName]; ok {
            return result, nil
        }
    
        templatePath := "templates/" + templateName
        file, err := os.Open(templatePath)
        if err != nil {
            return "", err
        }
    
        stat, err := file.Stat()
        if err != nil {
            return "", err
        }
    
        buffer := make([]byte, stat.Size())
        _, err = file.Read(buffer)
        if TemplateCache == nil {
            TemplateCache = make(map[string]string)
        }
        rawTemplate := string(buffer)
        re := regexp.MustCompile("{%\\s*include\\s+(.*?)\\s*%}")
        matches := re.FindAllStringSubmatchIndex(rawTemplate, -1)
        if len(matches) > 0 {
            newTemplate := ""
            start := 0
            for _, m := range matches {
                if len(m) == 4 {
                    newTemplate += rawTemplate[start:m[0]]
                    includeName := rawTemplate[m[2]:m[3]]
    
                    gRecursiveLoadTemplateCount ++
                    if gRecursiveLoadTemplateCount > 10 {
                        log.Fatal("Possible dead include loop in file: ", templateName)
                    }
                    includedTemplate, err := LoadTemplate(includeName)
                    gRecursiveLoadTemplateCount --
    
                    if err != nil {
                        fmt.Println("Failed to include file ", includeName, " from ", templateName, "err:", err)
                        includedTemplate = rawTemplate[m[0]:m[1]]  // Keep it as original
                    }
                    start = m[1]
                    newTemplate += includedTemplate
                }
            }
            if start < len(rawTemplate) {
                newTemplate += rawTemplate[start:]
            }
            rawTemplate = newTemplate
        }
        TemplateCache[templateName] = rawTemplate
        return rawTemplate, nil
    }
    

    좋은 웹페이지 즐겨찾기