Spring Batch - Non row based data structure file reader - spring

I have a file which is not row based data. It's a text file which contains multiple tables. In order to create one Item I need to take data from several lines. Actually in my case one file is a one record for me, which I have to extract data from several lines to populate item object.
Example:
class DataItem {
private String price;
private String quantity;
//Getters and setters
}
Input File is like:
Price Data
========================
Price : 150$
Quantity: 4000
-------------------------
As given above I need to parse several lines from the file in order to make a one database record (one Item Read).
How can I achieve this using Spring batch?

The FlatFileItemReader has a couple extension points that will be useful for you. The RecordSeparatorPolicy and the LineMapper.
RecordSeparatorPolicy
The RecordSeparatorPolicy indicates to the reader once a full record has been read. It's RecordSeparatorPolicy#isEndOfRecord(String record) takes the current String that has been read and returns true if it represents a full record and false if not. In your case, you'll want to develop one that returns true once one of the tables has been completely read in.
LineMapper
The LineMapper is a strategy interface that allows the String that represents a record to be mapped to an item. Simple cases can be addressed by the DefaultLineMapper which takes a single String, tokenizes it into a set of tokens via the LineTokenizer (represented by a FieldSet...a object similar to a ResultSet only for files), and passes it to a FieldSetMapper that takes the FieldSet and maps the tokens to the item to be returned. You can either implement your own LineMapper or you may be able to just implement a LineTokenizer and use the rest of the out of the box components.
With both of these two extension points, I'd expect you to be able to map that data with Spring Batch in a pretty straight forward manor.

Related

How to handle the string separated by a comma in csvwriter processinggroup nifi

I'm having a csv file with two columns for example column A and Columb B. Column B consists of string value like this : I am, doing good. so when I try to insert this data into a database only the string I am is getting inserted. I just want to know what attribute I need to add to the process group so that I am, doing good will get inserted to the database
The attached image consists of the attributes in the current process group

How to read an excel sheet and put the cell value within different text fields through UiPath?

How to read an excel sheet and put the cell value within different text fields through UiPath?
I have a excel sheet as follows:
I have read the excel contents and to iterate over the contents later I have stored the contents in a Output Data Table as follows:
Read Range - Output:
DataTable: CVdatatable
Output Data Table
DataTable: CVdatatable
Text: opCVdatatable
Screenshot:
Finally, I want to read the text opCVdatatable in a iteration and write them into text fields. So in the desired Input fileds I mentioned opCVdatatable or opCVdatatable+ "[k(enter)]" as required.
Screenshot:
But UiPath seems to start from the begining of the Output Data Table whenever I called for opCVdatatable.
Inshort, each desired Input fileds are iteratively getting filled up by all the data with the data stored in the Output Data Table.
Can someone help me out please?
My first recommendation is to use Workbook: Read range activity to read data from Excel because it is quicker, works in the background, and does not require excel to be installed on the system.
Start your sequence like this (note the add headers property is not checked):
You do not need to use Output Data Table because this activity outputs a string containing all row items. What you want to do instead is to access the items in the data table and output each one as a string in your type into, e.g., CVDatatable.Rows(0).Item(0).ToString, like so:
You mention you want to read the text opCVdatatable in an iteration and write them into text fields. This is a little bit more complex, but i'll give you an example. You can use a For Each Row activity and loop through each row in CVDatatable, setting the index property if required. See below:
The challenge is to get the selector correct here and make it dynamic, so that it targets a different text field per iteration. The selector for the type into activity will depend on the system you are targeting, but here is an example:
And the selector for this:
Also, here is a working XAML file for you to test.
Hope this helps.
Chris
Here's a different, more general approach. Instead of including the target in the process itself, the Excel would be modified to include parts of a selector:
Note that column B now contains an identifier, and this ID depends on the application you will be working with. For example, here's my sample app looks like. As you can see, the first text box has an id of 585, the second one is 586, and so on (note that you can work with any kind of identifier including the control's name if exposed to UiPath):
Now, instead of adding multiple Type Into elements to your workflow, you would add just a single one, loop over each of the datatable's row, and then create a dynamic selector:
In my case the selector for the Type Into activity looks as follows:
"<wnd cls='#32770' title='General' /><wnd ctrlid='" + row(1).ToString() + "' />"
This will allow you to maintain the process from the Excel sheet alone - if there's a new field that needs to be mapped, just add it to your sheet. No changes to the Workflow are required.

Spring Batch, read whole csv file before reading line by line

I want to read a csv file, enrich each row with some data from some other external system and then write the new enriched csv to some directory
Now to get the data from external system i need to pass each row one by one and get the new columns from external system.
But to query the external system with each row i need to pass a value which i have got from external system by sending all the values of a perticular column.
e.g - my csv file is -
name, value, age
10,v1,12
11,v2,13
so to enrich that i first need to fetch a value as per total age - i.e 12 + 13 and get the value total from external system and then i need to send that total with each row to external system to get the enriched value.
I am doing it using spring batch but using fLatFileReader i can read only one line at a time. How would i refer to whole column before that.
Please help.
Thanks
There are two ways to do this.
OPTION 1
Go for this option if you are okey to store all the records in memory. Totally depends how many record you need to calculate the total age.
Reader(Custom Reader) :
Write the logic to read one line at a time.
You need to return null from read() only when you feel all the lines are read for calculating the total age.
NOTE:- A reader will loop the read() method until it returns null.
Processor : You will get the full list of records. calculate the total age.
Connect the external system and get the value. Form the records which need to be written and return from the process method.
NOTE:- You can return all the records modified by a particular field or merge a single record. This is totally your choice what you would like to do.
Writer : Write the records.
OPTION 2
Go for this if option1 is not feasible.
Step1: read all the lines and calculate the total age and pass the value to the next step.
Step2: read all the lines again and update the records with required update and write the same.

Data Transformation for Large data in a file

I am new to ensemble and have a clarification regarding the Data Transformations.
I have 2 schemas as follows,
PatientID,
Patient Name,
Patient Address (combination of door number, Street, District, State)
and another schema as,
PatientID,
Patient Name,
Door Number
Street
District
State
Now there is an incoming text file with 1000's of records as per the first schema ('|' separated) as below,
1001|John|220,W Maude Ave,Suisun City, CA
like this there a 1000's of recrods in the input file
My requirement is to convert this as per the second schema (i.e to separate the Address) and store in the file like,
1001|John|220|W Maude Ave|Suisun City|CA
One solution I implemented was to loop through each line in the file and replace the , in the address with '|'.
My question is, whether we can do it through DTL. If the answer is yes how do we loop through 1000s of records using DTL.
Whether DTL will be time consuming? because we need to load the schema and then do the transformations.
Please help.
You can use DTL with any class that inherit from Ens.VirtualDocument or %XML.Adaptor, virtually Ensemble use class dictionary to represent the schema so for basic classes there is not problem is you extends %XML.Adaptor Ensemble can represent it. In case of virtual documents the object has to be set the DocType.
In order to do the loop there is a in DTL
Yes, DTLs can parse 1000's of records. You can do the following:
1) Create a record map to parse the incoming file that has schema 1
2) Define an intermediate object that maps schema 2 fields to object properties
3) Create a DTL whose source object is the record map object from 1 above and target is object from 2 above.

How to build a custom key for matching two queries, using Linq-To-Entities

I want to match in-memory entities to data from DB-tables and return a new in-memory DTO with a subset of that matched information. Now, matching involves two columns, thus I am building a new key on the fly. This works, as long as I execute the queries before building the keys, effectively using Linq-To-Objects for the matching.
When not executing the query right away, I receive a runtime exception as described by this MSDN article.
Here is my code and data model, simplified. I have
Rooms (as IEnumerable<Room>, already in memory)
Areas (as IEnumerable<Room>, already in memory)
Alarms (from the DB, as IQueryable from the context)
Alarms are tied to Areas and LocationIds. Rooms can have multiple Areas, and have one LocationId.
I want to build a set of Alarms occurred in a set of Rooms. This involves matching the Alarm's Area and LocationsId to each Room's LocationId and the Areas.
from area in allAreas
let alarmKey = area.AreaName + area.Room.LocationId //AreaName is String, LocationId is integer
//....
However, this line involves a not supported cast form int to String. How to create the key?
If you don't mind a number of leading spaces in LocationId you can do
let alarmKey = area.AreaName +
SqlFunctions.StringConvert((double)area.Room.LocationId)
SqlFunctions is in System.Data.Objects.SqlClient.

Resources