I have an XML node like this:
<table version="1.0" border="1" rules="all" cellpadding="10">
.
.
.
</table>
I want Freemarker to "echo" this, but exclude the version attribute, giving this:
<table border="1" rules="all" cellpadding="10">
.
.
.
</table>
I believe I need to use a macro something like this:
<#macro table>
<table [include all attributes except version]>
<#recurse>
</table>
</#macro>
But I don't know what goes in the '[include all attributes except version]' section.
How do I do this?
FreeMarker's XML wrapper is not really for transforming XML to a similar XML, it's just a way of exposing data... But, if you stretch it a bit, it's possible after all (using http://freemarker-online.kenshoo.com/):
Template:
<#visit doc>
<#macro table>
<table<#atts except=['a', 'c'] />>
<#recurse>
</table>
</#macro>
<#macro atts element=.node except=[]>
<#list element.## as att>
<#if !except?seqContains(att.##qname)> ${att.##qname}="${att?xml}"</#if><#t>
</#list>
</#macro>
Data model:
doc=<table a="1" b='2' c='3' />
There are some traps in this, however, if you have attributes that belong to a namespace. Then you will need the prefixes to be declared with <#ftl nsPrefixes="...">.
Related
We have an Java application which reads information from DB and generates HTML table via Freemarker like this:
<#if marks?size != 0>
<div>
<p>
<b>Total rows with information about broken utm-marks for ${date} is: ${total}. Displayed in current report: ${displayed}</b>
</p>
<br/>
</div>
<table border="1" cellspacing="0" cellpadding="1">
<tr class="tableHeader" style = "background-color:#f8f5e4; text-align:center; font-weight: bold;">
<th>Report date</th>
<th>Account Login</th>
<th>View Id</th>
<th>Utm marks</th>
<th>Exception type</th>
<th>Exception message</th>
</tr>
<#list marks as mark>
<tr class="tableBody">
<td>${(mark.reportDate)!""}</td>
<td>${(mark.accountLogin)!""}</td>
<td>${(mark.accountViewId)!""}</td>
<td>${(mark.utmMarks)!""}</td>
<td>${(mark.exceptionType)!""}</td>
<td>${(mark.exceptionMessage)!""}</td>
</tr>
</#list>
</table>
<br/>
<#else>
<div>
<p>
<b>No information about broken utm marks for ${date}.</b>
</p>
</div>
</#if>
This generated table will be sent to configured email.
Is it possible to build this type of application with Apache NiFi (without and with ExecuteScript)? Read from DB - fine; send email - fine; but what about templates and html table?
create ./templates folder in nifi root folder
put there a template file test.ftlh with content:
<html>
<head>
<title>Welcome!</title>
</head>
<body>
<h1>Welcome ${user}!</h1>
<p>Our latest product:
${latestProduct.name}!
</body>
</html>
use GenerateFlowFile to inject following json into flow file:
{
"user":"Big Joe",
"latestProduct": {
"name":"green mouse",
"url":"aaa/bbb/ccc"
}
}
use ExecuteGroovyScript to merge template with data
#Grab(group='org.freemarker', module='freemarker', version='2.3.31')
import freemarker.template.*
import groovy.json.*
class Const{
static Configuration cfg
}
//on processor start
static onStart(ProcessContext context){
Const.cfg = new Configuration(Configuration.VERSION_2_3_29)
Const.cfg.with{
setDirectoryForTemplateLoading(new File("./templates"))
setDefaultEncoding("UTF-8")
setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER)
setLogTemplateExceptions(false)
setWrapUncheckedExceptions(true)
setFallbackOnNullLoopVariable(false)
}
}
//flowfile process
def ff=session.get()
if(!ff)return
ff.write{InputStream rawIn, OutputStream rawOut->
//assume json in flowfile
def root = new JsonSlurper().parse(rawIn)
Template tpl = Const.cfg.getTemplate("test.ftlh")
rawOut.withWriter("UTF-8"){w-> tpl.process(root, w) }
}
REL_SUCCESS << ff
One way to do this without ExecuteScript (or similiar) would be:
put the HTML template-text in a NiFi process group variable
then use NiFi expression language function evaluateELString to substitute the flowfile attributes into the template.
This approach would have the advantage of being easy to maintain: the HTML template-text could be with the process group; there is no scripting code to maintain.
To illustrate this approach, suppose you put the HTML template-text into a process group variable, named email_template. Further, suppose a flowfile has the attributes set that are required by the HTML template (e.g., from a database). Then to get the realized email body, put the NiFi expression ${email_template:evaluateELString()} in the value for the Replacement Value property of the ReplaceText processor (which precedes the PutEmail processor).
In the illustration above, the variable,email_template could be set to:
<#if marks?size != 0>
<div>
<p>
<b>Total rows with information about broken utm-marks for ${date} is: ${total}. Displayed in current report: ${displayed}</b>
</p>
<br/>
</div>
<table border="1" cellspacing="0" cellpadding="1">
<tr class="tableHeader" style = "background-color:#f8f5e4; text-align:center; font-weight: bold;">
<th>Report date</th>
<th>Account Login</th>
<th>View Id</th>
<th>Utm marks</th>
<th>Exception type</th>
<th>Exception message</th>
</tr>
<#list marks as mark>
<tr class="tableBody">
<td>${mark.reportDate}</td>
<td>${mark.accountLogin}</td>
<td>${mark.accountViewId}</td>
<td>${mark.utmMarks}</td>
<td>${mark.exceptionType}</td>
<td>${mark.exceptionMessage}</td>
</tr>
</#list>
</table>
<br/>
<#else>
<div>
<p>
<b>No information about broken utm marks for ${date}.</b>
</p>
</div>
</#if>
...and ${email_template:evaluateELString()} would substitute the flowfile attribute values for date, total, displayed, mark.reportDate, etc.
I would like in Freemaker that my value is listed in 2 columns.
My code so far :
<#list orderItem.options as option>
<tr>
<td style="font-family: Arial,Helvetica,sans-serif;font-size: 16px;">
<div class="row">
<#if option.fileUrls??>
<span>
<span>${option.name}:
</span>
<#fileLinks option.fileUrls = "option.fileUrls"/>
</span>
<#else>
<#if option.value != 'Geen'>
<div class="column">${option.name}: ${option.value}</div>
${option.name}: ${option.value}
- -
</#if>
</#if>
</div>
</td>
</tr>
</#list>
So I want :
I have a webshop where people can buy food.
Food can have multiple options : Size, Salt, Saus
I want that my products will be printed in my mail this way :
Product name : Product name:
Size: small Size: Big
Salt : Yes Salt: no
Saus: Mayonaise Saus: Cocktail
You really should be limiting the scope of your question's example. I am not sure what the extra markup should do, or where it should be placed. But is it something like this you are looking for?
<table>
<#list orderItem.options as option>
<#if option.fileUrls??>
<tr>
<td>
<span>${option.name}</span>
<span><#fileLinks option.fileUrls/></span>
</td>
<td>
<#if option.value != 'Geen'>
<span>${option.value}</span>
</#if>
</td>
</tr>
</#if>
</#list>
</table>
I am sorry if this is not exactly what you are looking for, but your example is confusing. At least you might take my example response and go from there.
I have couple questions if you don't mind:
Is Product name also part of the options stored in orderItem.options ?
Is having file link exclusive to a certain option ?
Please edit your question and post the Java model (class) OrderItem
I got what you want, need to know your design approach to provide the best solution that suites your design.
I try to integrate a name from json in a path to an image
I already used this and don't really help because the program "can't resolve" the path:
"./photos/${{row.name}}.jpg"
"./photos/${row.name}.jpg"
"./photos/"+{row.name}+".jpg"
var x = {row.name}
"./photos/${x}.jpg"
{items.map(row =>(
<tr>
<td>
<Link to="/doctor">
<img
src={require("./photos/${{row.name}}.jpg")}
className="d-inline-block align-top"
alt={""}
/>{row.name}
</Link>
</td>
I expect ./photos/nameFromJson.jpg but it can't be resolved
If you want to use variables inside a string, the best way to do that is using template literals.
The template literals should look like this:
`string ${expression} string`
So, the code snippet that you provided, should look like this:
{items.map(row => (
<tr>
<td>
<Link to="/doctor">
<img
src={require(`./photos/${row.name}.jpg`)}
className="d-inline-block align-top"
alt=""
/>
<span>{row.name}</span>
</Link>
</td>
</tr>
))}
If your image names are correct, and everything is inside the photos then it should work like a charm. Basically you have made a few syntax mistake.
I'm trying to wrap my head around BEM naming convention in CSS, but for some parts I find it bit confusing.
In my case, my HTML (on a rough level) looks like this:
<div class="wrapper">
<img src="images/img.png">
<span class="header">Heading</span>
<table>
<tbody>
<tr>
<td class="itemInfo">
<span class="item">Item</span>
<span class="itemDetails">Item Details</span>
</td>
<td class="itemDate">01/01/1980</td>
</tr>
</tbody>
</table>
</div>
In my CSS I have defined styles for the .wrapper, .header, .item, .itemInfo, .itemDetails and .itemDate classes. Turning these into BEM should be straightforward.
However, my questions are related to some other tags in my HTML:
1) How do I deal with the IMG tag? It has styling defined in my CSS file:
img {
style definition 1;
style definition 2;
..
}
Should I BEM this element, both in HTML and in CSS files, by giving image tag a CSS class with BEM convention in my HTML file and also defining this very same class in my CSS, too?
2) In my example, how is TABLE tag understood in the BEM context? In other words, TABLE and TD selectors have their own style definitions in my CSS file (the same way as the IMG tag). Should I also treat those tags the same way as in the case of IMG tag (with/without BEM)?
BEM is designed to provide clarity to developers reading code, especially since CSS/Sass can get convoluted easily. For your <img> tag, I can make one of two assumptions:
You have styling you want to apply to all images, but also
specific styles to apply to this.
There are no other <img> tags and it doesn't matter.
Either way, you should create some CSS classes like so
.standard-img{
rule1: universal-value;
rule2: universal-value;
}
.img-to-style{
rule1: that-only-applies-to-this-img;
}
Obviously, your <img> HTML should look like this, then:
<img class="standard-img img-to-style" src="blah" />
As for the Table, what does it do? I'd do something like this:
<table class="ItemsTable">
<tbody>
<tr class="table__item-row">
<td class="item-row__info">
<span></span>
<span></span>
</td>
<td class="item-row__date">
// Content
</td>
</tr>
</tbody>
</table>
Makes sense, right? Mirror it in your CSS.
I have to get the XPATH for dynamic Ids . The code look like this
<table width="100%" role="presentation">
<tbody>
<tr>
<tr>
<td id="DWT10" role="presentation">
<div id="zl__TV-main__rows" class="DwtListView-Rows" style="height: 130px; width: 377px;">
<div id="zli__TV-main__654" class="RowDouble RowEven " role="treeitem" tabindex="0" aria-label="Unread, hello everyone, Wilkerson, 12:26 AM" aria-posinset="1" aria-level="1">
My XPATH goes like this :
//div[starts-with(#id='zl__CLV-main') and ./div [contains(#aria-posinset,'1')]]
I am getting:
Could not evaluate XPATH error.
XPAth only works if you have a valid XML source file. In your example there are no closing tags.
Your XPATH is invalid. the start-with function must be changed to
//div[starts-with(#id,'zl__CLV-main')
comma instead of =