FreeMarker interpolation results used inline with a second interpolation - freemarker

Let me start with I'm not a programmer by trade, but I'm learning the best I can. I'm trying to build a template to take the result of one FreeMarker interpolation result and use that as a variable for another. I hope I'm using the terms correctly.
For example, I want the result of (entity.customer.organization.name) to be used in:
${blurb["organizationXXXAttire"]!}
Where XXX is the result of (entity.customer.organization.name)
If it was just a blurb with out a variable company name it would look like:
${blurb["organizationCompanyAttire"]!}
I thought the following would work but it did not:
<#assign organization = (entity.customer.organization.name)>
${blurb["organization<#organization?interpret>Attire"]!}
Thanks in advance for any suggestions.

It's simply ${blurb["organization${entity.customer.organization.name}Attire"]!}.
?interpret is only needed if you have a string that contains a piece of template. Besides you can't call directives (<#...>, <#...>) inside an expression.

Related

Wrap all the strings with single quotas

Let's assume that my template is like a following
string1=${obj.firstString}
string2=${obj.secondString}
number1=${obj.firstNumber}
I'm looking for some automatic way to wrap all my string parameters with single quotas? The expected output is
string1='A'
string2='B'
number1=42
I understand that I can write string1=${"'" + obj.firstString + "'"} , but maybe there is some more conventional way for this requirement...
Thanks a lot!
I would just do this:
string1='${obj.firstString}'
string2='${obj.secondString}'
number1=${obj.firstNumber}
It's a template language, so the basic idea is to make your program look similar to its own output.

How to load value from dynamically specified parameter in NiFi

I have several processes with almost same flow like "Get some parameters, extract data from database according to them and upload them to target". The parameters vary slightly across processes as well as targets but only a bit. Most of the process is the same. I would like to extract those differences to parameter-context and dynamically load them. My idea is to have parameters defined following way and then using them.
So core of question is:
How to dynamically choose which parameter group load and use?
Having several parameter contexts with same-named/different-valued parameters and dynamically switching them would be probably the best, but it is not possible as far as I know.
Also duplicating flows is out-of-the-table. Any error correction would be spread out over several places and maintenance would be a nightmare.
Moreover, I know I can do it like "In GenetrateFlowFile for process A set value1=#{A_value1} and in GenetrateFlowFile for process B set value1=#{B_value1}. But this is tedious, error-prone and scales kinda bad. Not speaking of situation when I can have dozens of parameters and several processes. Also it is a kind of hardcoding, not configuring...
I was hoping for something like defining group=A and then using it like value1=#{ ${ group:append('_value1') } } but this does not work - it is evaluated as parameter literally named ${ group:append('_value1') }.
TL;DR: Use evaluateELString().
The actual solution is to set in GenetrateFlowFile processor group=A and in next UpdateAttribute processor set the following:
value1=${ group:prepend('hash{ '):append('_value1 }'):replace('hash', '#'):evaluateELString() }
The magic being done here is "Take value of group slap around it #{ and _value1 } to make it valid NiFi Expression Language statement and then evaluate it." (Notice - the word hash and function replace is there since I didnĀ“t manage to escape the # char right before {.)
If you would like to have your value1 at the beginning of the statement then you can use following code. The result is same, it is easier to use (often-changed value value1 is at the beginning of the statement) and is less readable "what is really going on?"-wise.
value1=${ literal('value1'):prepend('_'):prepend(${ group }):prepend('hash{ '):append(' }'):replace('hash', '#'):evaluateELString() }

Find HTML Tags in Properties

My current issue is to find HTML-Tags inside of property values. I thought it would be easy to search with a query like /jcr:root/content/xgermany//*[jcr:contains(., '<strong>')] order by #jcr:score
It looks like there is a problem with the chars < and > because this query finds everything which has strong in it's property. It finds <strong>Some Text</strong> but also This is a strong man.
Also the Query Builder API didn't helped me.
Is there a possibility to solve it with a XPath or SQL Query or do I have to iterate through the whole content?
I don't fully understand why it finds This is a strong man as a result for '<strong>', but it sounds like the unexpected behavior comes from the "simple search-engine syntax" for the second argument to jcr:contains(). Apparently the < > are just being ignored as "meaningless" punctuation.
You could try quoting the search term:
/jcr:root/content/xgermany//*[jcr:contains(., '"<strong>"')]
though you may have to tweak that if your whole XPath expression is enclosed in double quotes.
Of course this will not be very robust even if it works, since you're trying to find HTML elements by searching for fixed strings, instead of actually parsing the HTML.
If you have an specific jcr:primaryType and the targeted properties you can do something like this
select * from nt:unstructured where text like '%<strong>%'
I tested it , but you need to know the properties you are intererested in.
This is jcr-sql syntax
Start using predicates like a champ this way all of this will make sense to you!
HTML Encode <strong>
HTML Decimal <strong>
Query builder is your friend:
Predicates: (like a CHAMP!)
path=/content/geometrixx
type=nt:unstructured
property=text
property.operation=like
property.value=%<strong>%
Have go here:
http://localhost:4502/libs/cq/search/content/querydebug.html?charset=UTF-8&query=path%3D%2Fcontent%2Fgeometrixx%0D%0Atype%3Dnt%3Aunstructured%0D%0Aproperty%3Dtext%0D%0Aproperty.operation%3Dlike%0D%0Aproperty.value%3D%25%3Cstrong%3E%25
Predicates: (like a CHAMP!)
path=/content/geometrixx
type=nt:unstructured
property=text
property.operation=like
property.value=%<strong>%
Have a go here:
http://localhost:4502/libs/cq/search/content/querydebug.html?charset=UTF-8&query=path%3D%2Fcontent%2Fgeometrixx%0D%0Atype%3Dnt%3Aunstructured%0D%0Aproperty%3Dtext%0D%0Aproperty.operation%3Dlike%0D%0Aproperty.value%3D%25%26lt%3Bstrong%26gt%3B%25
XPath:
/jcr:root/content/geometrixx//element(*, nt:unstructured)
[
jcr:like(#text, '%<strong>%')
]
SQL2 (already covered... NASTY YUK..)
SELECT * FROM [nt:unstructured] AS s WHERE ISDESCENDANTNODE([/content/geometrixx]) and text like '%<strong>%'
Although I'm sure it's entirely possible with a string of predicates, it's possibly heading down the wrong route. Ideally it would be better to parse the HTML when it is stored or published.
The required information would be stored on simple properties on the node in question. The query will then be a lot simpler with just a property = value query, than lots of overly complex query syntax.
It will probably be faster too.
So if you read in your HTML with something like HTMLClient and then parse it with a OSGI service, that can accurately save these properties for you. Every time the HTML is changed the process would update these properties as necessary. Just some thoughts if your SQL is getting too much.

Xpath Expression evaluation on attributes with any namespace prefix

Could you please help me on this xpath expression evaluation
I am working on fetching the proxy references. In the xml file the references will get stored as:
One way of XML file will have the reference as below:
con1:service ref="MyProject/ProxyServices/service1"
xsi:type="con2:PipelineRef" xmlns:ref="http://www.bea.com/wli/sb/reference"/
here in the xml file the name spaces are:
xmlns:con1="http://www.bea.com/wli/sb/stages/config"
xmlns:con2="http://www.bea.com/wli/sb/pipeline/config"
Another way of XML will have the reference as below.
con1:service ref="MyProject/ProxyServices/service2"
xsi:type="ref:ProxyRef" xmlns:ref="http://www.bea.com/wli/sb/reference"/
here in the xml file the name spaces are:
xmlns:con1="http://www.bea.com/wli/sb/stages/config"
xmlns:ref="http://www.bea.com/wli/sb/reference"
I have used this xpath expression, this is not fetching the reference service values, could you please help what is wrong in it.
"//service[#type= #*[local-name() ='ProxyRef' or #type=#*[local-name() ='PipelineRef']]/#ref"
when I used like this it is working but, name space prefix is keep on changes when there are multiple references in the xml file.
"//service[#type='ref:ProxyRef'or #type='con:PipelineRef' or #type='con1:PipelineRef' or #type='con2:PipelineRef' or #type='con3:PipelineRef' ...#type='con20:PipelineRef' ]/#ref";
Now here basically the type attribute PipelineRef is keep on changing the name space prefix from con to con(n). Now I am looking for something which supports some thing like #type='*:PipelineRef' or #type='con*:PipelineRef' or the best way to fetch the service element reference attribute value.
Thanks in advance.
Try using contains() like so :
//service[contains(#type,':ProxyRef') or contains(#type,':PipelineRef')]
Another alternative would be using ends-with() function which is more precise for this purpose compared to contains() function. However, ends-with() isn't available in xpath 1.0, so there is a chance that you need to implement it yourself (feasible, but the xpath result is less intuitive for me).

how to replace a string in a ruby file after a match is found

I have a xml file, which i need to modify from my ruby script and save it. xml file looks something like
`
<mtn:messages>
<mtn:message correlation-key="0x" sequence="4">
<mtn:header>
<mtn:protocol-version>0x4</mtn:protocol-version>
<mtn:message-type>0x0F04</mtn:message-type>
<mtn:ttl>4</mtn:ttl>
<mtn:qos-class-of-service>0</mtn:qos-class-of-service>
<mtn:qos-priority>2</mtn:qos-priority>
</mtn:header>
</mtn:message>
</mtn:messages>
</mtn:test-case>
<mtn:test-case title="Train-Consist-Message">
<mtn:messages>
<mtn:message correlation-key="0x" sequence="4">
<mtn:header>
<mtn:protocol-version>0x4</mtn:protocol-version>
<mtn:message-type>0x0F04</mtn:message-type>
<mtn:ttl>4</mtn:ttl>
<mtn:qos-class-of-service>0</mtn:qos-class-of-service>
<mtn:qos-priority>2</mtn:qos-priority>
</mtn:header>
</mtn:message>
</mtn:messages>
</mtn:test-case>`
I need to replace <mtn:ttl>4</mtn:ttl> with <mtn:ttl>some other value</mtn:ttl> which comes under <mtn:test-case title="Train-Consist-Message"> and save it.
I have written below code, but its replacing all occurances of <mtn:ttl>4</mtn:ttl>.
`doc = IO.read(ENV['CadPath1']+ "conf\\cad-mtn-config.xml")
doc.gsub!(pattern, str)
File.open("File path", "w"){|fh| fh.write(doc)}`
Please help me with this. Waiting for your early reply...
String#gsub! modifies the string in-place, replacing all instances with the replacement specified. If you only want to replace the first instance, use String#sub or String.sub!.
The suggestion from Mike about using sub instead of gsub is good. But parsing XML (and HTML) with regular expression is usually frowned upon.
From your question I assume that you locate the to-be-modified element in terms of parent-child relations, not in terms of the source code order (i.e. you will not be able to say: "modify the second occurrence of this pattern"), so inventing a reliable regular expressions may be very, very hard.
You should use a parser library to find the element you want to change. There is a pretty large collection of those. See some of them at http://ruby-toolbox.com/categories/html_parsing.html and pick one, or use a built-in REXML library.
Alternatively, you could use a very simple 'html-scanner' module, which is included in Rails' ActionController (action_controller/vendor/html-scanner.rb), but if you do not use Rails, I am not sure whether extracting it is worth your time.
The exact code will depend on the parser you choose. Usually they have pretty good documentation/tutorials, so I am sure you will be able to handle it.

Resources