NetSuite Advanced PDF Template - Freemarker syntax - freemarker

I have a custom body field custbody_deposit_number that may have 2 values separated by a comma. I need to understand the syntax of the freemarker ?split built in. This is what the freemarker site says about ?split:
<#list "someMOOtestMOOtext"?split("MOO") as x>
- ${x}
</#list>
Prints
some
test
text
can anyone provide help on how to implement my field in the ?split syntax?

Like this:
<#list custbody_deposit_number?split(',') as x>
- ${x}
</#list>
You may also want to remove space around the commas, either via ${x?trim} or using ?split(r'\s*,\s*', 'r')

this is how we finally solved this issue:
<#if record.custbody_deposit_numbers?has_content>
<#list record.custbody_deposit_numbers?string?split(",") as x>
<tr>
<td align="center">${x}</td>
<td align="center">
<#assign depositdate = record.custbody_deposit_dates?string?split(",")[x_index]>
${depositdate}
</td>
<td align="right">
<#assign depositAmt = record.custbody_deposit_amount?string?split(",")[x_index]>
<#assign depositAmt1 = depositAmt?number>
${depositAmt1?string.currency}
</td>
</tr>
</#list>

Related

Xpath: Wildcards for descendant nodes not working

Desired output: 3333
<tbody>
<tr>
<td class="name">
<p class="desc">Intel</p>
</td>
</tr>
Other tr tags
<tr>
<td class="tel">
<p class="desc">3333</p>
</td>
</tr>
</tbody>
I want to select the last tr tag after the tr tag that has "Intel" in the p tag
//tbody//tr[td[p[contains(text(),'Intel')]]]/followingsibling::tr[position()=last()]//p/text()
The above works but I don't wish to reference td and p explicitly. I tried wildcards ? or *, but it doesn't work.
//tbody//tr[?[?[contains(text(),'Intel')]]]/followingsibling::tr[position()=last()]//p/text()
"...which contains a text node equal to 'Intel'"
//tbody/tr[.//text() = 'Intel']/following-sibling::tr[last()]/td/p/text()
"...which contains only the string 'Intel', once you remove all insignificant white-space"
//tbody/tr[normalize-space() = 'Intel']/following-sibling::tr[last()]/td/p/text()
I think the key take-away here is that you can use descendant paths (//) and pay attention to context in predicates once you make them relative (.//).

Xpath - How to select related cousin data

<html>
<table border="1">
<tbody>
<tr>
<td>
<table border="1">
<tbody>
<tr>
<th>aaa</th>
<th>bbb</th>
<th>ccc</th>
<th>ddd</th>
<th>eee</th>
<th>fff</th>
</tr>
<tr>
<td>111</td>
<td>222</td>
<td>333</td>
<td>444</td>
<td>555</td>
<td>666</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</html>
How can i select specific related cousin data using xpath, The desired output would be be:
<th>aaa</th>
<th>ccc</th>
<th>fff</th>
<td>111</td>
<td>333</th>
<td>666</td>
The most important aspect of the xpath is that i am looking to be able to include or exclude certain <th> tags and their corresponding <td>tags
So based on the answers so far the closest I have is:
//th[not(contains(text(), "ddd"))] | //tr[2]/td[not(position()=4)]
Is there any way of not explicitly using position()=4 but instead reference the corresponding th tag
Using XPath 3.0 you can structure that into
let $th := //table/tbody/tr[1]/th,
$filteredTh := $th[not(. = ("bbb", "ddd", "eee"))],
$pos := $filteredTh!index-of($th, .)
return ($filteredTh, //table/tbody/tr[position() gt 1]/td[position() = $pos])
I'm not sure that this is the best solution, but you might try
//th[not(.="bbb") and not(.="ddd") and not(.="eee")] | //tr[2]/td[not(position()=index-of(//th, "bbb")) and not(position()=index-of(//th, "ddd")) and not(position()=index-of(//th, "eee"))]
or shorter version
//th[not(.=("bbb", "ddd", "eee"))]| //tr[2]/td[not(position()=(index-of(//th, "bbb"), index-of(//th, "ddd"),index-of(//th, "eee")))]
that returns
<th>aaa</th>
<th>ccc</th>
<th>fff</th>
<td>111</td>
<td>333</td>
<td>666</td>
You can avoid using complicated XPath expressions to get required output. Try to use Python + Selenium features instead:
# Get list of th elements
th_elements = driver.find_elements_by_xpath('//th')
# Get list of td elements
td_elements = driver.find_elements_by_xpath('//tr[2]/td')
# Get indexes of required th elements - [0, 2, 5]
ok_index = [th_elements.index(i) for i in th_elements if i.text not in ('bbb', 'ddd', 'eee')]
for i in ok_index:
print(th_elements[i].text)
for i in ok_index:
print(td_elements[i].text)
Output is
'aaa'
'ccc'
'fff'
'111'
'333'
'666'
If you need XPath 1.0 solution:
//th[not(.=("bbb", "ddd", "eee"))]| //tr[2]/td[not(position()=(count(//th[.="bbb"]/preceding-sibling::th)+1, count(//th[.="ddd"]/preceding-sibling::th)+1, count(//th[.="eee"]/preceding-sibling::th)+1))]

XPath: Getting a node by attribute value of subnode

People, could you please help me with this XPATH. Lets say I have the following HTML code
<table>
<tr>
<td class="clickable">text</td>
<td>value1</td>
</tr>
<tr>
<td>value2</td>
<td>text</td>
</tr>
</table>
I need to build a XPath that will pick <tr>that have <td> with value text AND attribute class equals clickable.
I tried the following xpath:
//tr[contains(.,'text')][contains(./td/#class,'clickable')]
//tr[contains(.,'text')][contains(td/#class,'clickable')]
but none of those worked
Any help is appreciated
Thanks
You are almost there:
//tr[contains(td/#class,'clickable') and contains(td, 'text')]
Demo using xmllint:
$ xmllint input.xml --xpath "//tr[contains(td/#class,'clickable') and contains(td, 'text')]"
<tr>
<td class="clickable">text</td>
<td>value1</td>
</tr>
If you find tr with a td having value text and a td (maybe, another) with attribute class equals clickable, use answer of #alecxe.
If that is one td with two condition then
//tr[td[.='text' and #class='clickable']]

Xpath: howto return empty values

I have an Xpath like following:
"//<path to some table>/*/td[1]/text()"
and it returns text values of all non-empty tds, for example:
<text1>, <text2>, <text3>
But the problem is that between nodes, that contain mentioned values could be some empty tds elements:
What i want is to get result that contain some identifiers, that there is those empty values, for example:
<text1>,<>, <>, <text2>, <text3>, <>
or
<text1>,<null>, <null>, <text2>, <text3>, <null>
I tried to use next one:
"//<path to some table>/*/string(td[1]/text())"
but it returns undefined
Of course, I could just get whole node and then work with it in my code (cut all unnecessary info), but may be there is a better way?
html example for that case:
<html>
<body>
<table class="tablesorter">
<tbody>
<tr class="tr_class">
<td>text1</td>
<td>{some text}</td>
</tr>
<tr class="tr_class">
<td></td>
<td>{some text}</td>
</tr>
<tr class="tr_class">
<td>text2</td>
<td>{some text}</td>
</tr>
<tr class="tr_class">
<td>text3</td>
<td>{some text}</td>
</tr>
<tr class="tr_class">
<td></td>
<td>{some text}</td>
</tr>
</tbody>
</table>
</body>
</html>
Well simply select the td elements, not its text() child nodes. So with the path changed to //<path to some table>/*/td[1] or maybe //<path to some table>/*/td you will get a node-set of td elements, whether they are empty or not, and you can then access the string contents of each node (with XPath (select string(.) for each element node) or host environment method e.g. textContent in the W3C DOM or text in the MSXML DOM.). That way the empty strings will be included.
In case you use XPath 2.0 or XQuery you can directly select //<path to some table>/*/td/string(.) to have a sequence of string values. But that approach with a function call in the last step is not supported in XPath 1.0, there you can select the td element nodes and then access the string value of each in a separate step.
Do you mean you want only the td[1] with text and get rid of ones without text? If so, you can use this xpath
//td[1][string-length(text()) > 1]

What's the meaning of !"" within a variable expression in freemarker?

I have the following code from the apache ofbiz development book:
<#macro displayData data>
<#if data?is_sequence>
<#assign keys = data?first?keys/>
<#else>
<#assign keys = data?keys/>
</#if>
<#-- Header -->
<tr>
<#list keys as key>
<td class="dark-grid"><b>${key}</b></td>
</#list>
</tr>
<#-- Data -->
<#if data?is_sequence>
<#list data as record>
<tr>
<#list keys as key>
<td class="light-grid">${record[key]!""}</td>
</#list>
</tr>
</#list>
<#else>
<tr>
<#list keys as key>
<td class="light-grid">${data[key]!""}</td>
</#list>
 <h1>Processed script: "${parameters.scriptName}"</h1>
<#if data?has_content && (data?is_sequence || data?is_hash)>
</tr> </#if>
</#if>
</#macro>
when I try to display something in the front end I get the following error:
Error on line 31, column 38 in component://crmsfa/webapp/crmsfa/tests/displayData.ftl Expecting a string, date or number here, Expression record[key]!"" is instead a freemarker.ext.beans.SimpleMethodModel The problematic instruction: ---------- ==> ${record[key]!""} [on line 31, column 36 in component://crmsfa/webapp/crmsfa/tests/displayData.ftl] in user-directive displayData [on line 7, column 9 in component://crmsfa/webapp/crmsfa/tests/displayData.ftl] ---------- Java backtrace for programmers: ---------- freemarker.core.NonStringException: Error on line 31, column 38 in component://crmsfa/webapp/crmsfa/tests/displayData.ftl Expecting a string, date or number here, Expression record[key]!"" is instead a freemarker.ext.beans.SimpleMethodModel at freemarker.core.Expression.getStringValue(Expression.java:126) at
freemarker.core.Expression.getStringValue(Expression.java:93)
I would like to know two things in order that I may be able to debug this first I've never come across a ${record[key]!""} (the !"" inside the variable) or <#assign keys = data?first?keys/> could someone please explain the semantic meaning of these two expressions.
The reason of the error is that the type of data[key] is not appropriate. The !'' part has no role in the failing case, as that only kicks in if data[key] is null or missing.
Otherwise please use the manual, it describes the meaning of those operators as well as anybody here could: http://freemarker.org/docs/dgui_template_exp.html#exp_cheatsheet

Resources