Freemarker - Set and get variable name as empty string - freemarker

According to freemarker FAQ I can use any variable name with no limitation:
FreeMarker has no limitations regarding the characters used in variable names, nor regarding the length of the variable names
How can I define in freemarker a variable name as empty string and reference it as
${}
Exception:
freemarker.core.ParseException: Syntax error in template "test.ftlh" in line 1, column 4:
Encountered "}", but was expecting one of:
<STRING_LITERAL>
<RAW_STRING>
"false"
"true"
<INTEGER>
<DECIMAL>
"."
"+"
"-"
"!"
"["
"("
"{"
<ID>
at freemarker.core.FMParser.generateParseException(FMParser.java:5749)
at freemarker.core.FMParser.jj_consume_token(FMParser.java:5608)
at freemarker.core.FMParser.UnaryExpression(FMParser.java:658)
at freemarker.core.FMParser.MultiplicativeExpression(FMParser.java:768)
at freemarker.core.FMParser.AdditiveExpression(FMParser.java:720)
at freemarker.core.FMParser.RangeExpression(FMParser.java:900)
at freemarker.core.FMParser.RelationalExpression(FMParser.java:848)
at freemarker.core.FMParser.EqualityExpression(FMParser.java:811)
at freemarker.core.FMParser.AndExpression(FMParser.java:967)
at freemarker.core.FMParser.OrExpression(FMParser.java:989)
at freemarker.core.FMParser.Expression(FMParser.java:548)
at freemarker.core.FMParser.StringOutput(FMParser.java:1522)
at freemarker.core.FMParser.MixedContentElements(FMParser.java:3721)
at freemarker.core.FMParser.Root(FMParser.java:4411)
at freemarker.template.Template.<init>(Template.java:252)
at freemarker.cache.TemplateCache.loadTemplate(TemplateCache.java:549)
at freemarker.cache.TemplateCache.getTemplateInternal(TemplateCache.java:439)
at freemarker.cache.TemplateCache.getTemplate(TemplateCache.java:292)
at freemarker.template.Configuration.getTemplate(Configuration.java:2654)
at freemarker.template.Configuration.getTemplate(Configuration.java:2503)
at com.FreemarkerTest.main(FreemarkerTest.java:46)
I also tried ${""} by assigning empty variable but it ignores the value assigned:
<#assign ""="aa">
${""}
Normally in a map I can assign a variable with empty string and get it.

While all kind of variable names are allowed (in the data-model at least), they aren't necessarily convenient to refer to. In this case you had to write ${.vars['']}.
Note that the syntax is not "${" VariableName "}", but the more generic "${" Expression "}", so you can write things like ${x + 1}, or even ${1 + 1} (no variable reference in it at all). Thus ${} contains an empty expression (which is invalid), not a variable reference of any kind.

Related

Power Automate - Subtract two integer variables

I am trying to subtract two integer values as such:
But I get this error:
Unable to process template language expressions in action 'Negative_Index_of_Snabel-a' inputs at line '0' and column '0': 'The template language function 'sub' expects its first parameter to be an integer or a decimal number. The provided value is of type 'String'. Please see https://aka.ms/logicexpressions#sub for usage details.'.
I know that my variables in the sub() function is in quotes. But I cannot save it otherwise.
You're passing in literal string values, you need to specify that the values you want to evaluate are variables, like thus ...
sub(variables('VarMailInt'),variables('VarSnabelaIndex'))

Appending the title property of a variable to this string? [duplicate]

I have the following code:
$DatabaseSettings = #();
$NewDatabaseSetting = "" | select DatabaseName, DataFile, LogFile, LiveBackupPath;
$NewDatabaseSetting.DatabaseName = "LiveEmployees_PD";
$NewDatabaseSetting.DataFile = "LiveEmployees_PD_Data";
$NewDatabaseSetting.LogFile = "LiveEmployees_PD_Log";
$NewDatabaseSetting.LiveBackupPath = '\\LiveServer\LiveEmployeesBackups';
$DatabaseSettings += $NewDatabaseSetting;
When I try to use one of the properties in a string execute command:
& "$SQlBackupExePath\SQLBackupC.exe" -I $InstanceName -SQL `
"RESTORE DATABASE $DatabaseSettings[0].DatabaseName FROM DISK = '$tempPath\$LatestFullBackupFile' WITH NORECOVERY, REPLACE, MOVE '$DataFileName' TO '$DataFilegroupFolder\$DataFileName.mdf', MOVE '$LogFileName' TO '$LogFilegroupFolder\$LogFileName.ldf'"
It tries to just use the value of $DatabaseSettings rather than the value of $DatabaseSettings[0].DatabaseName, which is not valid.
My workaround is to have it copied into a new variable.
How can I access the object's property directly in a double-quoted string?
When you enclose a variable name in a double-quoted string it will be replaced by that variable's value:
$foo = 2
"$foo"
becomes
"2"
If you don't want that you have to use single quotes:
$foo = 2
'$foo'
However, if you want to access properties, or use indexes on variables in a double-quoted string, you have to enclose that subexpression in $():
$foo = 1,2,3
"$foo[1]" # yields "1 2 3[1]"
"$($foo[1])" # yields "2"
$bar = "abc"
"$bar.Length" # yields "abc.Length"
"$($bar.Length)" # yields "3"
PowerShell only expands variables in those cases, nothing more. To force evaluation of more complex expressions, including indexes, properties or even complete calculations, you have to enclose those in the subexpression operator $( ) which causes the expression inside to be evaluated and embedded in the string.
#Joey has the correct answer, but just to add a bit more as to why you need to force the evaluation with $():
Your example code contains an ambiguity that points to why the makers of PowerShell may have chosen to limit expansion to mere variable references and not support access to properties as well (as an aside: string expansion is done by calling the ToString() method on the object, which can explain some "odd" results).
Your example contained at the very end of the command line:
...\$LogFileName.ldf
If properties of objects were expanded by default, the above would resolve to
...\
since the object referenced by $LogFileName would not have a property called ldf, $null (or an empty string) would be substituted for the variable.
Documentation note: Get-Help about_Quoting_Rules covers string interpolation, but, as of PSv5, not in-depth.
To complement Joey's helpful answer with a pragmatic summary of PowerShell's string expansion (string interpolation in double-quoted strings ("...", a.k.a. expandable strings), including in double-quoted here-strings):
Only references such as $foo, $global:foo (or $script:foo, ...) and $env:PATH (environment variables) can directly be embedded in a "..." string - that is, only the variable reference itself, as a whole is expanded, irrespective of what follows.
E.g., "$HOME.foo" expands to something like C:\Users\jdoe.foo, because the .foo part was interpreted literally - not as a property access.
To disambiguate a variable name from subsequent characters in the string, enclose it in { and }; e.g., ${foo}.
This is especially important if the variable name is followed by a :, as PowerShell would otherwise consider everything between the $ and the : a scope specifier, typically causing the interpolation to fail; e.g., "$HOME: where the heart is." breaks, but "${HOME}: where the heart is." works as intended.
(Alternatively, `-escape the :: "$HOME`: where the heart is.", but that only works if the character following the variable name wouldn't then accidentally form an escape sequence with a preceding `, such as `b - see the conceptual about_Special_Characters help topic).
To treat a $ or a " as a literal, prefix it with escape char. ` (a backtick); e.g.:
"`$HOME's value: $HOME"
For anything else, including using array subscripts and accessing an object variable's properties, you must enclose the expression in $(...), the subexpression operator (e.g., "PS version: $($PSVersionTable.PSVersion)" or "1st el.: $($someArray[0])")
Using $(...) even allows you to embed the output from entire commands in double-quoted strings (e.g., "Today is $((Get-Date).ToString('d')).").
Interpolation results don't necessarily look the same as the default output format (what you'd see if you printed the variable / subexpression directly to the console, for instance, which involves the default formatter; see Get-Help about_format.ps1xml):
Collections, including arrays, are converted to strings by placing a single space between the string representations of the elements (by default; a different separator can be specified by setting preference variable $OFS, though that is rarely seen in practice) E.g., "array: $(#(1, 2, 3))" yields array: 1 2 3
Instances of any other type (including elements of collections that aren't themselves collections) are stringified by either calling the IFormattable.ToString() method with the invariant culture, if the instance's type supports the IFormattable interface[1], or by calling .psobject.ToString(), which in most cases simply invokes the underlying .NET type's .ToString() method[2], which may or may not give a meaningful representation: unless a (non-primitive) type has specifically overridden the .ToString() method, all you'll get is the full type name (e.g., "hashtable: $(#{ key = 'value' })" yields hashtable: System.Collections.Hashtable).
To get the same output as in the console, use a subexpression in which you pipe to Out-String and apply .Trim() to remove any leading and trailing empty lines, if desired; e.g.,
"hashtable:`n$((#{ key = 'value' } | Out-String).Trim())" yields:
hashtable:
Name Value
---- -----
key value
[1] This perhaps surprising behavior means that, for types that support culture-sensitive representations, $obj.ToString() yields a current-culture-appropriate representation, whereas "$obj" (string interpolation) always results in a culture-invariant representation - see this answer.
[2] Notable overrides:
• The previously discussed stringification of collections (space-separated list of elements rather than something like System.Object[]).
• The hashtable-like representation of [pscustomobject] instances (explained here) rather than the empty string.
#Joey has a good answer. There is another way with a more .NET look with a String.Format equivalent, I prefer it when accessing properties on objects:
Things about a car:
$properties = #{ 'color'='red'; 'type'='sedan'; 'package'='fully loaded'; }
Create an object:
$car = New-Object -typename psobject -Property $properties
Interpolate a string:
"The {0} car is a nice {1} that is {2}" -f $car.color, $car.type, $car.package
Outputs:
# The red car is a nice sedan that is fully loaded
If you want to use properties within quotes follow as below. You have to use $ outside of the bracket to print property.
$($variable.property)
Example:
$uninstall= Get-WmiObject -ClassName Win32_Product |
Where-Object {$_.Name -like "Google Chrome"
Output:
IdentifyingNumber : {57CF5E58-9311-303D-9241-8CB73E340963}
Name : Google Chrome
Vendor : Google LLC
Version : 95.0.4638.54
Caption : Google Chrome
If you want only name property then do as below:
"$($uninstall.name) Found and triggered uninstall"
Output:
Google Chrome Found and triggered uninstall

ODI: KM Java BeanShell - escape double quotes

I want to set a variable inside Knowledge Module's Task, with target technology set to Java BeanShell. The value represents mapping EXPRESSIONs, where source table is inside MSSQL database. Column names are surrounded by double quotes, that causes a problem with templating.
Column expression is:
source_tab."Entry Number"
Task (Java BeanShell)
<$
String SEL_COLS = "<%=odiRef.getColList(0, "", "[EXPRESSION]\t[ALIAS_SEP] [CX_COL_NAME]", ",\n\t", "", "")%>";
$>
This variable assignment fails, because " in source_tab."Entry Number" is not escaped - code does not compile.
odiRef.getQuotedString does not solve the problem...
odiRef.getQuotedString could help if generated code is executed as a final code in JBS technology. When we use it in the following way (in ?-, $- or #-substitution):
<$
String SEL_COLS = <%=odiRef.getQuotedString(odiRef.getColList(0, "", "[EXPRESSION]\t[ALIAS_SEP] [CX_COL_NAME]", ",\n\t", "", ""))%>;
$>
then result fails like this:
... Caused by: org.apache.bsf.BSFException: BeanShell script error:
Parse error at line 3, column 37. Encountered: Entry BSF info: ....
... 11 more
Text: <$
String SEL_COLS = "SOURCE_TAB.\"Entry Number\" ENTRY_NUMBER";
$>.
This looks good but does not work. It could work as final code (I mean result of all substitutions) in JBS Technology. Unfortunately any substitutions eats backslashes.
Ok, if standard odiRef-functtion does not work, lets write our own:
<%
String getQuotedStringCustomized(String s){
return '"'+s.replaceAll('"'.toString(),'"'+"+'"+'"'+"'+"+'"')+'"';
}
%>
-- other code........
<$
String SEL_COLS = <%=getQuotedStringCustomized(odiRef.getColList(0, "", "[EXPRESSION]\t[ALIAS_SEP] [CX_COL_NAME]", ",\n\t", "", ""))%>;
$>
Only the way to put " into a Java literal within the JBS Substitution is contatenation with Char literal '"' or using '"'.toString() expression if it is impossible to use Char type.
FINALLY:
In final JBS code you may use \", but within substitutions only +'"'+.

Why is `?something` invalid?

?. is a string literal:
?. #=> "."
However, I failed to declare a variable with a name like that:
?some_var = 100 #=> Error
How is?something invalid when ?. is valid?
? cannot describe any string literal; it is valid only for a single character.
Even if ?something were a valid string literal (counter to fact),
?something = ...
will be assignment to a string, which does not make sense. You cannot assign a value to a string.
?a is the same as "a". So it is a value, which belongs on the right hand side of an assignment, not the left hand side. It is not a variable name.
The Syntax exists as a relic from Ruby <=1.9, where it was equivalent to "a".bytes[0] and ?d could be used to shave off one character of code golf. I haven't seen any legitimate use otherwise.

Using variable in XQuery expressions

using Xquery, how can I embed variable in an xquery expression on the following xml document. I have the following xml document
<CD>
<TITLE>Picture book</TITLE>
<ARTIST>Simply Red</ARTIST>
<COUNTRY>EU</COUNTRY>
<COMPANY>Elektra</COMPANY>
<PRICE>7.20</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>Red</TITLE>
<ARTIST>The Communards</ARTIST>
<COUNTRY>UK</COUNTRY>
<COMPANY>London</COMPANY>
<PRICE>7.80</PRICE>
<YEAR>1987</YEAR>
</CD>
<CD>
<TITLE>Unchain my heart</TITLE>
<ARTIST>Joe Cocker</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>EMI</COMPANY>
<PRICE>8.20</PRICE>
<YEAR>1986</YEAR>
</CD>
I need to issue a query to return all the CDs with YEAR > 1986. I want like to have the components of the "where" clause as variables, I mean storing YEAR > 1986 in to three variables and use the variables in the query,
here what I have so far
String queryString =
"declare variable $field :=" +"YEAR"+";"+
"declare variable $operator :=" +">"+";"+
"declare variable $value :=" +"1986"+";"+
"declare variable $docName as xs:string external;" + sep +
"for $cat in doc($docName)/*/"+ "CD" +
"where $cat/$field $operator $value" +
"order by $cat/$field" +
"return $cat";
XQExpression expression = conn.createExpression();
expression.bindString(new QName("docName"), filename,
conn.createAtomicType(XQItemType.XQBASETYPE_STRING));
results = expression.executeQuery(queryString);
return results.getSequenceAsString(new Properties());
My query expression isn't perfect, I think I am having trouble in using the variables, any one can help me in solving this please?
Thanks
Variables in XQuery (and XSLT/XPath) represent values, not fragments of program text. That is, it's not a macro language - variables don't work by textual substitution.
Using a variable for the value is straightforward: x = $value.
Using a variable for the element name isn't too difficult: *[name()=$n] = $value
But using a variable for the operator isn't possible. When you get to this level it's better to generate the query as a string using string concatenation, and then compile it and execute it. In fact you seem to be generating the query as a string anyway (without worrying about the risk of code injection, I see).

Resources