使用字符串模板生成代码

时间:2016-11-18 18:52:12

标签: stringtemplate stringtemplate-4

我正在尝试使用字符串模板来生成Pig / Hadoop代码。由于我是新手,我自己也无法弄清楚。任何帮助将不胜感激。

我有一个LocalDate列表,如下面的一个节目

List<LocalDate> dates = Arrays.asList("20100101", "20100102").stream().map(d -> LocalDate.parse(d,formatter)).collect(Collectors.toList());

该列表可以包含1个日期或许多日期。

如果列表&#34;日期&#34;包含多个元素,然后我想生成:

SPLIT finalizedEvents INTO splitByDay_20100101 IF dataDate == 20100101,
                  INTO splitByDay_20100102 IF dataDate == 20100102, ....; // for all date in "dates" list
// similarly for all dates
// formatting substitution variable e.g. 2010/01/01 instead of 20100101 is needed
STORE splitByDay_20100101 INTO '/a/b/2010/01/01' USING AvroStorage();
STORE splitByDay_20100102 INTO '/a/b/2010/01/02' USING AvroStorage();

如果列表&#34;日期&#34;只包含一个元素然后我想生成(假设日期= [20100101])

splitByDay_20100101 = FOREACH finalizedEvents GENERATE $0..;
STORE splitByDay_20100101 INTO '/a/b/2010/01/01' USING AvroStorage();

到目前为止,我已经做了类似以下的事情但不确定如何进行条件

ST e = new ST("SPLIT finalizedEvents INTO <[dates]:{ d | IF split_<d> BY daysSinceEpoch == <d>}; separator=\", \">;");
e.add("dates", dates);
System.out.println(e.render());

1 个答案:

答案 0 :(得分:0)

以下是我提出的问题(详细说明如下):

Java代码:

List<LocalDate> dates = new ArrayList<>();
dates.add(LocalDate.parse("20100101", DateTimeFormatter.BASIC_ISO_DATE));
dates.add(LocalDate.parse("20100201", DateTimeFormatter.BASIC_ISO_DATE));

List<List<Character>> charListList = new ArrayList<>();
for (LocalDate date : dates) {
    List<Character> charList = new ArrayList<>();
    char[] dateCharArray = date.toString().toCharArray();
    for (char c : dateCharArray) {
        charList.add(c);
    }
    charListList.add(charList);
}

STGroup dateGroup = new STGroupFile("./src/com/stackoverflow/DateList/dates.stg");
ST dateTemp = dateGroup.getInstanceOf("writeCode");
dateTemp.add("formattedDates", charListList);
dateTemp.add("isSingle", charListList.size() == 1);

System.out.println(dateTemp.render());


StringTemplate代码(dates.stg):

writeCode(formattedDates, isSingle) ::= <<
<if(isSingle)><writeSingleStuff(formattedDates)>
<else><writeMultipleStuff(formattedDates)>
<endif>
<writeStoreList(formattedDates)>
>>


writeSingleStuff(date)::= "<date:{d|splitByDay_<wordReplaceWSlash(d)> = FOREACH finalizedEvents GENERATE $0..;}>"

writeMultipleStuff(rawDates)::= "SPLIT finalizedEvents <rawDates:{d|INTO splitByDay_<wordReplaceWEmpty(d)> IF dataDate == <wordReplaceWEmpty(d)>}; separator=\", \">;"

writeStoreList(formattedDates)::= "<formattedDates:{d|STORE splitByDay_<wordReplaceWEmpty(d)> INTO '/a/b/<wordReplaceWSlash(d)>' USING AvroStorage();<\n>}>"


wordReplaceWSlash(word) ::= "<word:{char|<charReplaceWSlash(char)>}>"

charReplaceWSlash(theChar) ::= <%<charReplaceWSlashMap.(theChar)>%>

charReplaceWSlashMap ::= [
    "-":"/",
    default:{<theChar>}
]


wordReplaceWEmpty(word) ::= "<word:{char|<charReplaceWEmpty(char)>}>"

charReplaceWEmpty(theChar) ::= <%<charReplaceWEmptyMap.(theChar)>%>

charReplaceWEmptyMap ::= [
    "-":"",
    default:{<theChar>}
]


代码的作用:

Java代码:

List<LocalDate> dates = new ArrayList<>();
dates.add(LocalDate.parse("20100101", DateTimeFormatter.BASIC_ISO_DATE));
dates.add(LocalDate.parse("20100201", DateTimeFormatter.BASIC_ISO_DATE));

这是一个包含LocalDates的列表,我们希望将其用作模板的输入。我用DateTimeFormatter.BASIC_ISO_DATE对它们进行了格式化,例如20100101变为2010-01-01。我们稍后需要这个,因为我们将告诉StringTemplate将-替换为/或空字符串以获取我们想要的两种类型的日期格式(我没有找到获取{的格式化程序{1}}首先) 两种不同的方法是:

  • 在Java代码中将2010/01/01替换为-,而不是在StringTemplate中。然后,如果我们需要这种日期格式,我们只需要用空字符串替换/
  • 将年,月,日三个不同的变量添加到模板中。然后我们可以连接字符串并在需要时添加/


/

我们不得不这样做,但是:
我们必须有一个日期字符的列表(和不是数组),以便我们可以在StringTemplate中“迭代”它。还有no direct way将char []转换为List。最后,我们必须将所有这些列表放在一个列表中,以便我们可以为每个日期生成代码(List<List<Character>> charListList = new ArrayList<>(); for (LocalDate date : dates) { List<Character> charList = new ArrayList<>(); char[] dateCharArray = date.toString().toCharArray(); for (char c : dateCharArray) { charList.add(c); } charListList.add(charList); } )。


charListList

这里我们用值填充模板。我们必须告诉StringTemplate here 我们的STGroup dateGroup = new STGroupFile("./src/com/stackoverflow/DateList/dates.stg"); ST dateTemp = dateGroup.getInstanceOf("writeCode"); dateTemp.add("formattedDates", charListList); dateTemp.add("isSingle", charListList.size() == 1); System.out.println(dateTemp.render()); 中是否只有一个日期,因为StringTemplate是(by design)无法这样做。


StringTemplateCode:

charListList

这是“根”模板,基本上只是将工作委托给其他模板。它处理一个或多个日期之间的案件干扰。


writeCode(formattedDates, isSingle) ::= <<
<if(isSingle)><writeSingleStuff(formattedDates)>
<else><writeMultipleStuff(formattedDates)>
<endif>
<writeStoreList(formattedDates)>
>>

通过这三行,我们编写了特定于单个项目的代码,多个项目以及两者具有共同点的代码。
虽然我们知道writeSingleStuff(date)::= "<date:{d|splitByDay_<wordReplaceWSlash(d)> = FOREACH finalizedEvents GENERATE $0..;}>" writeMultipleStuff(rawDates)::= "SPLIT finalizedEvents <rawDates:{d|INTO splitByDay_<wordReplaceWEmpty(d)> IF dataDate == <wordReplaceWEmpty(d)>}; separator=\", \">;" writeStoreList(dates)::= "<dates:{d|STORE splitByDay_<wordReplaceWEmpty(d)> INTO '/a/b/<wordReplaceWSlash(d)>' USING AvroStorage();<\n>}>" 在我们输入date时只有一个项目,但我们必须遍历列表。


writeSingleStuff

这两组模板几乎完全相同:用wordReplaceWSlash(word) ::= "<word:{char|<charReplaceWSlash(char)>}>" charReplaceWSlash(theChar) ::= <%<charReplaceWSlashMap.(theChar)>%> charReplaceWSlashMap ::= [ "-":"/", default:{<theChar>} ] wordReplaceWEmpty(word) ::= "<word:{char|<charReplaceWEmpty(char)>}>" charReplaceWEmpty(theChar) ::= <%<charReplaceWEmptyMap.(theChar)>%> charReplaceWEmptyMap ::= [ "-":"", default:{<theChar>} ] 或空字符串替换每个“单词”中的每个-个字符。我们使用一个小字典来替换除/之外的所有字符。