模拟小胡子/把手:从模板html中找出上下文数据结构

时间:2014-10-28 06:53:35

标签: javascript templates handlebars.js mustache

在js中的mustache / handlerbars或任何模板系统中, 是否有任何工具来收集模板引用的所有变量?

例如,给定输入

templateHTML:

<div class="{{divclass}}">
  {#item}}
    <h1>{{title}}</h1>
    <span>{{text}}</span>
  {{/item}}
</div>

将返回

{ 
  divclass: "",
  item: { 
    title: "",
    text: ""
  }
}

使用时像MyTemplateTool.getTemplateData(templateHTML)

我尝试使用谷歌搜索并查看了车把文档,但找不到合适的内容

2 个答案:

答案 0 :(得分:0)

我相信它只是.。请参阅相关的docs on paths。例如:

{{#srcs}}
  <script src="{{.}}"></script>
{{/srcs}}

答案 1 :(得分:0)

我心中也有同样的想法,我觉得写东西是值得的,所以你去了:

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MustacheSchemaBuilder
{
    static String javaIdentifierRegExp = "[a-zA-Z_$0-9]+";
    static String tab = "    ";
    static Format format = Format.java;

    enum Format {
        json,
        java,
        ;
    }

    enum TagType {
        variable("\\{\\{\\s*" + javaIdentifierRegExp + "\\s*\\}\\}"),
        escapedVariable("\\{\\{\\{\\s*" + javaIdentifierRegExp + "\\s*\\}\\}\\}"),
        sectionStart("\\{\\{#\\s*" + javaIdentifierRegExp + "\\s*\\}\\}"),
        invertedSectionStart("\\{\\{\\^\\s*" + javaIdentifierRegExp + "\\s*\\}\\}"),
        sectionEnd("\\{\\{/\\s*" + javaIdentifierRegExp + "\\s*\\}\\}"),
        //partial("\\{\\{>\\s*" + javaIdentifierRegExp + "\\s*\\}\\}"),
        // no support for set delimiters or partials
        ;

        Pattern pat; 
        private TagType(String aRegExp) {
            pat = Pattern.compile(aRegExp);
        }

        public Pattern getPattern() { return pat; };
    }

    class Tag{
        public TagType type;
        public String identifier;
        Tag(TagType aType, String aIdentifier) { type = aType; identifier = aIdentifier;}

        public String toString() { return type.name() + " : " + identifier; }

        @Override
        public boolean equals(Object aOther) {
            if(!(aOther instanceof Tag)) return false;
            Tag ot = (Tag) aOther;
            return ot.type.equals(this.type) && ot.identifier.equals(this.identifier);
        }

        @Override
        public int hashCode() {return identifier.hashCode();}
    }

    class Node {
        public Section parent;
        public Tag tag;
        Node(Section aParent, Tag aTag){parent = aParent; tag = aTag; if(parent != null) parent.children.put(tag, this);}

        @Override
        public int hashCode() {return tag.hashCode();}

        public int depth() {
            int depth = 0;
            Node currentNode = this;
            while(currentNode.parent != null) {
                depth++;
                currentNode = currentNode.parent;
            }
            return depth;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            for(int i = 0; i < this.depth(); i++) sb.append(tab);
            switch(format) {
            case java:
                sb.append("public Object ").append(tag.identifier).append(";\n");
                break;
            case json:
            default:
                sb.append(tag.identifier).append(": {},\n");
            }
            return sb.toString();
        }
    }

    class Section extends Node{
        public Map<Tag, Node> children = new LinkedHashMap();
        Section(Section aParent, Tag aTag) { super(aParent, aTag); };

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            for(int i = 0; i < this.depth(); i++) sb.append(tab);
            switch(format) {
            case java:
                sb.append("public Object ").append(tag.identifier).append(" = new Object() {\n");
                for(Node child : this.children.values()) sb.append(child);
                for(int i = 0; i < this.depth(); i++) sb.append(tab);
                sb.append("};\n");
                break;
            case json:
            default:
                sb.append(tag.identifier).append(": {\n");
                for(Node child : this.children.values()) sb.append(child);
                for(int i = 0; i < this.depth(); i++) sb.append(tab);
                sb.append("},\n");
            }
            return sb.toString();
        }
    }

    class MustacheSchemaBuildException extends Exception {
        private static final long serialVersionUID = 1L;
        MustacheSchemaBuildException(String aMessage) {super(aMessage);}
    }

    Section rootSection;

    public MustacheSchemaBuilder(String aContents) throws Exception
    {
        TreeMap<Integer, Tag> tagMap = new TreeMap();
        for(TagType type : TagType.values()) {
            populateMap(tagMap, type, aContents);
        }
        System.out.println(tagMap);

        rootSection = new Section(null, new Tag(TagType.sectionStart, "$root$"));
        Section currentSection = rootSection;

        for(Tag tag : tagMap.values()) {
            if(currentSection.tag.type == TagType.invertedSectionStart) {
                if(tag.type == TagType.sectionEnd) {
                    if(!tag.identifier.equals(currentSection.tag.identifier))
                        throw new MustacheSchemaBuildException("The end tag: " + tag.identifier + " doesn't match the expected start tag: " + currentSection.tag.identifier + "\n\n" + rootSection);
                    currentSection = currentSection.parent;
                }
                continue;
            }
            switch(tag.type)
            {
            case variable:
                if(!currentSection.children.containsKey(tag))
                    new Node(currentSection, tag);
                break;
            case sectionStart:
                Tag invertedSectionStartTag = new Tag(TagType.invertedSectionStart, tag.identifier);
                if(!(currentSection.children.containsKey(tag) || currentSection.children.containsKey(invertedSectionStartTag))) 
                    new Section(currentSection, tag);
                currentSection = (Section)currentSection.children.get(tag);
                break;
            case invertedSectionStart:
                Tag sectionStartTag = new Tag(TagType.sectionStart, tag.identifier);
                if(!(currentSection.children.containsKey(tag) || currentSection.children.containsKey(sectionStartTag)))
                    new Section(currentSection, tag);
                currentSection = (Section)currentSection.children.get(sectionStartTag);
                break;
            case sectionEnd:
                if(!tag.identifier.equals(currentSection.tag.identifier))
                    throw new MustacheSchemaBuildException("The end tag: " + tag.identifier + " doesn't match the expected start tag: " + currentSection.tag.identifier + "\n\n" + rootSection);
                currentSection = currentSection.parent;
                break;
            default:
            }
        }
    }

    public void build() {
        System.out.println(rootSection);
    }

    public static void main(String[] args) throws Exception
    {
        String contents;
        try {
            contents = readFile(args[0], Charset.defaultCharset());

        }catch(Exception e)
        {
            System.out.println("Unable to open file!");
            throw e;
        }

        MustacheSchemaBuilder builder = new MustacheSchemaBuilder(contents);

        builder.build();
    }

    void populateMap(Map<Integer, Tag> map, TagType aType, String aContents) {
        Matcher m = aType.getPattern().matcher(aContents);
        while(m.find()) {
            int start = m.start() + 3;
            if(aType == TagType.variable) start = m.start() + 2;
            map.put(m.start(), new Tag(aType, aContents.substring(start, m.end() - 2).trim()));
        }
    }

    static String readFile(String path, Charset encoding) throws IOException 
    {
      byte[] encoded = Files.readAllBytes(Paths.get(path));
      return new String(encoded, encoding);
    }
}

在命令行中提供模板文件路径 - 您需要使用java 7或更高版本来打开文件,或者您只需重写readFile - 方法。您可以通过更改类顶部的格式来生成json或java“模式”。 'schema'被写入stdout,你可以从那里复制它并将其粘贴到你需要的地方。希望这可以帮助。啊!这不支持partials或set delimiters,但是如果你开始写支持ping我就像我想要的那样:)