Introduction¶
Declarative Stream Mapping(DSM) is a stream deserializer library that works for both XML and JSON. DSM allows you to make custom parsing, filtering, transforming, aggregating, grouping on any JSON or XML document at stream time(read once). There is no need to writing custom parser. DSM use yaml or json configuration file to parse data. Processed data can be deserialized to java classes.
Definitions¶
- DSM Document:
A document (or set of documents) that defines or describes parsing element definition uses and conforms to the DSM Specification.
- Source Document:
Document(File, Stream, String, HTTP Request Payload) contains JSON or XML data.
Format¶
DSM document is a JSON object, which maybe represented either in JSON or YAML format. All field names in the specification are case sensitive. This includes all fields that are used as keys in a map, except where explicitly noted that keys are case insensitive.
Document Structure¶
DSM document may be made up single document or divided into multiple connected parts at the discretion of the user. In later case, $extends fields must be used to reference those parts.
Schema¶
In the following description, if a field is not explicitly REQUIRED or described with a MUST or SHALL, it can be considered OPTIONAL.
DSM Object¶
This is the root document object of the DSM document.
- Fields:
Field Name
Type
Description
version
string
REQUIRED. This string MUST be the semantic version number of the DSM Specification version that the DSM document uses. The DSM field SHOULD be used by tooling specifications and clients to interpret the DSM document
Map[string,any]
params_ field is a map that contains parameter definition to configure DSM document and `Parsing Element`_s.
Map[string,`Transformation Element`_]
Deceleration of Map contains transformationCode as key, and Transformation Element as value. Transformation Element holds lookup table to transform value from Source Document to destination document.
Map[string,Function_]
Deceleration of Map contains function name as key, and function deceleration as value. functions are used for custom parsing or calling services with parsed data. Functions implements FunctionExecutor interface.
Map [String, Parsing Element ]
A map contains declaration of reusable Parsing Element. The fragment definition can be referenced with $ref_ field while defining Parsing Element.
REQUIRED. The entry point of Parsing Element declarations. The result field defines structure of the output.
string
`$extends`_ field is used for import external DSM document.
params¶
params field is a map that contains parameter definition to configure DSM document and Parsing Element. The key of params map is string and case sensitive. The value of params map can be any type of json object(int, boolean, object, array) accepted by JSON and YAML specification.
Example DSM document that contains params.
YAML
version: 1.0
params:
dateFormat: dd.MM.yyyy
rootPath: fooBar/foo
category:
foo: bar
acceptedCountryCode: [TR,US,FR]
JSON
{
"version": 1.0,
"params":{
"dateFormat":"dd.MM.yyyy",
"rootPath":"fooBar/foo",
"category":{
"foo":"bar"
},
"acceptedCountryCode": ["TR","US","FR"]
}
}
transformations¶
Deceleration of Map contains transformationCode as key, and Transformation Element as value. Transformation Element holds lookup table to transform value from Source Document to destination document.
Example CF document that contains transformations
YAML
version: 1.0 transformations: COUNTRY_CODE_TO_NAME: map: DEFAULT: Other TR: Turkey US: United States
JSON
{
"version": 1.0,
"transformations":{
"COUNTRY_CODE_TO_NAME":{
"map":{
"TR":"Turkey",
"US":"United States",
"DEFAULT":"Other"
}
}
}
}
functions¶
Deceleration of Map contains function name as key, and function deceleration as value. functions are used for custom parsing or calling services with parsed data. Functions implements FunctionExecutor interface.
Example CF document that contains functions
YAML
version: 1.0 functions: insertProduct: com.example.InsertProduct approveOrder: com.example.ApproveOrder
JSON
{
"version": 1.0,
"functions":{
"insertProduct":"com.example.InsertProduct",
"approveOrder":"com.example.ApproveOrder"
}
}
fragments¶
A map contains declaration of reusable Parsing Element. The fragment definition can be referenced with $ref field while defining Parsing Element.
Example CF document that contains functions
YAML
version: 1.0
fragments:
product:
fields:
id: string
name: string
price: double
JSON
{ "version": 1.0, "fragments":{ "product":{ "fields":{ "id":"string", "name":"double", "price":"double" } } } }
result¶
REQUIRED. The entry point of Parsing Element declarations. The result field defines structure of the output.
Example CF document that contains result
YAML
version: 1.0 result: type: object path: / fields: id: string name: string price: double
JSON
{
"version": 1.0,
"result":{
"type":"object",
"path":"/"
"fields":{
"id":"string",
"name":"double",
"price":"double"
}
}
}
$extends¶
$extends field is used for import external DSM document to current DSM document. it’s value is basically relative path or URI definition of external DSM document. if it’s value start with “$” sing, it is accepted as an expression and resolved by expression resolver. External DSM document will merged into current DSM document. $extends can also be list of path or URI. Merge process start from first element to last element. Firstly current DSM document merged with first element then result of merge process extended to second element etc..
Example CF document that contains extends
YAML
version: 1.0
$extends: /foo/bar/external.yaml
or
version: 1.0
params:
rootPath: /bar/foo/
$extends:
- /foo/bar/external.yaml
- $params.rootPath.concat("externalWithExpression.yaml")
JSON
{
"version": 1.0,
"$extends": "/foo/bar/external.json"
}
or
{
"version": 1.0,
"params":{
"rootPath":"/bar/foo/"
},
"$extends": ["/foo/bar/external.json","$params.rootPath.concat('externalWithExpression.json')"]
}
Parsing Element Object¶
Parsing Element is basic object of DSM. Parsing Element contains set of rules for parsing specific tag of Source Document
- Fields:
Field Name
Type
Description
string
REQUIRED fieldName define the name of the property to expose by current object. the fieldName is unique in object.
string
REQUIRED. The data type of exposed field. it may have extra parameter provided with dataTypeParams
Map[string,any]
extra parameters for dataType field need to convert. for example. dateFormat for dataType
string
the name of the parsing strategy for the current field. the default is STD.
Map[string,any]
it is used for passing extra parameter to dataType converter. typeParams field extended to params field.
string
The path field specifies the location of a tag in the source document relative to the path field of the higher-level Parsing Element definition. The default value is the value in the fieldName field.
string
The parentPath field is used in a slightly more complex parsing definitions. it holds path to parent tag of the tag specified in the “path” field.
string,`Default Object`_
default value of the field if path not exist in the source document. if default value starts with “$” character it is accepted as expression and it is resolved by expression resolver.
string
The Filter field determines whether the value of a Parsing Element Object (complex or simple type does not matter) is added to the object tree. The filter field is an expression that returns true or false.
string
this field refers to the definition of the transformation_ to be used to transform the tag value.
string
name of the function in functions map.
string
this field is used to normalize the value of tag_. İt is an expression.
string
When “fieldName” fields of complex Parsing Element definitions are the same in the DSM document, these definitions are differentiated by using the “uniqueKey” field.
Map[string,any]
XML related configuration goes under this tag.
boolean
it is indicates that the current Parsing Element Object is an attribute on the tag pointed to by the parentPath field in the xml.
boolean
force using default field. Mostly used with filter field.
Map[string,String - Parsing Element Object - [Parsing Element Object] ]
fields of the current object. its only valid for object and array type
string
$ref_ field is used to extends current config to given fragment_. it’s value is an expression.
fieldName¶
REQUIRED The fieldName define the name of the property to expose by current object. the fieldName is unique in object.. However, a fieldName may have multiple Parsing Element. The fieldName is not explicitly defined. it is defined with fields property. The keys of fields map are the fieldName of the Parsing Element.
In blow DSM document, id, name, and price are fieldName of the result object. The result object exposes id, name and price property
YAML
result: # fieldName is result
version: 1.0
path: /
type:object
id: string # fieldName is id
fields:
price: double
name: string # fieldName is name
JSON
{
"version": 1.0,
"result":{
"type":"object",
"path":"/"
"fields":{
"id":"string",
"name":"double",
"price":"double"
}
}
}
dataType¶
The dataType field defines data type (string, int, boolean etc.) of the exposed property. it is basicity a converter from string to given dataType type. it may need extra parameters to convert a string to given data dataType. Extra parameters may be provided with params or dataTypeParams.
Supported dataType name and their corresponding java class:
Type Name |
Java Type |
Extra Parameters |
---|---|---|
int |
int |
|
float |
float |
|
short |
short |
|
double |
double |
|
long |
long |
|
date |
date |
dateFormat(required) |
boolean |
boolean |
|
char |
char |
|
BigDecimal |
BigDecimal |
|
BigInteger |
BigInteger |
YAML
version: 1.0
params:
dateFormat: dd.MM.yyyy # default 'dateFormat' for all 'date' dataType
result:
type:object
path: /
fields:
id: string
name: string # implicitly defined dataType. dataType is string
price:
dataType: double # explicitly defined dataType dataType. type is double
createDate: date # implicitly defined the date dataType. and 'dateFormat' is defined in params field.
modifiedTime:
dataType: date # explicitly defined the date dataType. and 'dateFormat' is defined in dataTypeParams field.
dataTypeParams:
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'"
JSON
{
"version": 1.0,
"params":{
"dateFormat": "dd.MM.yyyy"
},
"result":{
"type":"object",
"path":"/",
"fields":{
"id":"string",
"name":"double",
"price":{
"dataType": "double"
},
"createDate": "date",
"modifiedTime": {
"dataType": "date",
"dataTypeParams": {
"dateFormat":"yyyy-MM-dd'T'HH:mm:ss'Z'"
}
}
}
}
}
dataTypeParams¶
dataTypeParams is used for passing extra parameters to a dataType convert. dataTypeParams field extended to params field.
Check example here.
type¶
type defines how tags in the source document are parsed. it also defines the structure of the output object and hierarchy of the object tree. it may need extra parameters. Extra parameters are provided with typeParams field that extended to params field. Basically, there are two main “type” categories which are “complex”, and “simple”. The complex category includes “tagTypes” which exposes complex data dataType such as object or arrays. the simple category includes tagTypes which expose data type in the dataType field.
Supported type’s:
Type Name |
Category |
Java Type |
Extra Parameters |
---|---|---|---|
Simple |
default type if not defined explicitly |
||
Complex |
Map |
||
Complex |
List<Map> - List<dataType> |
||
Simple |
fields: array of fieldName of current object. |
||
Simple |
fields: array of fieldName of current object. |
||
Simple |
fields: array of fieldName of current object. |
||
Simple |
fields: array of fieldName of current object, separator: separator string. default is comma(,) |
std¶
std is basic type which copy the value of the tag in the source document to the current object. std is the default value of the type field. Data dataType is defined in dataType_ype_ field.
YAML
version: 1.0
result:
type: object
path: /
fields:
foo: string # tag type is STD
bar: int # tag type is STD
JSON
{
"version": 1.0,
"result":{
"type":"object",
"path":"/" ,
"fields":{
"foo":"string",
"bar":"int"
}
}
}
object¶
object type is used to expose an object. Parsing Element which has “object” type must have ‘fields’ field.
YAML
version: 1.0
result:
type: object
path: /
fields:
id: string
name: string
price: double
JSON
{
"version": 1.0,
"result":{
"type":"object",
"path":"/" ,
"fields":{
"id":"string",
"name":"string",
"price":"double"
}
}
}
Above DSM document generate following output(values are only example) :
{
"id":"11111",
"name":"foo",
"price":1111.111
}
array¶
array type is used to expose an array. Items of the array may be a object or simple dataType. if Parsing Element has “fields” field then the array type exposes List<Object>. if fields field is not defined, the data type of array item decided dataType field.
YAML
version: 1.0
result:
type: array # EXPOSE [Object] array of Object
path: /
fields:
id: string
name: string
price: double
tags: # EXPOSE [string] array of string
type: array
path: tag
type: string
JSON
{
"version": 1.0,
"result":{
"type":"object",
"path":"/",
"fields":{
"id":"string",
"name":"string",
"price":"double",
"tags":{
"type": "array",
"path": "tag",
"type": "string"
}
}
}
}
Above DSM document generate following output(values are only example) :
[{
"id":"11111",
"name":"foo",
"price":1111.111,
"tags":["foo","bar"]
}]
sum¶
sum type is used to sum properties defined with “fields” in typeParams_. if one of the properties that defined in fields does not exist in the current object, it is accepted as ZERO.
if current property(Parsing Element that “sum” type is defined on) is defined in “fields” in typeParams_, current property value is added to total result.(sum with self)
(Explained with example below)
typeParams:
Name |
Type |
Description |
---|---|---|
fields |
array |
REQUIRED list of fieldName of the properties in parent Parsing Element to sum. |
YAML
version: 1.0
result:
type: object
path: /
fields:
foo: int
bar: bar
fooAndBar:
path: \. # when current object closed
type: sum # declare sum type to sum foo and bar field
type:int
typeParams:
fields:[foo,bar] # sum foo,and bar fields then set to fooAndBar property of current object.
sumWithSelf:
type: sum # declare sum type to sum foo and bar field
type:int
typeParams:
fields:[foo,bar,sumWithSelf] # sum foo, bar and sumWithSelf(current field) fields then set sumWithSelf to total property of current object.
JSON
{
"version": 1.0,
"result":{
"type":"object",
"path":"/" ,
"fields":{
"foo":"int",
"bar":"int",
"fooAndBar":{
"path":"\.",
"type": "sum",
"typeParams":{
"fields":["foo","bar"]
}
},
"sumWithSelf":{
"type": "sum",
"type":"int",
"typeParams":{
"fields":["foo","bar","sumWithSelf"]
}
}
}
}
}
multiply¶
multiply type is used to multiply properties defined with “fields” in typeParams_. if one of the properties that defined in fields does not exist in the current object, it is accepted as ONE.
if current property(Parsing Element that “multiply” type is defined on) is defined in “fields” in typeParams_, current property value is multiplied with total result. (multiply with self)
(Explained with example below)
Name |
Type |
Description |
---|---|---|
fields |
array |
REQUIRED list of field name of the properties in current object to multiply. |
YAML
version: 1.0
result:
type: object
path: /
fields:
foo: int
bar: int
fooAndBar:
path: \. # when current object closed
type: multiply # declare multiply type to sum foo and bar field
type:int
typeParams:
fields:[foo,bar] # multiply foo,and bar fields then set it to fooAndBar property of current object.
multiplyWithSelf:
type: multiply # declare multiply type to sum foo and bar field
type:int
typeParams:
fields:[foo,bar,multiplyWithSelf] # multiply foo, bar and multiplyWithSelf(current field) fields then set it to multiplyWithSelf property of current object.
JSON
{
"version": 1.0,
"result":{
"type":"object",
"path":"/" ,
"fields":{
"foo":"int",
"bar":"int",
"fooAndBar":{
"path":"\.",
"type": "multiply",
"typeParams":{
"fields":["foo","bar"]
}
},
"multiplyWithSelf":{
"type": "multiply"
"type":"int",
"typeParams":{
"fields":["foo","bar","multiplyWithSelf"]
}
}
}
}
}
divide¶
divide type is used to divide properties defined with “fields” in typeParams_. if one of the properties that defined in fields does not exist in the current object, it is accepted as ONE.
if current property(Parsing Element that “divide” type is defined on) is defined in “fields” in typeParams_, current property value is divided with total result. (divide with self)
(Explained with example below)
Name |
Type |
Description |
---|---|---|
fields |
array |
REQUIRED list of field name of the properties in current object to divide. |
YAML
version: 1.0
result:
type: object
path: /
fields:
foo: int
bar: int
fooAndBar:
path: \. # when current object closed
type: divide # declare divide type to sum foo and bar field
type:int
typeParams:
fields:[foo,bar] # divide foo with bar (foo/bar) fields then set it to fooAndBar property of current object.
divideWithSelf:
type: divide # declare divide type to sum foo and bar field
type:int
typeParams:
fields:[foo,bar,divideWithSelf] # divide foo with bar then divide with divideWithSelf(current field) (foo/bar/divideWithSelf) fields then set it to sumWithSelf property of current object.
JSON
{
"version": 1.0,
"result":{
"type":"object",
"path":"/" ,
"fields":{
"foo":"int",
"bar":"int",
"fooAndBar":{
"path":"\.",
"type": "divide",
"typeParams":{
"fields":["foo","bar"]
}
},
"divideWithSelf":{
"type": "divide",
"type":"int",
"typeParams":{
"fields":["foo","bar","divideWithSelf"]
}
}
}
}
}
join¶
join type is used to join properties defined with “fields” in typeParams_. if one of the properties that defined in fields does not exist in the current object, it is skipped.
if current property(Parsing Element that “join” type is defined on) is defined in “fields” in typeParams_, current property value is included in to joining (join with self) Values are separated by separator defined in “typeParams”. The default separator is a comma(,)
Name |
Type |
Description |
---|---|---|
fields |
array |
REQUIRED list of field name of the properties in current object to join. |
separator |
string |
separator string. default is comma(i) |
YAML
version: 1.0
result:
type: object
path: /
fields:
foo: string
bar: string
fooAndBar:
path: \. # when current object closed
type: join # declare join type to sum foo and bar field
type:int
typeParams:
fields:[foo,bar] # join foo and bar (foo,bar) fields then set it to fooAndBar property of current object.
joinWithSelf:
type: join # declare join type to sum foo and bar field
type:int
typeParams:
separator: &
fields:[foo,bar,sumWithSelf] # join foo,bar, and joinWithSelf(current field) (foo&bar&joinWithSelf) fields then set it to joinWithSelf property of current object.
JSON
{
"version": 1.0,
"result":{
"type":"object",
"path":"/" ,
"fields":{
"foo":"string",
"bar":"string",
"fooAndBar":{
"path":"\.",
"type": "join",
"typeParams":{
"fields":["foo","bar"]
}
},
"joinWithSelf":{
"type": "join",
"type":"int",
"typeParams":{
"separator": "&",
"fields":["foo","bar","joinWithSelf"]
}
}
}
}
}
typeParams¶
typeParams is used for passing extra parameters to type field. The typeParams field is extended to params field.
Examples:
YAML
version: 1.0
result:
type: object
path: /
fields:
foo: string
bar: string
fooAndBar:
path: \. # when current object closed
type: join # declare join type to concat foo and bar field
type:int
typeParams: # typeParams is used to pass fields parameter to type
fields:[foo,bar]
JSON
{
"version": 1.0,
"result":{
"type":"object",
"path":"/" ,
"fields":{
"foo":"string",
"bar":"string",
"fooAndBar":{
"path":"\.",
"type": "join",
"typeParams":{
"fields":["foo","bar"]
}
}
}
}
}
path and parentPath¶
The path and parentPath fields indicate which tags are used in the source document during parsing. The value of those fields are regular expressions.
The path field specifies the location of a tag in the source document relative to the path field of the higher-level Parsing Element definition. The default value is the value in the fieldName field.
The parentPath field is used in a slightly more complex parsing definitions. it holds path to parent tag of the tag specified in the “path” field.
The path and parentPath fields can be defined as the relative path as in unix. Relative paths are resolved according to the structure in the DSM document, not by the structure in the source file.
Some example of relative path:
- current
./
- parent
../
- parentOfParent
../../
- categoryInParent
../category
- categoryInCurrent
./category
To find the exact tag path for the current Parsing Element, starting from the result field, all the parentPath and path fields from top to bottom are merged with the “/” character.
tagParentAbsolutePath and tagAbsolutePath evaluated as follow:
currentObject mean is Parsing Element that current path and parentPath is defined parentObject mean is parent Parsing Element of currentObject
parentObject = if (parentPath+path) is relative path then find parentObject by resolving relative path else currentObject.parent
tagParentAbsolutePath = parentObject.path+”/”+currentObject.parentPath
tagAbsolutePath = absoluteParentPath+”/”+currentObject.path
if tagAbsolutePath regex match any absolute path of tag, value of this tag evaluated by type
To explain with example:
result:
path: /orders/order #path = orders/order
#parentPath = ""
#tagAbsolutePath= /orders/order
#tagParentAbsolutePath= /
fields:
defaultName: #path =defaultName (default value is fieldName)
#parentPath = ""
#tagParentAbsolutePath =/orders/order (parent(result) absoluteTagPath))
#tagAbsolutePath =/orders/order/defaultName
tagPathDefined:
path: status #path =status
#parentPath = ""
#tagParentAbsolutePath =/orders/order (parent(result) absoluteTagPath))
#tagAbsolutePath =/orders/order/status
tagPathAndParentPath:
path: name #path = name
parentPath: category #parentPath = category
#tagParentAbsolutePath =/orders/order/category
#tagAbsolutePath =/orders/order/category/name
innerObject:
type: object
path: foo #path = "innerObject"
#parentPath = ""
#tagParentAbsolutePath =/orders/order
#tagAbsolutePath =/orders/order/innerObject
fields:
normalPathInInnerObject: #path = "normalPathInInnerObject"
#parentPath = ""
#tagParentAbsolutePath =/orders/order/innerObject
#tagAbsolutePath =/orders/order/innerObjcet/normalPathInInnerObject
relativeTagPath:
path:./defaultName #path = ../defaultName (only level up)
#parentPath = ""
#tagParentAbsolutePath =/orders/order
#tagAbsolutePath =/orders/order/defaultName
relativeParentPath:
path:defaultName #path = defaultName
parentPath:../ #parentPath = "../" (only level up)
#tagParentAbsolutePath =/orders/order
#tagAbsolutePath =/orders/order/defaultName relativeTagPathAndParentPath:
path:../defaultName #path = defaultName
parentPath:../ #parentPath = "../" (only level up)
#tagParentAbsolutePath =/orders/order
#tagAbsolutePath =/orders/order/../defaultName (relative path of parentPath important. path considered as regex)
relativePathFromResult:
path:/orders/order/defaultName #path = /orders/order/defaultName
#parentPath = ""
#tagParentAbsolutePath =/orders/order/defaultName
#tagAbsolutePath =/orders/order
tagAbsolutePath and tagParentAbsolutePath:
fieldName |
path |
parentPath |
tagAbsolutePath |
tagParentAbsolutePath |
---|---|---|---|---|
result |
orders/order |
order/simpleOrder |
/ |
|
result |
orders/order |
order/simpleOrder |
/ |
|
defaultName |
defaultName(default value is fieldName) |
order/simpleOrder/defaultName |
order/simpleOrder |
|
tagPathDefined |
status |
order/simpleOrder/status |
order/simpleOrder |
|
tagPathAndParentPath |
status |
order/simpleOrder/category/name |
order/simpleOrder/category |
|
innerObject |
innerObject |
order/simpleOrder/innerObject |
order/simpleOrder |
|
normalPathInInnerObject |
normalPathInInnerObject |
order/simpleOrder/innerObject/normalPathInInnerObject |
order/simpleOrder/innerObject |
|
relativeTagPath |
defaultName |
order/simpleOrder/defaultName |
order/simpleOrder |
|
relativeParentPath |
defaultName |
order/simpleOrder/defaultName |
order/simpleOrder |
|
relativeTagPathAndParentPath |
defaultName |
order/simpleOrder/..defaultName (relative path of parentPath important. path considered as regex) |
order/simpleOrder |
|
relativePathFromResult |
/orders/order/defaultName |
order/simpleOrder/defaultName |
order/simpleOrder |
fields¶
The fields field is used to define the properties of complex objects. Only Parsing Element that has complex type can have the “fields” field.
The fields field is a map that keys are fieldName of Parsing Element , values are string, Parsing Element or list of Parsing Element
Type of Value Definition¶
The value of the map can be empty, string, Parsing Element or array of Parsing Element.
Different value definitions create Parsing Element with some default values.
Below explain type of value definition and the default values of the Parsing Element that it creates.
- empty:
- fieldName
key of the map.
- dataType
string
- path
key of the map (fieldName)
- parentPath
null
- string:
- fieldName
key of the map.
- dataType
value of the map
- path
key of the map (fieldName)
- parentPath
null
- Parsing Element:
- fieldName
key of the map.
other fields are can be defined or initialized with default values.
- Array of Parsing Element:
some fields of objects can be read from the different tag in the source document. By making multiple definitions for one field, the value of different tags can be read.
Example of different type of value definition:
YAML
version: 1.0
result:
type: object
path: /
fields:
name: # fieldName is "name" and dataType is string and the path is "/name"
category:
price: long # fieldName is "price" and dataType is "long" and the path is "/price"
categoryType: # fieldName is "categoryType" and it is "string" value and the path is "/categoryType" it has extra definition (default)
default: "foo" # default value a is a string.
productUnit: # this field contains two definition. one of that will win depending on the structure of source document.
- path: unit/unit_name # fieldName is "productUnit" and dataType is "long" and the path is "/unit/unit_name"
default: $ self.data.categoryType=='foo'? 'LT': 'KG'
- path: mainUnit/unit_name # fieldName is "productUnit" and dataType is "long" and the path is "/mainUnit/unit_name"
JSON
{
"version": 1.0,
"result":{
"type"object",
"path":"/" ,
"fields":{
"name":"",
"category":"",
"price":"long",
"categoryType":{
"default": "foo"
},
"productUnit":[
{ "path": "unit/unit_name",
"default": " $self.data.categoryType=='foo'? 'LT': 'KG'"
},
{
"path": "mainUnit/unit_name",
},
],
}
}
}
filter¶
The filter field determines whether the value of a Parsing Element (complex or simple type does not matter) is added to the object tree. The filter field is an expression that returns true or false.
The following objects are available in Expression Context.
See also
Name |
Data Type |
Description |
Example |
---|---|---|---|
Map<string,any> |
params object. |
params.dateFormat ==’dd.MM.yyyy’ |
|
current node object that hold data of current complex type |
self.data.foo => foo field of current node, self.parent.data.foo => foo field of parent node, self.data.bar.foo => foo field of bar object in current node. |
||
Map<string,Node_> |
A map that stores all nodes by the “uniqueName” of Parsing Element |
all.bar.data.foo => foo field of bar node, all.barList.data[0].foo => foo field of first item of barList node |
|
value |
string |
value of the current tag in source document |
value==’Computer’,**value.startWith(‘bar’)** |
Examples:
Example 1
YAML
version: 1.0
result
type: array
path:/
filter: $self.data.category=='Computer' # collect all data that category field is 'Computer'
fields:
name: string
category: string
JSON
{
"version": 1.0,
"result":{
"type":"array",
"path":"/" ,
"filter": "$self.data.category=='Computer'",
"fields":{
"name":"string",
"category":"string"
}
}
}
Example 2
YAML
version: 1.0
result
type: array
path:/
fields:
name: string
category:
filter: $value=='Computer' # only assign "category" if "category" is "computer".
JSON
{
"version": 1.0,
"result":{
"type":"array",
"path":"/" ,
"fields":{
"name":"string",
"category":{
"filter": "$value=='Computer'"
}
}
}
}
Possible Output Of Example 2
[{
"name":"foo",
"category":"Computer"
},
{
"name":"foo"
}]
default¶
The default field holds the value to be assigned to a property by default. The default value is assigned when the path does not match the absolute path of any tag in the source document. If the value of the default field is a string, this value is accepted as the value field of the Default Object.
assignment order of the default is from the bottom to up in an object.
Examples
YAML
version: 1.0
result:
type: object
path: /
fields:
name:
- filter: $ self.data.categoryType=='foo'
default:
value: foo # force set name to foo with filter
force: true
- path: name
category: string
productUnit:
default: $ self.data.categoryType=='foo'? 'LT': 'KG' # default value is expression. this default value is assigned after "categoryType" field assigned.
categoryType:
default: "foo" # default value a is a string.
JSON
{ "version": 1.0, "result":{ "type":"object", "path":"/" , "fields":{ "name":"string", "category":"string", "productUnit":{ "default": " $self.data.categoryType=='foo'? 'LT': 'KG'" }, "categoryType":{ "default": "foo" } } } }
transformationCode¶
transformationCode field refers to the definition of the transformation_ to be used to transform the tag value.
Below definition work as follows:
value of tag “/country_code” is read from source document
if this value exist in “COUNTRY_CODE_TO_NAME” transformation_ definition, get value that match.
if not exist, get “DEFAULT” value of “COUNTRY_CODE_TO_NAME” transformation_ definition
YAML
version: 1.0
transformations:
COUNTRY_CODE_TO_NAME:
map:
DEFAULT: Other
TR: Turkey
US: United States
result:
type: object
path: /
fields:
country:
path: country_code
transformationCode: COUNTRY_CODE_TO_NAME
JSON
{
"version": 1.0,
"transformations":{
"COUNTRY_CODE_TO_NAME":{
"map":{
"TR":"Turkey",
"US":"United States",
"DEFAULT":"Other"
}
}
},
"result":{
"type": "object",
"path": "/",
"fields"{
"country":{
"path": "country_code"
"transformationCode": "COUNTRY_CODE_TO_NAME"
}
}
}
}
See also
function¶
The function field refers to the definition of functions field to be used for the custom operation. For more detail about how functions works, look at functions sections.
Below definition work as follows:
all fields of product are read from source document
When the “/product” tag is closed, the “com.example.InsertProduct” function in the “insertProduct” definition is called.
YAML
version: 1.0
functions:
insertProduct: com.example.InsertProduct
result:
type: object
path: /product
function: insertProduct
fields:
name: string
price: long
image: string
JSON
{
"version": 1.0,
"functions":{
"insertProduct":"com.example.InsertProduct"
},
"result":{
"type": "object",
"path": "/",
"function": "insertProduct",
"fields": {
"name": "string",
"price": "long",
"image": "string"
}
}
}
See also
uniqueName¶
When “fieldName” fields of complex Parsing Element definitions are the same in the DSM document, these definitions are differentiated by using the “uniqueKey” field. This field is optional. The default value is the value of the “fieldName” field. The uniqueName field may need in very complex document parsing.
Example Case:
In the following DSM document, both the users and the orders objects have a category field and the category field is an object. The uniqueName field is used to differentiate the category objects.
YAML
version: 1.0
result:
type: object
path: /
fields:
users:
type: array
fields:
name: string
email: string
category:
type: object
uniqueName: userCategory
fields:
categoryName: string
order:
type: object
fields:
id: string
category:
type: object
uniqueName: orderCategory
fields:
categoryName: string
JSON
{
"version": 1,
"result": {
"type": "object",
"path": "/",
"fields": {
"users": {
"type": "array",
"fields": {
"name": "string",
"email": "string",
"category": {
"type": "object",
"uniqueName": "userCategory",
"fields": {
"categoryName": "string"
}
}
}
},
"order": {
"type": "object",
"fields": {
"id": "string",
"category": {
"type": "object",
"uniqueName": "orderCategory",
"fields": {
"categoryName": "string"
}
}
}
}
}
}
}
normalize¶
The normalize is used to normalize the value of the tag being read. Changes can be made to the raw string value of the tag by using normalize field. The value of this field is an expression.
The following objects are available in Expression Context.
Name |
Data Type |
Description |
Example |
---|---|---|---|
Map<string,any> |
params object. |
params.dateFormat ==’dd.MM.yyyy’ |
|
current node object that hold data of current complex type |
self.data.foo => foo field of current node, self.parent.data.foo => foo field of parent node, self.data.bar.foo => foo field of bar object in current node. |
||
Map<string,Node_> |
A map that stores all nodes by the “uniqueName” of Parsing Element Object |
all.bar.data.foo => foo field of bar node, all.barList.data[0].foo => foo field of first item of barList node |
|
value |
string |
raw string value of the current tag in source document |
value==’Computer’,**value.startWith(‘bar’)** |
See also
xml¶
The xml field is used to make extra definitions and to change “path” and “type” fields for XML format.
check XML Object for more detail
See also
$ref¶
$ref field is used to extends Parsing Element to given fragments. it’s value is a Load Time Expression. fragments can be extends another fragments but can not extends itself. Sometimes we don’t need parent properties. To exclude parent properties, define dataType as “exclude”. In example bellow category property is excluded.
YAML
version: 1.0
result:
type: array
path: /
xml:
path: "/Pets/Pet"
$ref: $fragments.pet
fields:
category: exclude # import all properties of fragments.pet except category property.
isPopular:
default $self.data.tags.stream().anyMatch(s->s.name=='Popular')
fragments:
tag:
type: object
fields:
id: int
name: string
category:
type: object
fields:
id: int
name: string
pet:
type: object
fields:
id: long
name: string
status: string
category:
$ref: $fragments.category
photoUrls:
type: array
path: photoUrls
xml:
path: photoUrls/photoUrls
tags:
type: array
path: tags
xml:
path: tags/tag
$ref: $fragments.tag
JSON
{
"version": 1,
"result": {
"type": "array",
"path": "/",
"xml": {
"path": "/Pets/Pet"
},
"$ref": "$fragments.pet",
"fields": {
"category": "exclude",
"isPopular": "default $self.data.tags.stream().anyMatch(s->s.name=='Popular')"
}
},
"fragments": {
"tag": {
"type": "object",
"fields": {
"id": "int",
"name": "string"
}
},
"category": {
"type": "object",
"fields": {
"id": "int",
"name": "string"
}
},
"pet": {
"type": "object",
"fields": {
"id": "long",
"name": "string",
"status": "string",
"category": {
"$ref": "$fragments.category"
},
"photoUrls": {
"type": "array",
"path": "photoUrls",
"xml": {
"path": "photoUrls/photoUrls"
}
},
"tags": {
"type": "array",
"path": "tags",
"xml": {
"path": "tags/tag"
},
"$ref": "$fragments.tag"
}
}
}
}
}
Transformation Element Object¶
Transformation is a very powerful feature that used to map value of a tag from the source document to destination document. Transformation Element holds the mapping and how the mapping will be used with `Parsing Element`_s. We can consider, transformation as switch-case in programing language. Every record in the mapping table is a case and DEFAULT record is a default case fo switch-case statement.
- Fields:
Field Name
Type
Description
map
Map<String,Object>
REQUIRED mapping table from source to destination
onlyIfExist
boolean
transform source value only if exist in mapping table. if not exist use as is.
string
ref field is used to extends current Transformation Element to another Transformation Element. it is an expression.
YAML
version: 1.0
transformations:
COUNTRY_CODE_TO_NAME:
map:
DEFAULT: Other
TR: Turkey
US: United States
COUNTRY_CODe_TO_NAME_IF_EXIST:
$ref: $transformations.COUNTRY_CODE_TO_NAME
onlyIfExist: true
JSON
{
"version": 1,
"transformations": {
"COUNTRY_CODE_TO_NAME": {
"map": {
"DEFAULT": "Other",
"TR": "Turkey",
"US": "United States"
}
},
"COUNTRY_CODe_TO_NAME_IF_EXIST": {
"$ref": "$transformations.COUNTRY_CODE_TO_NAME",
"onlyIfExist": true
}
}
}
Default Object¶
Default Object determines how the default field is assigned.
- Fields:
Field Name
Type
Description
string
REQUIRED default value that is assigned to current field
force
string
Use the default value, even if the tag specified in the “path” field is in the source file.
atStart
string
assign default value at start of tag.
value¶
REQUIRED it holds default value that is assigned to current field
if the value starts with the “$” character, it is treated as “expression” and is resolved by expression resolver.
The following objects are available in Expression Context.
Name |
Data Type |
Description |
Example |
---|---|---|---|
Map<string,any> |
params object. |
params.dateFormat ==’dd.MM.yyyy’ |
|
current node object that hold data of current complex type |
self.data.foo => foo field of current node, self.parent.data.foo => foo field of parent node, self.data.bar.foo => foo field of bar object in current node. |
||
Map<string,Node_> |
A map that stores all nodes by the “fieldName” of Parsing Element Object |
all.bar.data.foo => foo field of bar node, all.barList.data[0].foo => foo field of first item of barList node |
force¶
if it’s value is true, it means Use the default value, even if the tag specified in the “path” field is in the source file. if force value is true, default value is assigned both start and end of parentPath. It is mostly used with filter field or with value in params. The default value is false.
atStart¶
if atStart filed is true, default value is assigned at start of the tag. other wise default value is assigned at the end of the tag.
See also
XML Object¶
XML Object is used to make extra definitions and to change “path” and “parentPath” fields for xml format
- Fields:
Field Name
Type
Description
string
xml specific path definition default value is path field of Parsing Element Object
string
xml specific parentPath definition. default value is parentPath field of Parsing Element Object
boolean
attribute field is indicates that the current Parsing Element Object is an attribute on the tag pointed to by the parentPath field in the xml.
attribute¶
The attribute field is indicates that the current Parsing Element is an attribute on the tag pointed to by the parentPath field in the xml.
Examples:
YAML
version: 1.0
result:
type: object
path: /
xml:
path: /Pets/Pet # xml specific path definition
fields:
id:
dataType: long
xml:
attribute: true # id field is an attribute that is located at /Pets/Pet tag.
name: string
price: long
image: string
JSON
{
"version": 1.0,
"result":{
"type": "object",
"path": "/" ,
"xml":{
"path": "/Pets/Pet"
}
"fields": {
"id": {
"dataType": "long",
"xml":{
"attribute": "true"
}
},
"name": "string",
"price": "long",
"image": "string"
}
}
}
See also
Absolute Path¶
Absolute Path is found by joining all tag name from top to bottom with “/” character until specified tag.
Below example is json representation of array of Pet object.
Absolute tag paths are listed below.
[
{
"id": 1,
"category": {
"id": 1,
"name": "Cats"
},
"name": "PetNameForm",
"photoUrls": [
"url1",
"url2",
"url3"
],
"tags": [
{
"id": 2,
"name": "New"
},
{
"id": 2,
"name": "Cute"
},
],
"status": "sold"
]
Absolute tag paths of all field in above json document are listed below.
Field Name |
Absolute Path |
---|---|
/ |
|
Pet:id |
/id |
Pet:category |
/category |
Pet:category.id |
/category/id |
Pet:category.name |
/category/name |
Pet:name |
/name |
Pet:photoUrls |
/photoUrls |
Pet:photoUrls.(item) |
/photoUrls |
Pet:tags |
/tags |
Pet:tags.id |
/tags/id |
Pet.tags.name |
/tags/name |
Pet.status |
/status |
Same Example for XML:
<Pets>
<Pet>
<category>
<id>1589257917030308320</id>
<name>Cats</name>
</category>
<id>6598053714149410844</id>
<name>PetNameForm</name>
<photoUrls>
<photoUrl>url1</photoUrl>
<photoUrl>url2</photoUrl>
<photoUrl>url3</photoUrl>
</photoUrls>
<status>sold</status>
<tags>
<tag>
<id>4250197027829930927</id>
<name>New</name>
</tag>
<tag>
<id>8271965854563266871</id>
<name>Cute</name>
</tag>
<tag>
<id>3487705188883980239</id>
<name>Popular</name>
</tag>
</tags>
</Pet>
</Pets>
Absolute tag paths of all field in above XML document are listed below.
Field Name |
Absolute Path |
---|---|
/ |
|
Pets array |
/Pets |
Pets array item |
/Pets/Pet |
Pet:id |
//Pets/Pet/id |
Pet:category |
/Pets/Pet/category |
Pet:category.id |
/Pets/Pet/category/id |
Pet:category.name |
/Pets/Pet/category/name |
Pet:name |
/name |
Pet:photoUrls |
/Pets/Pet/photoUrls |
Pet:photoUrls.(item) |
/Pets/Pet/photoUrls |
Pet:tags |
/Pets/Pet/tags |
Pet:id |
/Pets/Pet/tags/id |
Pet:tags.name |
/Pets/Pet/tags/name |
Pet.status |
/Pets/Pet/status |
Expressions and Scripting¶
Expressions makes DSM very flexible. Expression allows a value to be filtered, manipulated, modified etc. Expressions can access objects in the expression context and do operations by using these objects.
Expressions can be used at both source document parsing time and DSM document loading time.
Expressions are resolved by one of Scripting language such a Javascript, Groovy, Apache JEXL or other JSR223 implementations. Expressions must be written with scripting language syntax. Default scripting language is Apache JEXL
See also
There are two type of expression, Loading Time and Parsing Time expressions.
Loading Time Expression¶
Loading Time Expression is expressions that is only used during loading of `DSM document`. It allows you to modify structure of DSM document.
Loading Time Expressions are defined in the $extends and or $ref fields. For more detail check $extends and or $ref field.
The following fields are available in the expression context.
Name |
Data Type |
Description |
Example |
---|---|---|---|
Map<string,Object> |
params object. |
params.dateFormat ==’dd.MM.yyyy’ |
Example¶
YAML
version: 1.0
params:
rootPath: /bar/foo/
$extends:
- /foo/bar/external.yaml
- $params.rootPath.concat("externalWithExpression.yaml") # use "params" object in expression context to get "rootPath" property
JSON
{
"version": 1.0,
"params":{
"rootPath":"/bar/foo/"
},
"$extends": ["/foo/bar/external.json","$params.rootPath.concat('externalWithExpression.json')"]
}
Parsing Time Expression¶
Parsing Time Expression is expressions that is only used during parsing of `source document`. It allows you to change the structure of the output, change the property value, import a specific part of the source document, filter by property , transform a property, and almost all operations that can be done with custom coding.
The Parsing Time Expressions can be defined in the filter, default, and normalize fields.
The following objects are available in the expression context.
Name |
Data Type |
Description |
Example |
---|---|---|---|
Map<string,any> |
params object. |
params.dateFormat ==’dd.MM.yyyy’ |
|
Map<string,Node_> |
A map that stores all nodes by the “uniqueName” of Parsing Element Object |
all.bar.data.foo => foo field of bar node, all.barList.data[0].foo => foo field of first item of barList node |
|
current node object that hold data of current complex type |
self.data.foo => foo field of current node, self.parent.data.foo => foo field of parent node, self.data.bar.foo => foo field of bar object in current node. |
||
value |
string |
(not available in default field) The raw string value of the current tag in source document |
value==’Computer’,**value.startWith(‘bar’)** |
all¶
Each complex type creates a node_. The created nodes can be accessed using the “all” object in the expressions. Each node is stored in all map with the uniqueName of the Parsing Element that creates the node.
result:
type: array
fields:
order:
type: object
fields:
state: string
createDate: date
saleLines:
type: array
fields:
product:
type: object
fields:
id: string
name: string
price: string
quantity: long
unit: string
company:
type: object
fields:
id: string
name: string
price: string
for configuration at above following all map is created.
result:
parent: null
data:
order: order.data # contains data of the order node
company: company.data
order:
parent: result
data:
orderLines: orderLines.data
company:
parent: result
data: {}
orderLines:
parent: order
data: [{ product:product.data }] # data is array. each item contains product data
product:
parent: orderLines
data: {}
Example usages:
- product.parent
is equals orderLine node
- product.parent.data
is equals orderLine.data
- product.parent.parent
is equals order
- product.parent.parent.data
is equals order.data
- product.parent.parent.parent
is equals result
- order.data.orderLine
is equals orderLine.data
- order.data.orderLine[lastIndex].product
is equals product.data
self¶
current node object that hold data of current complex type.
Example usages:
- self.parent
parent node
- self.data.foo
foo field of current object
- self.data[0]
First element of current array
Example¶
YAML
version: 1.0
result:
type: object
path: /
fields:
name:
- filter: $ self.data.categoryType=='foo' # filter expression.
default:
value: foo # force set name to foo with filter
force: true
- path: name
category:
type: object
fields:
id: int
name:
default: self.parent.data.categoryType=='foo'? 'Foo':'Bar' # default value is expression.
categoryType:
default: all.data.categoryType=='foo'? 'Foo':'Bar' # default value is expression. and its is equivalent of expression in category.name property.
productUnit:
default: $ self.data.categoryType=='foo'? 'LT': 'KG' # default value is expression.
categoryType:
default: "foo" # default value a is a string.
JSON
{ "version": 1.0, "result":{ "type":object", "path":"/" , "fields":{ "name":"string", "category":{ "id": "int", "name": { "default": "self.parent.data.categoryType=='foo'? 'Foo':'Bar'", }, "categoryType": { "default": "default: all.data.categoryType=='foo'? 'Foo':'Bar'", } }, "productUnit":{ "default": " $self.data.categoryType=='foo'? 'LT': 'KG'" }, "categoryType":{ "default": "foo" } } } }
Merge of DSM Document¶
DSM document can extends to another DSM document by using $extends field.
Parsing Element can extends to another Parsing Element by using $ref field.
DSM documents and Parsing Elements are merged with each other.
Before going to explain merge process lets make some definition.
- source:
DSM Document or Parsing Element that we want to extend to another.
- target:
DSM Document or Parsing Element that we want to extend to.
- Merge process work as follows:
- for every field of target do followings:
if field not exist in source, copy value of target to source.
if field exist in source do followings
2.1. if dataType of fields is different then skip this field.
2.2. if dataType of fields is same then do followings
2.2.1. if dataType is simpleDataType (string,number) then skip this field (do not copy target to source)
2.2.2. if dataType is array then add target values to start of the source values
2.2.3. if dataType is map then start Merge process for those two map.
Example merge process of DSM documents:
external DSM Document:(external.yaml)
version: 1.0
params:
dateFormat: dd.MM.yyyy
rootPath: /foo/bar
acceptedCountryCode: [TR,US,FR]
transformations:
COUNTRY_CODE_TO_NAME:
map:
DEFAULT: Other
TR: Turkey
US: United States
result:
fields:
id: string
name: string
price: double
current DSM Document:
version: 1.0
$extends: $params.rootPath.concat("external.yaml") # resolve expression
params:
rootPath: /DSM/MAIN
acceptedCountryCode: [UK]
transformations:
COUNTRY_CODE_TO_NAME:
map:
UK: United Kingdom
result:
type: object
path: /
fields:
category: string
After merge process following configuration will take effect:
version: 1.0
$extends: $params.rootPath.concat("external.yaml")
params:
dateFormat: dd.MM.yyyy # (rule 1) imported from external document
rootPath: /DSM/MAIN # (rule 2.2.1) overwritten by current DSM document
acceptedCountryCode: [TR,US,FR,UK] #(rule 2.2.2) external list element added to start off current list element(UK is only exist in current document and located at the end )
transformations: #(rule 2.2.3) transformations field exist in both source and target and type is MAP
COUNTRY_CODE_TO_NAME: #(rule 2.2.3)
map:
UK: United Kingdom # only exist in current DSM document
DEFAULT: Other # (rule 1) imported from external document
TR: Turkey # (rule 1) imported from external document
US: United States # (rule 1) imported from external document
result:
type: object # exist only current DSM document
path: /
fields:
category: string # exist only current DSM document
id: string
name: string # imported from external document
price: double
Property Assignment Order¶
The property assignment order is very important for the correct operation of the expressions in the filter field and in the default field Referencing a not existing field in “self.data” can cause NullPointerException.
DSM reads source document top to bottom in one pass as a stream. Once it reads a tag source document, it checks whether absolute path of the tag match with tagAbsolutePath_ or taParentAbsolutePath_ of any of Parsing Element if Parsing Element founds, value of tag is assigned according to Parsing Element definitions.
The Property assignment work as follows:
let’s name the tag that is pointed by path as current tag and the tag that is pointed by parentPath as parent tag
The property is assigned when current tag is closed except attribute properties for the XML document. The attribute properties is assigned at start of parent tag by reading attribute value of parent tag
- Order of the property assignment as follows:
the closing of `current tag`_ is near to the document header(starting of parent tag” for attribute )
deeper `current tag`_
Parsing Element definition close to the document header.(assignment start from top to bottom )
The default value of a property is assigned when current tag not exist in source document and parent tag” is closed(for all property, include attribute).
default value is assigned only once except force field is true. if force field is true default value is assigned at both start and close of parent tag
- Order of the default value of property assignment as follows:
assure the property is not assigned or force field is true
the closing of `parent tag`_is near to the document header.
deeper parent tag
Parsing Element definition far to the document header.(assignment start bottom to top )
Example:
<Pets>
<Pet>
<category>
<id>1</id>
<name>Cats</name>
</category>
<id>6598053714149410844</id>
<name>Van Kedisi</name>
<photoUrls>
<photoUrl>url1</photoUrl>
<photoUrl>url2</photoUrl>
<photoUrl>url3</photoUrl>
</photoUrls>
<status>sold</status>
<tags>
<tag>
<id>1</id>
<name>New</name>
</tag>
<tag>
<id>2</id>
<name>Cute</name>
</tag>
<tag>
<id>3</id>
<name>Popular</name>
</tag>
</tags>
</Pet>
</Pets>
result:
type: array
path: /
xml:
path: "/Pets/Pet"
fields:
id:long
name:
status:
isPopular:
default $self.data.tags.stream().anyMatch(s->s.name=='Popular')
category:
type: object
fields:
name:
id: long
photoUrls:
type: array
path: photoUrls
xml:
path: photoUrls/photoUrls
tags:
type: array
path: tags
xml:
path: tags/tag
fields:
id:int
name:
DSM read document top to bottom.
it founds /Pets/Pet absolute path that match with result Parsing Element. Then create a array and put first item into the array.
result=[{}]
it founds /Pets/Pet/category match with category Parsing Element. then it create a object and assign it to category property
result=[{
"category":{}
}]
it founds /Pets/Pet/category/id match with category.id Parsing Element. then it assign it to id property of category object.
result=[{
"category":{
"id": 3
}
}]
it founds /Pets/Pet/category/name match with category.name Parsing Element. then the value is assigned
result=[{
"category":{
"id": 3,
"name": "Cats"
}
}]
it founds /Pets/Pet/id match with id then the value is assigned
result=[{
"category":{
"id": 3,
"name": "Cats"
}
"id":1
}]
it founds /Pets/Pet/name match with name then the value is assigned
result=[{
"category":{
"id": 3,
"name": "Cats"
},
"id":1,
"name":"Van Kedisi",
}]
it founds /Pets/Pet/photoUrls/photoUrl match with photoUrls Parsing Element then the new array is created and assigned
result=[{
"category":{
"id": 3,
"name": "Cats"
},
"id":1,
"name":"Van Kedisi",
"photoUrls":[]
}]
it founds /Pets/Pet/photoUrls/photoUrl match with photoUrls then the value of photoUrls is assigned
result=[{
"category":{
"id": 3,
"name": "Cats"
},
"id":1,
"name":"Van Kedisi",
"photoUrls":["url1","url2","url3"]
}]
after reading all fields under /Pets/Pet path following result generated.
result=[{
"category":{
"id": 3,
"name": "Cats"
},
"id":1,
"name":"Van Kedisi",
"photoUrls":["url1","url2","url3"],
"status":"sold",
"tags":[
{
"id":1,
"name": "New"
},
{
"id":1,
"name": "Cute"
},
{
"id":1,
"name": "Popular"
}
]
}]
it can’t find /Pets/Pet/isPopular but isPopular property has default value. When /Pets/Pet (parent tag) tag is closed then it’s expression is evaluated. The result of expression is assigned to isPopular property.
result=[{
"category":{
"id": 3,
"name": "Cats"
},
"id":1,
"name":"Van Kedisi",
"photoUrls":["url1","url2",url3"],
"status":"sold",
"tags":[
{
"id":1,
"name": "New"
},
{
"id":1,
"name": "Cute"
},
{
"id":1,
"name": "Popular"
}
],
"isPopular": true
}]