tipsy / j2html Goto Github PK
View Code? Open in Web Editor NEWJava to HTML generator. Enjoy typesafe HTML generation.
Home Page: https://j2html.com/
License: Apache License 2.0
Java to HTML generator. Enjoy typesafe HTML generation.
Home Page: https://j2html.com/
License: Apache License 2.0
I'd like something like that
<font color='#FFFFFF'>data</font>"
for html email purpose
<a href="/">Главная</a>
It's 2015 already, we have UTF-8!
j2html 1.2.0. To reproduce, run this:
System.out.println(Config.cssMinifier.minify("body {\n" +
" font-family: verdana, geneva, sans-serif;\n" +
" font-size: 90%\n" +
"}\n" +
"table {\n" +
" border: 1px solid black;\n" +
" border-collapse: collapse;\n" +
" font-size: 90%\n" +
"}\n" +
"th {\n" +
" text-align: left\n" +
"}\n" +
"th,td {\n" +
" vertical-align: text-top\n" +
"}\n" +
"td.unresolved {\n" +
" color: red\n" +
"}\n" +
"td.resolved {\n" +
" color: green\n" +
"}\n" +
"th, td {\n" +
" padding: 0.2em;\n" +
" text-align: left\n" +
"}\n" +
"td.odd, th.odd {\n" +
" background-color: #f2f2f2\n" +
"}"));
which yields in
body{font-family:verdana,geneva,sans-serif;font-size:90}table{border:1px solid black;border-collapse:collapse;font-size:90}th{text-align:lef}th,td{vertical-align:text-to}td.unresolved{color:re}td.resolved{color:gree}th,td{padding:0.2em;text-align:lef}td.odd,th.odd{background-color:#f2f2f}
Note last character of each selector is trimmed.
I am using j2Html and its great FOSS :)
Currently image TagCreater generates a short hand notation of closing tags i.e. <img .... />.
This is gives following error
The element type "img" must be terminated by the matching end-tag ""
Hello, it seems like multiple css classes don;t work.
e.g.
I want something like this:
<div class="class1 class2">
to produce it I use :
div().withClass("class1").withClass("class2")
and this results in <div class="class2">
I assume, I need to use div().withClass("class1 class2")
, right?
But it's not really convenient and not intuitive.
Consider also the following case:
div().
.withClass("class1")
.withCondClass(isActive, "class2-active")
This also won't work but now there is no obvious way to write it correctly.
I guess I will have to do something like this:
String activeClass = isActive ? "class2-active" : "";
div().withClass("class1 " + activeClass);
Which could also be improved should withClass
work in additive way.
Thanks!
The purpose of unsafeHtml
is that it does not escape the input which is only something you ever want to do when you know the html is safe since everything is otherwise escaped by default.
Currently, in j2html, unsafeHtml("<h1>foo</h1>").render()
returns "<h1>foo</h1>"
. This should really be called "safeHtml".
I'm guessing it's named "unsafeHtml" because that's what it produces. But other templating libraries I'm familiar with use the inverse safe(markup)
including nunjucks (https://mozilla.github.io/nunjucks/templating.html#safe) and jinja, which makes more sense since you're basically annotating the text you're passing in as safe.
If you like the name unsafeHtml
and don't like my proposal, I think unescapedHtml
would still be a much less ambiguous name.
But I certainly would scratch my head if I saw unsafeHtml(user.name)
in a project.
Your library currently depends on java 8 because of 1 line children.forEach(this::with);
Could it be updated as follow and be backward compatible with java 7 ?
iff --git a/src/main/java/j2html/tags/ContainerTag.java b/src/main/java/j2html/tags/ContainerTag.java
index 9c08527..f8bc20c 100644
--- a/src/main/java/j2html/tags/ContainerTag.java
+++ b/src/main/java/j2html/tags/ContainerTag.java
@@ -43,12 +43,14 @@ public class ContainerTag extends Tag {
* @param children tags to be appended
* @return itself for easy chaining
*/
- public ContainerTag with(List<Tag> children) {
- if (children != null) {
- children.forEach(this::with);
- }
- return this;
- }
+ public ContainerTag with(List<Tag> children) {
+ if (children != null) {
+ for ( Tag child : children ) {
+ this.with( child );
+ }
+ }
+ return this;
+ }
/**
* Call with-method based on condition
I got a worse performance with v0.88
long startTrainTime = System.currentTimeMillis();
EmptyTag c = img().withClass("image").withSrc(sb.toString());
long endTrainTime = System.currentTimeMillis();
DecimalFormat df = new DecimalFormat("#.#####");
System.out.println(df.format((endTrainTime - startTrainTime) / 1000. / 60.));
v.0.7: 0,00007
v.0.88: 0,06715
looks like the last simple escaper change
In the class Tag
change
public T attr(String attribute, String value)
to
public T attr(String attribute, Object value)
And the body of the method
setAttribute(attribute, value);
return (T) this;
to
setAttribute(attribute,value == null ? null : value.toString());
return (T) this;
The impact is minor but in that way we can write
myTag.attr("attribute", 6)
j2html is great, easy and fast. But I think it could be even faster and consume less memory with the following approach. Maybe it is not a good idea so I am asking for feedback here first.
Take a look at this code:
String headline = "My Headline";
String imgSrc = "img/hello.png";
body().with(
h1(headline).withClass("example"),
img().withSrc(imgSrc)
).render();
This template generates the DomContent each and every time I render this page. This involves - with a bigger template - a lot of new ContainerTag
statements (which are hidden by static imports).
It would be nice to build a DomContent Tree with some self written ContainerTags first and then let it render with a model.
Therefor we need a second render method render(Object model)
. The model is passed down the line and each Tag or Attribute can pick up its model if needed for rendering. Object would usually be a map like in Spring MVC.
This way I can reuse the DomContent for each and every page. I don't need to build it and I don't need the GC to collect it.
This would be fairly easy when we add two methods to DomContent (and one method to Attribute)
public abstract String render(Object model) ;
public void render(Appendable writer, Object model);
If you think this is a good idea I can send a patch request.
The plugin net.orfjackal.retrolambda throws an error when importing j2html to eclipse. This is annoying for eclipse users who wants to send a pull request.
diff --git a/pom.xml b/pom.xml
index 1489f96..1159143 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,6 +63,35 @@
<packaging>jar</packaging>
<build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.eclipse.m2e</groupId>
+ <artifactId>lifecycle-mapping</artifactId>
+ <version>1.0.0</version>
+ <configuration>
+ <lifecycleMappingMetadata>
+ <pluginExecutions>
+ <pluginExecution>
+ <pluginExecutionFilter>
+ <groupId>net.orfjackal.retrolambda</groupId>
+ <artifactId>retrolambda-maven-plugin</artifactId>
+ <versionRange>[2.5,)</versionRange>
+ <goals>
+ <goal>process-main</goal>
+ <goal>process-test</goal>
+ </goals>
+ </pluginExecutionFilter>
+ <action>
+ <execute />
+ </action>
+ </pluginExecution>
+ </pluginExecutions>
+ </lifecycleMappingMetadata>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
<plugins>
<plugin>
<groupId>net.orfjackal.retrolambda</groupId>
Or expect your commiters to use at least m2e 1.7
and add this to the plugin configuration
<?m2e execute onConfiguration?>
If you like I can send a Pull Request
I'm very happy for the code , I want to lean it. Can you give me some Demo in realy project web.
Hi,
Is it possible to make text escaping configurable?
Let's say I want to use different implementation of text escaping or disable it completely.
I think it should be possible to achieve using ServiceLoader.
I can provide pull request if you are interested.
First, I'd like to thank you for useful project. I started using it for creating html reports and found it very handy. However when I added j2html as a dependency to my project the size of final war-file has been almost doubled from 10 Mb to 18 Mb. I found that j2html hooked up ant, ant-launcher, guava, closure-compiler, .. and many others jar files. I wonder if they all are needed for run-time? If not, please correct the dependency list in the .pom file to set correct scope for them.
Best regards,
Hello,
I found myself writing a lot of tag.attr("title", title)
code and I thought it may be a good idea to add withTitle
/withCondTitle
methods to Tag
class. What do you think?
Hi, I hope raising a new issue is okay for this eve though it's actually a question. There is a following statement on the j2html homepage: "Please don't use j2html if: You use a CSS framework such as Bootstrap." I would assume this is quite a show stopper for many.
However, if I understand properly what j2html does, this only affects cases where pretty much the whole html is rendered by the j2html, including the head / body etc, but does it really matter when generating just parts of the html with j2html?
For example if my java server returns a snippet that is meant to be injected into a div by whatever means, does it really matter which libs are used in the frontend? For me j2html would be really useful server side html component creator, but I might have understood something completely wrong..
Thanks!
Hi,
just starting using the library and found that the first snippet of code of the section "Loops, each() and filter()" at https://j2html.com/examples.html does not compile. In particular:
body(
div(attrs("#employees"),
employees.stream().map(employee ->
div(attrs(".employee"),
h2(employee.getName()),
img().withSrc(employee.getImgPath()),
p(employee.getTitle())
)
).collect(Collectors.toList())
)
)
should be something like:
body(
div(attrs("#employees"),
employees.stream().map(employee ->
div(attrs(".employee"),
h2(employee.getName()),
img().withSrc(employee.getImgPath()),
p(employee.getTitle())
)
).toArray(ContainerTag[]::new)
)
)
The problem is .collect(Collectors.toList())
given that the div method accepts a vararg of type ContainerTag that derives from DomContent. Isn't?
Paolo
Hi,
I am trying to use j2html inside jmeter's beanshell component.
My UseCase: I want to generate a custom html report.
I have included the j2html-1.0.0.jar in the lib/ext folder of jmeter, when I run the test I am gettting this error - Command not found: body( j2html.tags.ContainerTag ) .
This library is very light but is linked to 2 big dependencies at runtime.
It would be nice to have a standalone library instead.
To do so:
Add equals() method to Tags classes for unit testing.
This issue looks for the posibilities of if and if-else structures, and sums up a number of usages.
Not sure if this is better suited as a wiki, but in some approaches, new classes are needed.
Often a tag has to be placed under a condition. For example, if the current page number is equal to the value i than use a span tag, otherwise an anchor tag. There are multiple ways to perform conditional logic in j2html, and maybe some undiscovered ones that could improve the api.
Examples with an if-else-structure:
Example with condWith():
ul().with(
li().condWith(pageNumber == currentPageNumber,
span(pageNumber + "")
).condWith(pageNumber != currentPageNumber,
a(pageNumber + "").withHref("http....")
)
);
Example with the ternary operator:
ul().with(
li().with(pageNumber == currentPageNumber
? span(pageNumber + "")
: a(pageNumber + "").withHref("http....")
)
);
The ternary operator example is cleaner in this case because the condition only has to be specified once, and no additional with() or condWith() is required, and also no parent tag is required. Also, the ternary operator only executes/evaluates one its bodies, while conWith always execute the body, even if the condition fails.
But in case only an if-structure is needed instead of an if-else, something new has to be introduced when a ternary operator is used.
Examples with an if-structure:
Example with condWith():
ul().with(
li().with(
div("Message " + message.getContent())
).condWith(message.getUser().equals(currentUser),
a("delete").withHref("http....")
)
);
The drawback of this approach may be the use of both with() and condWith().
Example with ternary operator, with a new introduced class/method:
ul().with(
li().with(
div("Message " + message.getContent()),
message.getUser().equals(currentUser)
? a("delete").withHref("http....")
: none
)
);
Which may feel a bit cleaner, although the message.getUser().equals(currentUser)
line may not immediately appear/suggest that it is a condition, and none
may be a bit verbose. "none" is used in Python and Scala to indicate nothing, although an empty group() of something like an invisible parent tag without child tags may also be an option. "none" can be be a static field, since only one instance is needed.
Another approach would be to introduce an IF() method. ("if" is a reserved keyword, so I use "IF" in this example, although there may be better names.)
Example with IF():
ul().with(
li().with(
div("Message " + message.getContent()),
IF(message.getUser().equals(currentUser),
a("delete").withHref("http....")
)
)
);
Although a drawback of IF (and also for condWith) is that the code is evaluated even if the condition fails, which can lead to NullPointerExceptions:
IF(message.getUser() != null,
span("User: " + message.getUser().getName()) // still executes if the condition fails
)
For this null problem, the Java 8 Optional class/monads may be used. Example with Optional class:
ul().with(
li().with(
Optional.of(message.getUser()).filter(u -> u.equals(currentUser)).map(
a -> span(a)
).orElseGet(none);
)
);
Optional can also be used with if-else structures:
ul().with(
li().with(Optional.of(pageNumber).filter(p -> p == currentPageNumber).map(p ->
span(p + ""))
.orElseGet(() ->
a(pageNumber + "").withHref("http....")
)
)
);
The advantage of using Optional/monads is that it only evaluates the code when required, and also gives the flexibility to define code (a lambda bodies), although the code is verbose.
My preference: (under change)
Not sure yet what my prefered solution would be. Mixing condWith for if-structures with the ternary operator for if-else-structures feel a bit inconsistent. So then I would probably lean to using the ternary operator with the non-existing none static field.
When I need more safety or when optional if/if-else bodies are expensive, of when more flexibility is needed, I would probably lean to the more verbose Optional/monad approach.
I ran into this issue today when I was trying to add a css file that resided in my java project that I'm using j2html in. I was trying to do this using the following code.
Tag css = styleWithInlineFile("style.css");
However, css was continually being set to null
. Looking through the code, I think I see why. In InlineStaticResource.java
, when the getFileAsString
method is called, the file path is constructed using InlineStaticResource.class.getResource(path)
. However, I believe this method is constructing and incorrect file path. From how I understand the line above to work, it's basically only looking in the directory of InlineStaticResource.java
and below. Which means j2html effectively can't see any files outside of this directory.
I'm using java 8 inside eclipse along with Maven.
Please let me know if my understanding is correct or if I should be able to add a css file given the current code.
Thanks!
The html string generated with j2tml is written to a File using FileUtils.writeStringToFile(outputFile, html) just one longe line.
In build.gradle ->
compile 'com.j2html:j2html:0.7'
In java file ->
import static j2html.TagCreator.*;
Results in 'Cannot resolve symbol 'j2html'
Repository is ->
jcenter()
Currently ContainerTag and EmptyTag share the same 40 convenience methods, but they're manually included in each class. Attempts at refactoring this have been unsuccessful, as I can't seem to find a way to keep the type-information intact (this is important for the fluent-api chaining).
For example, if I move them to Tag (the abstract class they both extend), and do
div().withClass("class").withText()
, I run into problems, because withText()
should be available for ContainerTag objects, but not EmptyTag objects.
I'm sure there's a way though... any thoughts?
That would simplify code in quite a few cases.
It would greatly help
Hi,
First of all, thanks for great work with easy to handle java library.
I got problem, i can't render euro money (โฌ) sign with withText()
method. It is even possible to put into tags some special characters ?
(1) render() as pretty formatted string
an excample is here: "output" section of https://github.com/jmurty/java-xmlbuilder
(2) method name is normally a verb or verb+noun. I renamed all methods withXxx to addXxx. To me it's more friendly,
html().add(body().add( h1("Heading!").addClass("example"), a("asdfac").addHref("url"), br(), p().add(span("this is a line").addStyle("color:red").add(br())) )).render();
Looking into creating a shorthand for adding id/class to elements. Current suggestion:
table($("#my-table.table"),
tbody(
tr($(".table-row"),
td()
)
)
)
<table id="my-table" class="table">
<tbody>
<tr class="table-row">
<td></td>
</tr>
</tbody>
</table>
How to use data-label attr for td. I want to create a table like this.
Account | Due Date | Amount | Period |
---|---|---|---|
Hi | |||
Visa - 3412 | 04/01/2016 | $1,190 | 03/01/2016 - 03/31/2016 |
Visa - 6076 | 03/01/2016 | $2,443 | 02/01/2016 - 02/29/2016 |
Corporate AMEX | 03/01/2016 | $1,181 | 02/01/2016 - 02/29/2016 |
Visa - 3412 | 02/01/2016 | $842 | 01/01/2016 - 01/31/2016 |
Hi,
I tried to use j2html in one of my projects. It is very fast and efficient, but the generated html code is not readable.
Is there any plan to add a format or beautify option to format/indent the generated tags for more readability?
First off, this project is really cool! Unfortunately, the documentation is a bit lacking and more examples would be nice.
I plan on continuing to evaluate j2html and depending on how things go I will help out with the docs.
A great reference for docs:
https://modules.ceylon-lang.org/repo/1/ceylon/html/1.2.2/module-doc/api/index.html
Current structure:
BaseTag (base node)
SimpleTag extends BaseTag (simple tag like <br>
)
Tag extends BaseTag (closed tag like <body></body>
)
Where only Tag (closed tag) has convenience methods
Should maybe be:
Tag (base node)
SimpleTag extends Tag (simple tag like <br>
)
ClosedTag extends Tag (closed tag tag like <body></body>
)
Where Tag (base node) has convenience methods
Or maybe there are better ways of doing it...
I'm requesting a feature here, that is to have an method render(java.io.Writer)
. When creating larger DOM's constructing a larger string might become a hassle, and if you plan to write the resulting string somewhere writing in a writer directly will be a lot faster. The best example of that would be the creation of an website, where creating the string for the whole DOM should be of magnitudes slower than writing it directly.
I suggest creating a method render(java.lang.Appendable)
because this covers Writer
s as well as StringBuilder
.
The compatibility with java 7 should be maintained ?
This test fails.
import static j2html.TagCreator.document;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import j2html.Config;
public class DoctypeTest
{
@Test
public void test ( )
{
Config.closeEmptyTags = true;
assertEquals("<!DOCTYPE html>", document().render());
}
}
Fix:
public static RawHtml document() { return new RawHtml("<!DOCTYPE html>"); }
public static String document(ContainerTag htmlTag) {
if (htmlTag.getTagName().equals("html")) {
return document().render() + htmlTag.render();
}
throw new IllegalArgumentException("Only HTML-tag can follow document declaration");
}
why not support checkbox?what's reason?
I am using j2html just for a few days, so I don't know if it is a bug or a feature:
Using this code:
rawHtml(iff(condition, "<p>Hallo</p>"))
boils down to rawHtml(null)
This gives an error at least with my PrintWriter from Spring Security as it checks the length of the CharSequence which fails with a NPE.
Wouldn't it be better something like this:
public static DomContent iff ( boolean condition, DomContent ifValue ) {
return condition ? ifValue : new NullDomContent();
}
public class NullDomContent extends DomContent {
@Override
public String render ( ) { return ""; }
}
No null check is needed. This could be used in ContainerTag, too:
if (child == null) {
return this; // in some cases, like when using iff(), we ignore null children
}
In DomContent the method render(Appendable writer)
is already implemented and the method render()
is abstract. This should be switched for more performance.
In ContainerTag for example the method looks like this:
@Override
public void render(Appendable writer) throws IOException {
writer.append(renderOpenTag());
if (children != null && !children.isEmpty()) {
for (DomContent child : children) {
child.render(writer);
}
}
writer.append(renderCloseTag());
}
But it would be much easier to implement it like this:
@Override
public void render(Appendable writer) throws IOException {
renderOpenTag(writer);
if (children != null && !children.isEmpty()) {
for (DomContent child : children) {
child.render(writer);
}
}
renderCloseTag(writer);
}
The difference is that in the first method each child is creating and returning a String object while the second method just appends to the same Appendable object in the rendering process.
Otherwise we are just glueing Strings together instead of taking advantage of a StringBuilder.
I will send a PR later on and will add some performance tests, too. Stay tuned...
I came across a situation in which I need something like an invisible parent to generate something like this:
<ul>
<li>First</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>Last</li>
</ul>
This structure is often used in generating paginating bars. The part from 5 to 7 is generated.
In similar situations, you would an extra div:
ul().with(
li("First"),
div().with(
numbers.stream().map(number ->
li(number.toString())
).collect(Collectors.toList())
),
li("Last")
)
But a div directly inside a UL-element is unwanted.
Another option (without creating new classes):
ul().with(
li("First"),
unsafeHtml(
numbers.stream().map(number ->
li(number.toString()).render()
).collect(Collectors.joining(""))
),
li("Last")
)
But the use of unsafeHtml(), render() and joining("") doesn't feel very nice.
Another option would to to create something like an invisible parent tag, a tag that doesn't show its own element, only its children:
ul().with(
li("First"),
group(
numbers.stream().map(number ->
li(number.toString())
).collect(Collectors.toList())
),
li("Last")
)
This can further be improved with a custom java.util.stream.Collector that internally used the group(), so that group() doesn't have to be exposed:
ul().with(
li("First"),
numbers.stream().map(number ->
li(number.toString())
).collect(domContentCollector()),
li("Last")
)
This last one looks very nice imo, with the domContentCollector().
But solution does require Java 1.8 instead of 1.7.
Code: devxzero@bf7e3ac
(Not fully sure whether DomContentCollector is implemented completely correct.)
When I'm doing a "mvn install", I got a Failure in the tests on the "j2html.tags.TagCreatorTest" test.
Running the project with java 8 (oracle) or java 7(open jdk), maven 3.0.5 under linux (Ubuntu 14.04).
Following message in target/surfire-reports/j2html.tags.TagCreatorTest.txt :
org.junit.ComparisonFailure: expected:<[
Any content
but was:<[
Any content
]/body>
Not all Source files are formatted the same. This leads to many unintended changes as my IDE Eclipse usually formats the source code as soon as I save the file I am editing (Save Actions)
I would like to upload a formatting configuration for eclipse which every developer can use. I would just use eclipse standards with longer lines and some tweaks for special cases. But if you can export yours to the root folder would be fine, too.
Then I would like to format the complete source code with this formatting configuration to have everything formatted with the same rules.
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.