Is there a simple way of taking the value of a property and then copy it to another property with certain characters replaced?
Say propA=This is a value. I want to replace all the spaces in it into underscores, resulting in propB=This_is_a_value.
Here is the solution without scripting and no external jars like ant-conrib:
The trick is to use ANT's resources:
There is one resource type called "propertyresource" which is like a source file, but provides an stream from the string value of this resource. So you can load it and use it in any task like "copy" that accepts files
There is also the task "loadresource" that can load any resource to a property (e.g., a file), but this one could also load our propertyresource. This task allows for filtering the input by applying some token transformations. Finally the following will do what you want:
<loadresource property="propB">
<propertyresource name="propA"/>
<filterchain>
<tokenfilter>
<filetokenizer/>
<replacestring from=" " to="_"/>
</tokenfilter>
</filterchain>
</loadresource>
This one will replace all " " in propA by "_" and place the result in propB. "filetokenizer" treats the whole input stream (our property) as one token and appies the string replacement on it.
You can do other fancy transformations using other tokenfilters: http://ant.apache.org/manual/Types/filterchain.html
Use the propertyregex task from Ant Contrib.
I think you want:
<propertyregex property="propB"
input="${propA}"
regexp=" "
replace="_"
global="true" />
Unfortunately the examples given aren't terribly clear, but it's worth trying that. You should also check what happens if there aren't any underscores - you may need to use the defaultValue option as well.
If ant-contrib isn't an option, here's a portable solution for Java 1.6 and later:
<property name="before" value="This is a value"/>
<script language="javascript">
var before = project.getProperty("before");
project.setProperty("after", before.replaceAll(" ", "_"));
</script>
<echo>after=${after}</echo>
In case you want a solution that does use Ant built-ins only, consider this:
<target name="replace-spaces">
<property name="propA" value="This is a value" />
<echo message="${propA}" file="some.tmp.file" />
<loadfile property="propB" srcFile="some.tmp.file">
<filterchain>
<tokenfilter>
<replaceregex pattern=" " replace="_" flags="g"/>
</tokenfilter>
</filterchain>
</loadfile>
<echo message="$${propB} = "${propB}"" />
</target>
Output is ${propB} = "This_is_a_value"
Use some external app like sed:
<exec executable="sed" inputstring="${wersja}" outputproperty="wersjaDot">
<arg value="s/_/./g"/>
</exec>
<echo>${wersjaDot}</echo>
If you run Windows get it googling for "gnuwin32 sed".
The command s/_/./g replaces every _ with .
This script goes well under windows. Under linux arg may need quoting.
Two possibilities :
via script task and builtin javascript engine (if using jdk >= 1.6)
<project>
<property name="propA" value="This is a value"/>
<script language="javascript">
project.setProperty('propB', project.getProperty('propA').
replace(" ", "_"));
</script>
<echo>$${propB} => ${propB}</echo>
</project>
or using Ant addon Flaka
<project xmlns:fl="antlib:it.haefelinger.flaka">
<property name="propA" value="This is a value"/>
<fl:let> propB := replace('${propA}', '_', ' ')</fl:let>
<echo>$${propB} => ${propB}</echo>
</project>
to overwrite exisiting property propA simply replace propB with propA
Here's a more generalized version of Uwe Schindler's answer:
You can use a macrodef to create a custom task.
<macrodef name="replaceproperty" taskname="#{taskname}">
<attribute name="src" />
<attribute name="dest" default="" />
<attribute name="replace" default="" />
<attribute name="with" default="" />
<sequential>
<loadresource property="#{dest}">
<propertyresource name="#{src}" />
<filterchain>
<tokenfilter>
<filetokenizer/>
<replacestring from="#{replace}" to="#{with}"/>
</tokenfilter>
</filterchain>
</loadresource>
</sequential>
</macrodef>
you can use this as follows:
<replaceproperty src="property1" dest="property2" replace=" " with="_"/>
this will be pretty useful if you are doing this multiple times
Adding an answer more complete example over a previous answer
<property name="propB_" value="${propA}"/>
<loadresource property="propB">
<propertyresource name="propB_" />
<filterchain>
<tokenfilter>
<replaceregex pattern="\." replace="/" flags="g"/>
</tokenfilter>
</filterchain>
</loadresource>
Just an FYI for answer Replacing characters in Ant property - if you are trying to use this inside of a maven execution, you can't reference maven variables directly. You will need something like this:
...
<target>
<property name="propATemp" value="${propA}"/>
<loadresource property="propB">
<propertyresource name="propATemp" />
...
Properties can't be changed but antContrib vars (http://ant-contrib.sourceforge.net/tasks/tasks/variable_task.html ) can.
Here is a macro to do a find/replace on a var:
<macrodef name="replaceVarText">
<attribute name="varName" />
<attribute name="from" />
<attribute name="to" />
<sequential>
<local name="replacedText"/>
<local name="textToReplace"/>
<local name="fromProp"/>
<local name="toProp"/>
<property name="textToReplace" value = "${#{varName}}"/>
<property name="fromProp" value = "#{from}"/>
<property name="toProp" value = "#{to}"/>
<script language="javascript">
project.setProperty("replacedText",project.getProperty("textToReplace").split(project.getProperty("fromProp")).join(project.getProperty("toProp")));
</script>
<ac:var name="#{varName}" value = "${replacedText}"/>
</sequential>
</macrodef>
Then call the macro like:
<ac:var name="updatedText" value="${oldText}"/>
<current:replaceVarText varName="updatedText" from="." to="_" />
<echo message="Updated Text will be ${updatedText}"/>
Code above uses javascript split then join, which is faster than regex. "local" properties are passed to JavaScript so no property leakage.
Or... You can also to try Your Own Task
JAVA CODE:
class CustomString extends Task{
private String type, string, before, after, returnValue;
public void execute() {
if (getType().equals("replace")) {
replace(getString(), getBefore(), getAfter());
}
}
private void replace(String str, String a, String b){
String results = str.replace(a, b);
Project project = getProject();
project.setProperty(getReturnValue(), results);
}
..all getter and setter..
ANT SCRIPT
...
<project name="ant-test" default="build">
<target name="build" depends="compile, run"/>
<target name="clean">
<delete dir="build" />
</target>
<target name="compile" depends="clean">
<mkdir dir="build/classes"/>
<javac srcdir="src" destdir="build/classes" includeantruntime="true"/>
</target>
<target name="declare" depends="compile">
<taskdef name="string" classname="CustomString" classpath="build/classes" />
</target>
<!-- Replacing characters in Ant property -->
<target name="run" depends="declare">
<property name="propA" value="This is a value"/>
<echo message="propA=${propA}" />
<string type="replace" string="${propA}" before=" " after="_" returnvalue="propB"/>
<echo message="propB=${propB}" />
</target>
CONSOLE:
run:
[echo] propA=This is a value
[echo] propB=This_is_a_value
Related
I have a service in wso2 ei, which takes an expiration date which must be compared with the current date, if it passes the expiration date the service must respond expired.
My idea is to transform it into time in unix or timestamp to be able to make the comparison, does anyone know how to do it in xpath?
this is my code.
<property name="bodyExpirDate" expression="$body//values/expir_date" scope="default" type="STRING"/>
<property name="DateTimeNoww" expression="get-property("SYSTEM_DATE","yyyy-MM-dd'T'HH:mm:ss")" type="STRING"/>
<property name="todayFormatted" expression="get-property("SYSTEM_DATE", "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")" scope="default"/>
<filter xpath="get-property('DateTimeNoww') > get-property('bodyExpirDate')">
<then>
<payloadFactory media-type="json">
<format>{"Status":"Expirado","dateTimeNow":$1, "dateTimePrj":$2, "currentDateXpath":$3}</format>
<args>
<arg evaluator="xml" expression="get-property('DateTimeNoww')"/>
<arg evaluator="xml" expression="get-property('bodyExpirDate')"/>
<arg value="a"/>
</args>
</payloadFactory>
</then>
Edit:
I cant do that, but i use this javascript code, but i cant call bodyExpirDate2 in my script
<property name="bodyExpirDate2" expression="string-length(concat(get-property('apos'),get-property('bodyExpirDate'),get-property('apos')))" scope="default"/>
<property name="DateTimeNoww" expression=" get-property("SYSTEM_DATE","yyyy-MM-dd'T'HH:mm:ss")" type="STRING"/>
<script language="js">
var mystringDate = mc.getProperty('bodyExpirDate2');
mystringDate = mystringDate.replace('T',' ');
mystringDate = mystringDate.replace(/\s/g, '');
var b = " ";
var position = 10;
var output = [mystringDate.slice(0, position), b, mystringDate.slice(position)].join('');
var match = output.match(/^(\d+)-(\d+)-(\d+) (\d+)\:(\d+)\:(\d+)$/);
var date = new Date(match[1], match[2] - 1, match[3], match[4], match[5], match[6]);
var result = (date.getTime() / 1000);
mc.setProperty('result', result.toString());
</script>
<filter xpath="get-property('result') > 1">
Guess you need to enable xpath 2 first. Go to /conf/synapse.properties file uncomment the following.
synapse.xpath.dom.failover.enabled=true
I'm interested in the recordTerminator parser property of BeanIO. Does it apply to segments too, like "segmentTerminator"? Namely, I have a stream of fixedlength format, containing of a single record with repeatable segments, and all stream is a single line. Hence, I have set recordTerminator="", but it still gives me
==> Invalid 'state': Expected minimum 1 occurrences
==> Invalid 'city': Expected minimum 1 occurrences
==> Invalid 'street': Invalid field length, expected 35 characters
==> Invalid 'zip': Expected minimum 1 occurrences
It doesn't complain about fields that precede to repeatable segment, and complaints about the fields in a repeatable segment are out of order defined in mapping.xml, that looks like this:
<beanio xmlns="http://www.beanio.org/2012/03" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.beanio.org/2012/03 http://www.beanio.org/2012/03/mapping.xsd">
<stream name="employeeFile" format="fixedlength">
<parser>
<property name="recordTerminator" value="" />
</parser>
<record name="employee" class="example.Employee">
<field name="firstName" length="35" />
<field name="lastName" length="35" />
<field name="title" length="35" />
<field name="salary" length="35" />
<segment name="addressList" collection="list" minOccurs="1" maxOccurs="unbounded" class="example.Address">
<field name="street" length="35" />
<field name="city" length="35" />
<field name="state" length="35" />
<field name="zip" length="10" />
</segment>
</record>
</stream>
</beanio>
Class implementations is like this:
package example;
public class Employee {
String firstName;
String lastName;
String title;
String salary;
List<Address> addressList;
// getters and setters not shown...
}
package example;
public class Address {
private String street;
private String city;
private String state;
private String zip;
// getters and setters not shown...
}
If I remove all preceding fields to repetitive segment both from mapping.xml and the input string, remaining string is properly unmarshalled, and marshalled to json afterwards, I even didn't change implementation of java classes, so the preceding fields stay uninitialized, as expected, but properly printed out after marshalling. Where did I go wrong?
OK, my camel code is in spring xml, looks like this:
<route id="simple-route">
<!-- from id="request-file" uri="file://C:/mqdocuments/?fileName=response464.txt"/-->
<from id="request-file" uri="file://C:/mqdocuments/?fileName=request464.txt"/>
<log id="route-log-request" message="request: ${body}"/>
<setHeader headerName="CamelJmsDestinationName" id="_setHeader1">
<constant>queue://QM_TEST/INPUTQ?targetClient=1</constant>
</setHeader>
<to id="_to1" pattern="InOut" uri="websphere:queue:SYSTEM.DEFAULT.LOCAL.QUEUE?useMessageIDAsCorrelationID=true&replyTo=REPLYQ"/>
<log id="route-log-response" message="response: ${body}"/>
<transform>
<simple>${body}\0</simple>
</transform>
<unmarshal ref="parseTransactions464"/>
<marshal ref="jack"/>
<log id="route-log-json" message="jackson: ${body}"/>
</route>
So basically, when I uncomment input from file, in which the reponse is saved, and place in comment mq to endpoint, unmarshalling is OK, but if I put a request to a queue, and get response, then I hope to rectify the problem by a transform that simply adds EOF character, because without it, it gives me error that I reported in the first place.
And transform doesn't help, because I don't know how to write EOF (ascii 26), but even if I figure that out, I'm not sure it will help.
I'm going to attempt this as an answer, unfortunately I can't test this, I have nothing setup for use with Camel. First I would not change the default recordTerminator value for BeanIO and leave it to use the default which is any of CR, LF or CRLF.
Then in the transformation of the message, I'll append a newline (\n) instead of the \0. I don't quite understand why you would want to use the EOF character if you have control over it. Instead of:
<transform>
<simple>${body}\0</simple>
</transform>
I would go for:
<transform>
<simple>${body}\n</simple>
</transform>
See the section on "Using New Lines or Tabs in XML DSLs" close to the bottom of the page:
Using New Lines or Tabs in XML DSLs
Available from Camel 2.9.3
From Camel 2.9.3: it is easier to specify new lines or tabs in XML
DSLs as you can escape the value now xml
<transform> <simple>The following text\nis on a new line</simple></transform>
I was floating around trying to identify the problem, but in the end, I realized I should have set the charset with the encoding attribute of beanio dataFormat, which I couldn't do because of this defect:
http://camel.465427.n5.nabble.com/Re-Exhausted-after-delivery-attempt-1-caught-java-lang-NullPointerException-charset-tc5817807.html
http://camel.465427.n5.nabble.com/Exhausted-after-delivery-attempt-1-caught-java-lang-NullPointerException-charset-tc5817815.html
https://issues.apache.org/jira/browse/CAMEL-12284
Finally, I was instructed by Claus Ibsen to use such workaround:
<bean class="org.apache.camel.dataformat.beanio.BeanIODataFormat"
id="some_bean_id">
<property name="encoding" value="UTF-8"/>
<property name="mapping" value="mapping.xml"/>
<property name="streamName" value="some_stream_name"/>
</bean>
I am using MSBuild.
I am getting the value of the Person_1 through the $(Person_1). How can I get the value of the Name subelement of Person_2? I need the syntax.
<PropertyGroup>
<Person_1>Bob</Person_1>
<Person_2>
<Name>Bob</Name>
</Person_2>
</PropertyGroup>
RE: https://msdn.microsoft.com/en-us/library/ms171458.aspx
A property that contains XML is simply that. You cannot access parts of the content just because it is XML. To understand this do the following;
<PropertyGroup>
<MyProperty>
<PropertyContentXML>
<InnerXML1>Blablabla</InnerXML1>
<InnerXML2>More blablabla</InnerXML2>
</PropertyContentXML>
</MyProperty>
</PropertyGroup>
<Target Name="Build">
<Message Text="$(MyProperty)" />
</Target>
The output of this will be:
<PropertyContentXML xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<InnerXML1>Blablabla</InnerXML1>
<InnerXML2>More blablabla</InnerXML2>
</PropertyContentXML>
You are mixing Properties and ItemGroups.
Properties are simple named values, ItemGroups are items with an identity and with properties. You can not use both in the same way.
Properties are defined as :
<PropertyGroup>
<name>value</name>
</Propertygroup>
and are accessed by using the $(name) syntax.
Item groups are defined as:
<ItemGroup>
<Item Include="item1">
<ItemPropery>value</ItemProperty>
</Item>
</ItemGroup>
and are accessed by using this syntax: %(Item.ItemProperty).
See also this reference for the 'intuitive' syntax
You'll need something advanced, like an inline task:
<UsingTask TaskName="TransformXmlToItem"
TaskFactory="CodeTaskFactory"
AssemblyName="Microsoft.Build.Tasks.Core">
<ParameterGroup>
<Xml Required="true"/>
<Elements ParameterType="Microsoft.Build.Framework.ITaskItem[]" Output="true"/>
</ParameterGroup>
<Task>
<Reference Include="System.Xml" />
<Using Namespace="System.Collections.Generic" />
<Using Namespace="System.Xml" />
<Code Type="Fragment" Language="cs">
<![CDATA[
using (var xr = new XmlTextReader(Xml, XmlNodeType.Element,
new XmlParserContext(null, null, null, XmlSpace.Default))) {
xr.Namespaces = false;
xr.MoveToContent();
var items = new List<ITaskItem>();
while (!xr.EOF) {
if (xr.NodeType == XmlNodeType.Element) {
var item = new TaskItem(xr.Name);
var text = xr.ReadElementContentAsString();
if (!string.IsNullOrWhiteSpace(text)) {
item.SetMetadata("text", text);
}
}
xr.Read();
}
Elements = items.ToArray();
}
]]>
</Code>
</Task>
The task reads the XML elements and creates items from it. The text is transformed into metadata.
You can then write a task like this:
<Target Name="DeconstructPropertyXml">
<TransformXmlToItem Xml="$(Person_2)">
<Output TaskParameter="Elements" ItemName="Person_2I"/>
</TransformXmlToItem>
<Message Text="%(Person_2I.Identity) = %(Person_2I.text)" Importance="high"/>
</Target>
Which should just output Name = Bob.
The same way you could add additional metadata from attributes, etc.
When I make the following AppleScript call to my app, I get a list of text objects:
tell "MyApp"
name of every myobject
end tell
But the following call returns an error:
tell "MyApp"
name of selected myobjects
end tell
Script Error
MyApp got an error: Can't make name of selected MyObjects into type specifier.
I turned on verbose logging with the -NSScriptingDebugLogLevel 1 argument to my app, which gave me this:
2015-01-27 14:33:53.650 MyApp[4848:2572448] Error converting apple event to script command: -1700
2015-01-27 14:33:53.650 MyApp[4848:2572448] Original event: <NSAppleEventDescriptor: 'core'\'getd'{ '----':'obj '{ 'form':'prop', 'want':'prop', 'seld':'pnam', 'from':'obj '{ 'form':'prop', 'want':'prop', 'seld':'MASM', 'from':null() } }, &'csig':65536 }>
2015-01-27 14:33:53.650 MyApp[4848:2572448] Offending object descriptor: <NSAppleEventDescriptor: 'obj '{ 'form':'prop', 'want':'prop', 'seld':'pnam', 'from':'obj '{ 'form':'prop', 'want':'prop', 'seld':'MASM', 'from':null() } }>
2015-01-27 14:33:53.651 MyApp[4848:2572448] Expected type descriptor: <NSAppleEventDescriptor: 'obj '>
This is the "application" section of my sdef file:
<class name="application" code="capp" plural="applications" inherits="application">
<cocoa class="MyApp.MAApplication" />
<element type="myobject" access="r">
<cocoa key="myobjects" />
</element>
<property name="selected myobjects" code="MASM">
<cocoa key="selectedMyObjects" />
<type type="myobject" list="yes" />
</property>
</class>
And the MyObject class:
<class name="myobject" code="MAMO" inherits="item" plural="myobjects">
<cocoa class="MyObject" />
<property name="id" code="ID " type="text" access="r">
<cocoa key="permanentID" />
</property>
<property name="name" code="pnam" type="text" access="r">
<cocoa key="displayName" />
</property>
</class>
When I just call selected myobjects, I get back a list of identifiers, so that part is working correctly. When can't I get the name or other properties back from that list, when I can with another list specified the exact same way (except as an element instead of property)?
Update
Still not having any luck so far. I noticed, with verbose logging, that when I call name of every MyObject, the command "Intrinsics.get" triggers with an NSPropertySpecifier "displayName of myobjects". Apparently that link doesn't get made when using a property rather than an element to return a list of items. I found a workaround, though, since I specify an is selected property on MyObject. You can call:
name of every myobject whose is selected = true
That works the way I expected my selected myobjects property to work, returning a list of text objects.
Update 2
I added a sample project to GitHub:
https://github.com/abbeycode/AppleScriptObjectList
That contains a sample script with the first two methods that behave as expected, followed by the one that triggers the error. Feel free to mess around if you'd like. I submitted a radar with this sample project.
I am using spring web-flow 2.0 and I need to return a variable from sub-flow to parent flow like:
<end-state id="end" >
<output name="mvViewBean" value="viewBean" />
</end-state>
and use it inside my parent flow like :
<subflow-state id="updateSubflowState" subflow="mv-update" >
<on-exit>
<evaluate expression="mvService.onblabla(mvViewBean)" />
</on-exit>
</subflow-state>
Do i need to define variable definitions or something else?
Just came across this issue...The currentEvent does work, but if you indicate that you accept the variable in your updateSubflowState through a
<output name="mvViewBean" value="flowScope.mvViewBean"/>
then you will be able to access it as mvViewBean.
Yo can get the output values getting attribute in currentEvent.
<subflow-state id="updateSubflowState" subflow="mv-update" >
<on-exit>
<evaluate expression="mvService.onblabla(currentEvent.attributes.mvViewBean)" />
</on-exit>
</subflow-state>