I have the following grammar:
Department:
'Department:' name = ID
'Company:' companyName = STRING
'Persons:' persons += Person+
;
Person:
firstName = STRING
':'
surname = STRING
':'
address = STRING
;
And I would like to have formatting like this:
Department: Department1
Company: "Company1"
Persons:
"Person1FirstName" : "Person1LastName" : "Person1Address"
"Person2FirstName" : "Person2LastName" : "Person2Address"
But when I implement the formatter code I cannot seem to be able to use indent twice since the white space formatting gets merged instead of getting concatinated.
class TestsFormatter extends AbstractFormatter2
{
def dispatch void format(Department department, extension IFormattableDocument document)
{
department.interior[indent]
department.regionFor.keyword("Department:").prepend[setNewLines(2)]
department.regionFor.keyword("Department:").append[oneSpace]
department.regionFor.keyword("Company:").prepend[newLine]
department.regionFor.keyword("Company:").append[oneSpace]
department.regionFor.keyword("Persons:").prepend[newLine]
for (Person person : department.persons)
{
person.format
}
}
def dispatch void format(Person person, extension IFormattableDocument document)
{
person.prepend[indent]
person.prepend[indent]
}
}
I found out that there is an example with "increaseIndentation/decreaseIndentation" in the documentation of AbstractFormatter2. But when I try to use them, it cannot resolve them.
you can achive this by using a custom replacer similar as described in How to define different indentation levels in the same document with Xtext formatter
Related
I have a string which consist of data along with spaces i want to sort this string into particular variables
eg.
" Company Name : ABC Department : TESTING";
i want to split this string and get the company name and department name to add to their particular variable
You will have a pain in the neck for achieving that taks because the data is ill formatted,
your goal is to obtain from the string something like:
Company Name = ABC
Department = TESTING
even using the method split, you need a token that you dont have...
the suggestion i can provide is to redefine those strings in something well formatted and parsable... json is a good candidate for this task
imagine this example using json objects:
QString str3 = "{\"Company Name\" : \"ABC\", \"Department\" : \"TESTING\", \"Number\" : 123, \"Updated\" : false}";
then you need to "parse" the string into a json object, then get those "values" for the "keys"
like:
QJsonDocument doc1 = QJsonDocument::fromJson(str3.toUtf8());
QJsonValue company = doc1["Company Name"];
QJsonValue dept = doc1["Department"];
QJsonValue number = doc1["Number"];
QJsonValue updated = doc1["Updated"];
qDebug()<< "Company: " << company.toString();
qDebug()<< "Department: " << dept.toString();
qDebug()<< "Number: " << number.toInt();
qDebug()<< "Updated: " << updated.toBool();
your output will look like:
Company: "ABC"
Department: "TESTING"
Number: 123
Updated: false
I am currently having a list of obeject defined as:
fun updateList(tools: List<Tool>, updateTools: List<Updated>){
... code below
}
the Tool data class is defined as:
data class Tool(
var id: String = ""
var description: String = ""
var assignedTo: String = ""
)
the Updated data class is defined as:
data class Updated(
var id: String = ""
var assignedTo: String = ""
)
Basically, I parse the list updateTools and if I found a id match in tools, I update the assignedTo field from the Tool type object from tools by the one from updateTools
fun updateList(tools: List<Tool>, updateTools: List<Updated>){
updateTools.forEach{
val idToSearch = it.id
val nameToReplace = it.name
tools.find(){
if(it.id == idToSearch){it.name=nameToReplace}
}
}
return tools
}
it's not working but I do not see how to make it easier to work. I just started kotlin and I feel that it's not the good way to do it
any idea ?
Thanks
First of all:
you're not assigning assignedTo, you're assigning name...
in the predicate passed to find, which
should only return a Boolean value to filter elements, and
should probably not have any side effects,
those should be done later with a call to i.e. forEach.
Additionally, your constructor parameters to the data class are normal parameters, and as such, need commas between them!
Your last code block, corrected, would be:
updateTools.forEach {
val idToSearch = it.id
val nameToReplace = it.name
tools.find { it.id == idToSearch }.forEach { it.assignedTo = nameToReplace }
}
return tools
I'd do it like this (shorter):
updateTools.forEach { u -> tools.filter { it.id == u.id }.forEach { it.assignedTo = u.name } }
This loops through each update, filters tools for tools with the right ID, and sets the name of each of these tools.
I use forEach as filter returns a List<Tool>.
If you can guarantee that id is unique, you can do it like this instead:
updateTools.forEach { u -> tools.find { it.id == u.id }?.assignedTo = u.name }
firstOrNull returns the first element matching the condition, or null if there is none. Edit: it seems find is firstOrNull - its implementation just calls firstOrNull.
The ?. safe call operator returns null if the left operand is null, otherwise, it calls the method.
For = and other operators which return Unit (i.e. void, nothing), using the safe call operator simply does nothing if the left operand is null.
If we combine these, it effectively sets the name of the first element which matches this condition.
First, you're missing comma after properties in your data classes, so it should be:
data class Tool(
var id: String = "",
var description: String = "",
var assignedTo: String = ""
)
data class Updated(
var id: String = "",
var assignedTo: String = ""
)
As for second problem, there're probably number of ways to do that, but I've only corrected your idea:
fun updateList(tools: List<Tool>, updateTools: List<Updated>): List<Tool> {
updateTools.forEach{ ut ->
tools.find { it.id == ut.id }?.assignedTo = ut.assignedTo
}
return tools
}
Instead of assigning values to variables, you can name parameter for forEach and use it in rest of the loop.
I'm parsing a json file like this :
JSONObject stationJson = array.optJSONObject(i);
Station s = new Station();
s.setName(stationJson.optString("name"));
s.setTimestamp(stationJson.optString("last_update"));
s.setNumber(stationJson.optInt("number"));
This is the json file :
{
"number": 123,
"contract_name" : "7500 - London",
"name": "nom station",
"address": "adresse indicative",
}
I would like to display just the "London" in the name section not the Number.
I found this Code Snippet but I don't know how to use it :
private String buildDisplayName(String name) {
String regexp = "[\\d\\s]*([a-zA-Z](.*)$)";
Pattern p = Pattern.compile(regexp);
Matcher m = p.matcher(name);
if (m.find()) {
return m.group();
}
return name;
}
Any help would be great!
If it's always the exact same format why not use substring so you still understand your own code. For example, use:
String test = stationJson.optString("name");
s.setName(test.substring(test.indexOf("-")+2));
This gets the string value from your name, 2 positions from the position of the hyphen ( the "-").
If you want to work with regex, that's great, but if you don't really know how it works, I wouldn't recommend it. This might give you an idea of what the code snippet you pasted is actually doing. And here is a tutorial about it.
I am trying to use a kind of builder pattern to build an OR query using multiple criteria depending upon the scenario. An example is
public class Stylist extends Model {
public String firstName;
public String lastName;
public String status;
...
}
I would like to search Stylist collection if the first name or last name matches a given string and also status matches another string. I am writing the query as follows:
MorphiaQuery query = Stylist.q();
if (some condition) {
query.or(query.criteria("status").equal("PendingApproval"), query.criteria("status").equal(EntityStatus.ACTIVE));
}
if (some other condition as well) {
query.or(query.criteria("firstName").containsIgnoreCase(name), query.criteria("lastName").containsIgnoreCase(name));
}
When both the conditions are met, I see that query contains only the criteria related to firstName and lastName i.e. different OR criteria are not added/appended but overwritten. It's quite different from filter criteria where all the different filter conditions are appended and you can easily build queries containing multiple AND conditions.
I can solve the problem by putting my conditions differently and building my queries differently but doesn't seem to be an elegant way. Am I doing something wrong ?
I am using Play! Framework 1.2.4 and Play Morphia module version 1.2.5a
Update
To put it more clearly, I would like to AND multiple OR queries. Concretely, in the above mentioned scenario, I would like to
I would like to search for Stylists where :
firstName or lastName contains supplied name AND
status equals ACTIVE or PENDING_APPROVAL.
I have been able to construct the query directly on Mongo shell through :
db.stylists.find({$and: [{$or : [{status: "PENDING_APPROVAL"}, {status : "ACTIVE"}]},{$or : [{firstName : { "$regex" : "test" , "$options" : "i"}}, {lastName : { "$regex" : "test" , "$options" : "i"}}]}] }).pretty();
But have not able to achieve the same through Query API methods. Here is my attempt :
Query<Stylist> query = MorphiaPlugin.ds().find(Stylist.class);
CriteriaContainer or3 = query.or(query.criteria("firstName").containsIgnoreCase(name), query.criteria("lastName").containsIgnoreCase(name));
CriteriaContainer or4 = query.or(query.criteria("status").equal("PENDING_APPROVAL"), query.criteria("status").equal("ACTIVE"));
query.and(or3, or4);
query.toString() results in following output : { "$or" : [ { "status" : "PENDING_APPROVAL"} , { "status" : "ACTIVE"}]}
Not sure, where am I missing ?
I guess there could be 2 ways to handle your case:
first, use List<Criteria>
MorphiaQuery query = Stylist.q();
List<Criteria> l = new ArrayList<Criteria>()
if (some condition) {
l.add(query.criteria("status").equals("PendingApproval");
l.add(query.criteria("status").equal(EntityStatus.ACTIVE));
}
if (some other conditional as well) {
l.add(query.criteria("firstName").containsIgnoreCase(name));
l.add(query.criteria("lastName").containsIgnoreCase(name));
}
query.or(l.toArray());
Second, use CritieriaContainer
MorphiaQuery query = Stylist.q();
CriteriaContainer cc = null;
if (some condition) {
cc = query.or(query.criteria("status").equal("PendingApproval"), query.criteria("status").equal(EntityStatus.ACTIVE));
}
if (some other condition) {
if (null != cc) query.or(cc, query.criteria("firstName").containsIgnoreCase(name), query.criteria("lastName").containsIgnoreCase(name));
else query.or(query.criteria("firstName").containsIgnoreCase(name), query.criteria("lastName").containsIgnoreCase(name));
}
Currently, I'm using Conversion Studio to bring in a CSV file and store the contents in an AX table. This part is working. I have a block defined and the fields are correctly mapped.
The CSV file contains several comments columns, such as Comments-1, Comments-2, etc. There are a fixed number of these. The public comments are labeled as Comments-1...5, and the private comments are labeled as Private-Comment-1...5.
The desired result would be to bring the data into the AX table (as is currently working) and either concatenate the comment fields or store them as separate comments into the DocuRef table as internal or external notes.
Would it not require just setting up a new block in the Conversion Studio project that I already have setup? Can you point me to a resource that maybe shows a similar procedure or how to do this?
Thanks in advance!
After chasing the rabbit down the deepest of rabbit holes, I discovered that the easiest way to do this is like so:
Override the onEntityCommit method of your Document Handler (that extends AppDataDocumentHandler), like so:
AppEntityAction onEntityCommit(AppDocumentBlock documentBlock, AppBlock fromBlock, AppEntity toEntity)
{
AppEntityAction ret;
int64 recId; // Should point to the record currently being imported into CMCTRS
;
ret = super(documentBlock, fromBlock, toEntity);
recId = toEntity.getRecord().recId;
// Do whatever you need to do with the recId now
return ret;
}
Here is my method to insert the notes, in case you need that too:
private static boolean insertNote(RefTableId _tableId, int64 _docuRefId, str _note, str _name, boolean _isPublic)
{
DocuRef docuRef;
boolean insertResult = false;
;
if (_docuRefId)
{
try
{
docuRef.clear();
ttsbegin;
docuRef.RefCompanyId = curext();
docuRef.RefTableId = _tableId;
docuRef.RefRecId = _docuRefId;
docuRef.TypeId = 'Note';
docuRef.Name = _name;
docuRef.Notes = _note;
docuRef.Restriction = (_isPublic) ? DocuRestriction::External : DocuRestriction::Internal;
docuRef.insert();
ttscommit;
insertResult = true;
}
catch
{
ttsabort;
error("Could not insert " + ((_isPublic) ? "public" : "private") + " comment:\n\n\t\"" + _note + "\"");
}
}
return insertResult;
}