hubspot / jinjava Goto Github PK
View Code? Open in Web Editor NEWJinja template engine for Java
License: Apache License 2.0
Jinja template engine for Java
License: Apache License 2.0
In http://product.hubspot.com/blog/jinjava-a-jinja-for-your-java the author says speed of jinja2 in python is 1387.3108 runs/s which is a bit slower than jinjava.
But I compared the 2 projects:
jinja2 is much faster if a Template is prepared in advance.
python code:
from jinja2 import Template
n = 70000
event = {'name': "jia.liu"}
t = Template('Hello, {% if name is defined %} {{name}} {% else %} world {% endif %}')
msg = []
for i in range(n):
msg.append(t.render(**event))
jinjava code:
Jinjava jinjava = new Jinjava();
Map<String, Object> context = new HashMap<>();
context.put("name", "Jared");
String template = "Hello, {% if name is defined %} {{name}} {% else %} world {% endif %}";
for (int i = 0; i < 70000; i++) {
jinjava.renderForResult(template, context);
}
System.out.println(System.currentTimeMillis()-s);
I really hope i use jinjava in a wrong way. Is there any method I could first create a Template instance like jinja2?
It would be nice to be able to allow users to disable certain template features. One use case would be to disable looping, extensions, etc. to offer an environment similar to what Ansible does for its YAML files. From http://docs.ansible.com/ansible/playbooks_variables.html:
ansible allows Jinja2 loops and conditionals in templates, but in playbooks, we do not use them. Ansible playbooks are pure machine-parseable YAML. This is a rather important feature as it means it is possible to code-generate pieces of files, or to have other ecosystem tools read Ansible files. Not everyone will need this but it can unlock possibilities.
It looks like this should be possible by allowing on Context
that allows setting the following:
And then allowing a constructor on Jinjava
that takes a Context
:
https://github.com/HubSpot/jinjava/blob/master/src/main/java/com/hubspot/jinjava/Jinjava.java#L82
Alternatively, the JinjavaConfig
could encapsulate the Context
dependencies`.
I would be happy to add PR if this sounds reasonable.
There is a Python function called "range", which is also available in Jinja2, that allows you to create an incrementing loop without the need to declare a scope. Can we have this added to our HubL accessible functions? This would make it a lot easier for us to create simple loops for stuff like numbered blog pagination.
Thanks!
JinjavaConfig config = new JinjavaConfig();
config.setResourceLocator(new MyCustomResourceLocator());
Jinjava jinjava = new Jinjava(config);
Should read
Jinjava jinjava = new Jinjava(config);
jinjava.setResourceLocator(new MyCustomResourceLocator());
There seems to be a problem with the xmlattr and the way it binds itself to the filter method of the XmlAtttrFilter class. Using this in my template:
{{ boot_attributes_map|xmlattr }}
Produces this error:
com.hubspot.jinjava.interpret.FatalTemplateErrorsException: TemplateError{severity=FATAL, reason=SYNTAX_ERROR, message=TemplateSyntaxException: Method not found: class com.hubspot.jinjava.lib.filter.XmlAttrFilter.filter(com.hubspot.jinjava.objects.collections.PyMap, com.hubspot.jinjava.interpret.JinjavaInterpreter), fieldName=null, lineno=5}
It seems like it is ignoring the String... on the method when trying to find it. I can work around the error by sending a parameter to the xmlattr so that it finds the method:
{{ boot_attributes_map|xmlattr('') }}
I will see if I can identify where the problem is in the code and submit a pull request.
I'm using this library to template files from an api where all values are strings and I wonder if you would be open to add a bool
filter that would convert a true/false string to a boolean. I'm happy to submit a PR if you think it's suiting. This is what ansible does in their playbook filters.
currently filters only support parameters positionally (even though we allow naming syntactically, we actually ignore the names when invoking the filter).
Any time I attempt to use filters I get the following error:
Request processing failed; nested exception is com.hubspot.jinjava.interpret.FatalTemplateErrorsException: TemplateError{severity=FATAL, reason=SYNTAX_ERROR, message=TemplateSyntaxException: Method not found: class com.hubspot.jinjava.lib.filter.TitleFilter.filter(java.lang.String, com.hubspot.jinjava.interpret.JinjavaInterpreter), fieldName=null, lineno=2}
My template for that example is simply:
{{ "hello world" | title }}
At this point I'm not doing much so wondering if its just something I missed that's required for filter support? I'm assuming the default ones are already registered.
I was originally attempting to add my own filter but had the same problem, my filter implemented the Jinjava Filter interface as I'm sure the TitleFilter does. The method its looking for in the filter has the following footprint:
public Object filter(Object o, JinjavaInterpreter jinjavaInterpreter, String... strings)
I'm running on Java 1.8.0_101 with Jinjava 2.1.0.
While you can pass arguments into macros and a call block back into a macro using {{ caller }}, you are not able to pass an argument into the call block. For example the following example does not work, despite being seemingly possible based on Jinja and the CallTag.java.
{% macro foo(class) %}
{{ caller('a message from me') }}
{% endmacro %}
{% call(message) foo('my-message') %}
Print this call block back into macro with {{ message }}
{% endcall %}
Consider the following code:
{% macro example(prefix, items) %}
{{ prefix }} {{ items | first }}
{% if (items | count > 1) %}{{ example( prefix ~'-', items[1:items|count]) }}{% endif %}
{% endmacro %}
{{ example('-',['lorem', 'ipsum', 'dolor']) }}
With jinjava 2.1.7 or earlier this correctly outputs:
- lorem
-- ipsum
--- dolor
Starting with version 2.1.8 this no longer works and instead just outputs:
- lorem
It is same issue with #4
I need custom filter and add my filters using below code
// create a node in advance and reuse it each time
String template = "{{some thing here}}";
TokenParser t = new TokenParser(null,template);
Node parsedTemplate =TreeParser.parseTree(t);
Jinjava jinjava = new Jinjava();
Context c = jinjava.getGlobalContext();
c.registerFilter(f);
c.putAll(event);
JinjavaInterpreter interpreter = new JinjavaInterpreter(jinjava, c, null);
interpreter.render(parsedTemplate);
However , the event , for example ** event = {'name': "jia.liu"} ** always varies, and I must put the event to Contest c each time.
I don't want to create a Context c and register all filters to it .
But If I create Context c in advance and reuse it , will the content in the context increase continually?
In the python jinja2 , Context(named env in jinja2) is apart from event.
Thanks
I'm looking for a way to remove some of the default registered tags. For security reasons, we don't want end-users to be able to use tags like extends
, import
or include
.
Would you accept a PR that adds this capability?
I’ve found that if you define a macro like this:
(within valid-macro-usage.jinja)
{%- macro fun(val) %}{{ val }}{% endmacro -%}
{{ fun("called within template in which it was defined") }}
And then import it with a name like this:
{% import "valid-macro-usage.jinja" as m %}
{{ m.fun("called within template in which it was imported") }}
you’ll get a TemplateError like this:
[TemplateError{severity=FATAL, reason=SYNTAX_ERROR, item=OTHER, message='TemplateSyntaxException: Could not resolve function 'fun'', fieldName='null', lineno=3, category=UNKNOWN, categoryErrors=null}]
Whereas if you modify valid-macro-usage.jinja
to call m.fun
(which shouldn’t be necessary) it works as expected.
This branch adds a breaking test to illustrate the problem: https://github.com/HubSpot/jinjava/tree/fix_macro_reference_error_in_template_imported_by_name
Example from jinja.pocoo.org/docs/dev/templates:
<ul class="sitemap">
{%- for item in sitemap recursive %}
<li><a href="{{ item.href|e }}">{{ item.title }}</a>
{%- if item.children -%}
<ul class="submenu">{{ loop(item.children) }}</ul>
{%- endif %}</li>
{%- endfor %}
</ul>
When you put a dash (-) as a key into your context map, the the key will not render in the output. It would be nice for this to either work or throw an exception.
Hi,
I am parsing the following jinja template:
{% import 'library.jinja' as lib %}
{{ lib.echo('test') }}
library.jinja
is defined as this:
{% macro echo(what) -%}
echo {{ what }}
{%- endmacro %}
For some reason that I can not figure out I am ending with the following Exeception when calling
JinjavaConfig.Builder configBuilder = JinjavaConfig.newBuilder().withLstripBlocks(true).withTrimBlocks(true);
Jinjava jinjava = new Jinjava(configBuilder.build());
String template = "{% import 'library.jinja' as lib %}\n{{ lib.echo('test') }}";
String renderedTemplate = jinjava.render(template, null);
Exception:
java.lang.ArrayIndexOutOfBoundsException: 55
at com.hubspot.jinjava.tree.parse.TokenScanner.newToken(TokenScanner.java:247)
at com.hubspot.jinjava.tree.parse.TokenScanner.getNextToken(TokenScanner.java:172)
at com.hubspot.jinjava.tree.parse.TokenScanner.computeNext(TokenScanner.java:281)
at com.hubspot.jinjava.tree.parse.TokenScanner.computeNext(TokenScanner.java:31)
at com.google.common.collect.AbstractIterator.tryToComputeNext(AbstractIterator.java:143)
at com.google.common.collect.AbstractIterator.hasNext(AbstractIterator.java:138)
at com.google.common.collect.Iterators$PeekingImpl.hasNext(Iterators.java:1144)
at com.hubspot.jinjava.tree.TreeParser.text(TreeParser.java:101)
at com.hubspot.jinjava.tree.TreeParser.nextNode(TreeParser.java:81)
at com.hubspot.jinjava.tree.TreeParser.buildTree(TreeParser.java:59)
at com.hubspot.jinjava.interpret.JinjavaInterpreter.parse(JinjavaInterpreter.java:116)
at com.hubspot.jinjava.lib.tag.ImportTag.interpret(ImportTag.java:86)
at com.hubspot.jinjava.lib.tag.Tag.interpretOutput(Tag.java:29)
at com.hubspot.jinjava.tree.TagNode.render(TagNode.java:50)
at com.hubspot.jinjava.interpret.JinjavaInterpreter.render(JinjavaInterpreter.java:182)
at com.hubspot.jinjava.interpret.JinjavaInterpreter.render(JinjavaInterpreter.java:155)
at com.hubspot.jinjava.Jinjava.renderForResult(Jinjava.java:204)
at com.hubspot.jinjava.Jinjava.renderForResult(Jinjava.java:177)
at com.hubspot.jinjava.Jinjava.render(Jinjava.java:150)
I do not know if this is a bug in Jinjava or in my code. But I can not figure out what I would be doing wrong.
I just figured out that I do not experience this error when I do not use
JinjavaConfig.newBuilder().withLstripBlocks(true).withTrimBlocks(true);
Just using the following works out fine:
JinjavaConfig.Builder configBuilder = JinjavaConfig.newBuilder().build();
It would be nice to have a proper site with more extensive documentation, samples and community.
See http://jtwig.org/ as an example.
According to the list filter file: https://github.com/HubSpot/jinjava/blob/master/src/main/java/com/hubspot/jinjava/lib/filter/ListFilter.java
Applying a list filter to a string variable should return a sequence of characters.
{% set my_test = 'Test'%}
{{ my_test|list }}
prints something like
[[C@45a31e18]
Is this expected behavior for this filter, when used with strings? If so is there any practical application for this or should the filter really only be applied to numeric variables?
Due to VariableChain doing the resolving (instead of SimpleResolver) ResourceBundles are not supported. The reflection stuff for beans, maps, collections etc. has been duplicated. Is there a reason for this or is it by accident?
Currently, the following statement fails even though I tried defining the enumerate method in java to return my own "Tuple" class and a "Map" object.
{% for index, object in enumerate(list) %}
I was able to write and define an ELFunction which was accepted and runs without failing. However, after the template is rendered, the replacement for "index" and "object" are just null.
What should/can I return as a result of "enumerate" for the above statement to work with jinjava?
jinjava.getGlobalContext().registerFunction(
new ELFunctionDefinition("", "enumerate", JinjavaHelpers.class, "enumerate", List.class));
public static List<Map<Integer,X>> enumerate(List list_in) {
List nums = new ArrayList(list_in.size());
for (int x = 0; x < list_in.size(); x++) {
nums.add(Integer.valueOf(x));
}
return zip(nums, list_in);
}
public static <X,Y> List<Map<X,Y>> zip(List<X> list_a, List<Y> list_b) {
Iterator<X> xiter = list_a.iterator();
Iterator<Y> yiter = list_b.iterator();
List<Map<X,Y>> result = new LinkedList<Map<X,Y>>();
while (xiter.hasNext() && yiter.hasNext()) {
Map<X,Y> myMap = new HashMap<X,Y>();
myMap.put(xiter.next(), yiter.next());
result.add(myMap);
}
return result;
}
I have a case that {% block content %}{% endblock %} is defined within {% for %} and it doesn't work as expected.
when I used jinjava, i have a template file. but the template have "for i in range(2) ....",but when running this, failed. why? donn't support "function range" ,help me...
I used jar version: 2.0.11-java7, is this merged the range function code ???
i am waiting, please .thank you
Jinja itself provides two useful options trim_blocks
and lstrip_blocks
for changing the behavior of whitespace preservation in the output. Quoting from the documentation:
If an application configures Jinja to trim_blocks
, the first newline after a template tag is removed automatically (like in PHP). The lstrip_blocks
option can also be set to strip tabs and spaces from the beginning of a line to the start of a block. (Nothing will be stripped if there are other characters before the start of the block.)
With both trim_blocks
and lstrip_blocks
enabled, you can put block tags on their own lines, and the entire block line will be removed when rendered, preserving the whitespace of the contents.
These options are particularly important when using this to render things other than HTML where whitespace itself can be significant (for example, Markdown).
Although it seems #iteritems
is on its way out, it's probably still worth it to create an alias to map#items
.
When I have a list of items and I want to filter them using selectattr like this
items | selectattr('property', 'equalto', 'fixed-value')
I'm getting the following error:
generate failed: TemplateError{severity=FATAL, reason=SYNTAX_ERROR, message=TemplateSyntaxException: com.hubspot.jinjava.interpret.InterpretException: equalto test requires 1 argument, fieldName=null, lineno=79}
But that is exactly the syntax mentioned in https://github.com/HubSpot/jinjava/blob/5e6411216131e5405af8259bfddaef61a6550ac3/src/main/java/com/hubspot/jinjava/lib/exptest/IsEqualToExpTest.java. Am I using this the wrong way or is this a bug?
public static boolean test(String str){
return true;
}
public static void main(String[] args) throws IOException {
Jinjava jinjava = new Jinjava();
jinjava.getGlobalContext().registerFunction(
new ELFunctionDefinition("x", "test", App.class,"test",String.class));
Map<String, Object> context = Maps.newHashMap();
context.put("name", "Jared");
String template = "| {% if x.test(name) %} test {% endif %}|";
String renderedTemplate = jinjava.render(template, context);
System.out.println(renderedTemplate);
}
whether the test function return true or false, no any effect
what can I do
help~
When I try to get a part of a string like this (currently using jinjava 2.1.7):
{{ repository[0:4] }}
I get the following Exception thrown:
com.hubspot.jinjava.interpret.TemplateSyntaxException: Property repository is not a sequence.
at com.hubspot.jinjava.el.ExpressionResolver.resolveExpression(ExpressionResolver.java:74)
at com.hubspot.jinjava.interpret.JinjavaInterpreter.resolveELExpression(JinjavaInterpreter.java:323)
at com.hubspot.jinjava.tree.ExpressionNode.render(ExpressionNode.java:41)
at com.hubspot.jinjava.lib.tag.ForTag.interpret(ForTag.java:137)
at com.hubspot.jinjava.lib.tag.Tag.interpretOutput(Tag.java:29)
at com.hubspot.jinjava.tree.TagNode.render(TagNode.java:50)
at com.hubspot.jinjava.lib.fn.MacroFunction.doEvaluate(MacroFunction.java:69)
at com.hubspot.jinjava.el.ext.AbstractCallableMethod.evaluate(AbstractCallableMethod.java:72)
at com.hubspot.jinjava.el.JinjavaInterpreterResolver.invoke(JinjavaInterpreterResolver.java:82)
at de.odysseus.el.tree.impl.ast.AstMethod.eval(AstMethod.java:91)
at de.odysseus.el.tree.impl.ast.AstMethod.eval(AstMethod.java:100)
at de.odysseus.el.tree.impl.ast.AstEval.eval(AstEval.java:51)
at de.odysseus.el.tree.impl.ast.AstNode.getValue(AstNode.java:31)
at de.odysseus.el.TreeValueExpression.getValue(TreeValueExpression.java:122)
at com.hubspot.jinjava.el.ExpressionResolver.resolveExpression(ExpressionResolver.java:62)
at com.hubspot.jinjava.interpret.JinjavaInterpreter.resolveELExpression(JinjavaInterpreter.java:323)
at com.hubspot.jinjava.tree.ExpressionNode.render(ExpressionNode.java:41)
at com.hubspot.jinjava.interpret.JinjavaInterpreter.render(JinjavaInterpreter.java:181)
at com.hubspot.jinjava.interpret.JinjavaInterpreter.render(JinjavaInterpreter.java:153)
at com.hubspot.jinjava.Jinjava.renderForResult(Jinjava.java:200)
at com.hubspot.jinjava.Jinjava.renderForResult(Jinjava.java:173)
at com.hubspot.jinjava.Jinjava.render(Jinjava.java:149)
at com.automic.bob.service.translate.parser.jinja.JinjaParser.getParsedString(JinjaParser.java:34)
at com.automic.bob.service.translate.parser.build.BuildFileParser.parseAction(BuildFileParser.java:186)
at com.automic.bob.service.translate.parser.build.BuildFileParser.generateScriptForBuildActions(BuildFileParser.java:148)
at com.automic.bob.service.translate.parser.build.BuildFileParser.parse(BuildFileParser.java:78)
at com.automic.bob.service.translate.TranslateFileMessageHandler.sendReplyMessage(TranslateFileMessageHandler.java:77)
at com.automic.bob.service.translate.TranslateFileMessageHandler.handle(TranslateFileMessageHandler.java:42)
at com.automic.bob.service.translate.TranslateFileMessageHandler.handle(TranslateFileMessageHandler.java:19)
at com.automic.bob.lib.comm.RabbitMQ$4.handleDelivery(RabbitMQ.java:290)
at com.rabbitmq.client.impl.ConsumerDispatcher$5.run(ConsumerDispatcher.java:144)
at com.rabbitmq.client.impl.ConsumerWorkService$WorkPoolRunnable.run(ConsumerWorkService.java:99)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.el.ELException: Property repository is not a sequence.
at com.hubspot.jinjava.el.ext.AstRangeBracket.eval(AstRangeBracket.java:35)
at de.odysseus.el.tree.impl.ast.AstEval.eval(AstEval.java:51)
at de.odysseus.el.tree.impl.ast.AstNode.getValue(AstNode.java:31)
at de.odysseus.el.TreeValueExpression.getValue(TreeValueExpression.java:122)
at com.hubspot.jinjava.el.ExpressionResolver.resolveExpression(ExpressionResolver.java:62)
... 34 more
Nested variables don't seem to be working as expected ie: in my template
{{ date.from }}
and rendering with something like this (using Scala)
val m = immutable.HashMap(
"date" -> immutable.HashMap(
"from" -> "1451865600000",
"to" -> "1452038400000"
)
)
jinjava.render(template, mapAsJavaMap(m))
Renders fine, but the value is not being printed into the output.
Is this just not part of your implementation of Jinja?
Hello, how could I render a for loop?
I mean actually my Map("list" -> List())
will always behave strangely if i do it like that:
{% for item in list %}
{{ item }}
{% endfor %}
Item will still always be List() instead of the inner variables..
Edit:
I sent a HashMap with a "list" -> List("1", "2", "3") object to the template the result will always be:
List(1, 2, 3)
But it should be:
1
2
3
Edit: it looks that the scala List is making problems..
from jinja math docs:
//
Divide two numbers and return the truncated integer result. {{ 20 // 7 }} is 2.
However attempting this with jinjava throws an exception. For example, I would expect this template:
20 // 7 = {{ 20 // 7 }}
to return 20 // 7 = 2
, but instead it throws this:
com.hubspot.jinjava.interpret.InterpretException: Error resolving expression [20 // 7]: NullPointerException:
at com.hubspot.jinjava.el.ExpressionResolver.resolveExpression(ExpressionResolver.java:89)
at com.hubspot.jinjava.interpret.JinjavaInterpreter.resolveELExpression(JinjavaInterpreter.java:397)
Caused by: java.lang.NullPointerException
at jinjava.de.odysseus.el.tree.impl.Parser.mul(Parser.java:547)
at com.hubspot.jinjava.el.ext.ExtendedParser.add(ExtendedParser.java:149)
at jinjava.de.odysseus.el.tree.impl.Parser.cmp(Parser.java:462)
Here are the dependency 2.1.7 inflicts on your project:
+--- com.hubspot.jinjava:jinjava:2.1.7
| +--- org.slf4j:slf4j-api:1.7.12
| +--- org.javassist:javassist:3.18.2-GA
| +--- org.jsoup:jsoup:1.8.1
| +--- de.odysseus.juel:juel-api:2.2.7
| +--- de.odysseus.juel:juel-impl:2.2.7
| +--- de.odysseus.juel:juel-spi:2.2.7
| +--- org.apache.commons:commons-lang3:3.4
| --- com.google.code.findbugs:annotations:3.0.0
That is a bit too much! Especially problematic are the findbugs "shutup" annotation, but are these jars all that necessary? The most I can put up with is Guava dependence, if at all... Can you try to make it a "single jar" beauty like the freemarker or jsoup projects?
... Staying away from jinjava for now, given no compelling benefits over freemarker for email templates (Unless you can point some?) and all the extra baggage.
PS: I use ansible a lot and I am well aware of jinja2's power.
This is a great open source library! Sounds like it is exactly what we might want to use for our company.
Could you add some documentation for contribution guidelines and how to get involved in this project? Or do you think that HubSpot won't be keeping this open source for very long?
TestCase:
{ "zkhost":{ "aaa":null, "bbb":null, "ccc":null }
{%for zk in zkhost%}{{zk}}{%if not loop.last%},{%endif%}{%endfor%}
the result we want:
aaa,bbb,ccc
in fact
,,
From the name of the config flag failOnUnknownTokens
, I expected rendering
{% for zone in zones %} ... {% endfor %}
to fail if zones
is not defined in the bindings.
I can implement the behavior if that's a reasonable expectation. If it is, are there other tags that should respect that flag?
CODE:
{% set a="1" %}
{% set b=b | default("2") %}
{% set c={"key": "value"} %}
{% set d=d | default({"key": "value"}) %}
Type: {{ type(a) }} - Value: {{ a }}
Type: {{ type(b) }} - Value: {{ b }}
Type: {{ type(c) }} - Value: {{ c }}
Type: {{ type(d) }} - Value: {{ d }}
Type: {{ type(c.key) }} - Value: {{ c.key }}
Type: {{ type(d.key) }} - Value: {{ d.key }}
OUTPUT:
Type: str - Value: 1
Type: str - Value: 2
Type: dict - Value: {key=value}
Type: str - Value: {key=value}
Type: str - Value: value
Type: null - Value:
What the problem with the last output?
Does this library have any support for what in Liquid is known as Drops? See here:
https://github.com/Shopify/liquid/wiki/Introduction-to-Drops
Basically its a restricted model so you can do things like {{ product.tags }}, tags being a method that grabs a bunch of tags for the product and returns them.
If this can be at minimum done by eager loading, like a JSON object, that would also solve the requirement somewhat, at least for myself.
example template that reveals error:
{%- macro do_thing() -%}
{%- set x = 1 -%}
token
{%- endmacro -%}
xx{{ do_thing() }}xx
I would expect output to be: (as confirmed by http://jinja2test.tk/ )
xxtokenxxx
but instead jinjava outputs:
xx
tokenxxx
While you can use the datetimeformat filter to format timestamps, there is currently no way to take a convert variables into datetime objects. For example, if you wanted to calculate 30 days before local_dt, there isn't any way to take a string or numeric variable and convert it to a datetime object.
It would be great if a filter or function could be added to support string/int to datetime object conversion.
When I try to use those variables in a for loop, those variables are replaced by nothing.
My syntax is :
{% for fo in foo %}
{% for ba in bar %}
...
{% endfor %}
send_user "Completed ({{ forloop.counter }}/{{ foo.count }})\n"
{% endfor %}
output is :
Completed (/)
Please consider the following code:
final String tpl = "The question is: {{ obj.text }}!";
final Map<String, Object> ctx = new HashMap<>();
final Map<String, Object> obj = new HashMap<>();
obj.put("text", "{{ obj.val }}");
obj.put("val", "is it a bug?");
ctx.put("obj", obj);
Jinjava jj = new Jinjava();
System.out.println(jj.render(tpl, ctx));
The expected output is: The question is {{ obj.val }}!
, but The question is: is it a bug?!
appears on my console.
I have created similar code in Jinja2 (python):
from jinja2 import Template
t = Template('The question is {{ obj.text }}!')
ctx = {"obj": {"text": "{{ obj.val }}", "val": "is it a bug?"}}
print t.render(ctx)
The render result is as expected: The question is {{ obj.val }}!
I would like to know if it is an intended behavior, because in my application I have some templates where expressions insert google-encoded polylines which may occasionally contain {{ }}
characters, which in turn are interpreted as another expression with unresolvable name.
Almost identical to #78, but the issue is with the select() filter. Seeing the following error: TemplateSyntaxException: com.hubspot.jinjava.interpret.InterpretException: equalto test requires 1 argument
I believe this issue is the same as issue #78, except that rejectattr is concerned.
topics|rejectattr("name", "equalto", "News")
TemplateSyntaxException: com.hubspot.jinjava.interpret.InterpretException: equalto test requires 1 argument
I am not sure if this is a bug or by design, but I thought I would point it out. The datetimeformat is returning the format of today's date if the date the filter was ran on is null. I looked at the doc here and it does not give any indication of the intended functionality.
The filter is using the Functions.getDateTimeArg() which is causing this behavior
private static ZonedDateTime getDateTimeArg(Object var) {
ZonedDateTime d = null;
if (var == null) {
d = ZonedDateTime.now(ZoneOffset.UTC);
} else if (var instanceof Number) {
d = ZonedDateTime.ofInstant(Instant.ofEpochMilli(((Number) var).longValue()), ZoneOffset.UTC);
} else if (var instanceof PyishDate) {
d = ((PyishDate) var).toDateTime();
} else if (var instanceof ZonedDateTime) {
d = (ZonedDateTime) var;
} else if (!ZonedDateTime.class.isAssignableFrom(var.getClass())) {
throw new InterpretException("Input to function must be a date object, was: " + var.getClass());
}
return d;
}
example:
{% set l = 2 %}
{% for i in range(1, l + 1) %}
{{i}}
{% endfor %}
the parser does not understand the expression l + 1
in args range
function
I've been trying to use the withFailOnUnknownTokens, but I when I active it, it seems not change anything. Do you guys know if it is working? Is there a example?
I looked into some tests here on Git, but even doing the same, it is not working for me.
Thanks
Hi, trying to use filters I get the following error:
com.hubspot.jinjava.interpret.FatalTemplateErrorsException: TemplateError{severity=FATAL, reason=EXCEPTION, message=InterpretException: Error resolving expression [testvar | upper]: IllegalArgumentException: wrong number of arguments, fieldName=null, lineno=1}
This is running:
Jinjava jinjava = new Jinjava(new JinjavaConfig());
String template = "hello {{ testvar | upper }}";
jinjava.render(template, ImmutableMap.of("testvar", "stranger")));
Running with no filters works fine.
I've checked with a colleague that's using jinjava in another project and he seems to be getting the same error.
Can we have something similar to jinja2.StrictUndefined flag in python? This would be very useful to verify missing token values in template.
The steps mentioned in the README.md to add a custom filter dont seem to be valid anymore.
The following line:
jinjava.getFilterLibrary().addFilter(new MyAwesomeFilter());
should be
jinjava.getGlobalContext().registerFilter(new MyAwesomeFilter());
The Jinja specification allows for manual whitespace control by adding a minus at the start or end of tags (http://jinja.pocoo.org/docs/dev/templates/#whitespace-control) like:
{% for foo in [1,2,3,4,5,6,7,8,9] -%}
{{ foo }}
{%- endfor %}
This code should yield 123456789
. However it yields
1
2
3
4
5
6
7
8
9
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.