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

params

Map[string,any]

params_ field is a map that contains parameter definition to configure DSM document and `Parsing Element`_s.

transformations

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.

functions

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.

fragments

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.

result

Parsing Element

REQUIRED. The entry point of Parsing Element declarations. The result field defines structure of the output.

$extends

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

fieldName

string

REQUIRED fieldName define the name of the property to expose by current object. the fieldName is unique in object.

dataType

string

REQUIRED. The data type of exposed field. it may have extra parameter provided with dataTypeParams

dataTypeParams

Map[string,any]

extra parameters for dataType field need to convert. for example. dateFormat for dataType

type

string

the name of the parsing strategy for the current field. the default is STD.

typeParams

Map[string,any]

it is used for passing extra parameter to dataType converter. typeParams field extended to params field.

path

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.

parentPath

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.

default

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.

filter

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.

transformationCode

string

this field refers to the definition of the transformation_ to be used to transform the tag value.

function

string

name of the function in functions map.

normalize

string

this field is used to normalize the value of tag_. İt is an expression.

uniqueName

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.

xml

Map[string,any]

XML related configuration goes under this tag.

attribute

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.

overwriteByDefault_

boolean

force using default field. Mostly used with filter field.

fields

Map[string,String - Parsing Element Object - [Parsing Element Object] ]

fields of the current object. its only valid for object and array type

$ref

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

std

Simple

dataType

default type if not defined explicitly

object

Complex

Map

array

Complex

List<Map> - List<dataType>

sum

Simple

dataType

fields: array of fieldName of current object.

multiply

Simple

dataType

fields: array of fieldName of current object.

divide

Simple

dataType

fields: array of fieldName of current object.

join

Simple

dataType

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 “sumtype 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 “multiplytype is defined on) is defined in “fields” in typeParams_, current property value is multiplied with total result. (multiply with self)

(Explained with example below)

typeParams:

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 “dividetype is defined on) is defined in “fields” in typeParams_, current property value is divided with total result. (divide with self)

(Explained with example below)

typeParams:

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 “jointype 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(,)

typeParams:

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

expression

Name

Data Type

Description

Example

params

Map<string,any>

params object.

params.dateFormat ==’dd.MM.yyyy’

self

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.

all

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

Transformations

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

functions

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

params

Map<string,any>

params object.

params.dateFormat ==’dd.MM.yyyy’

self

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.

all

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

Expression

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

XML Object

$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.

$ref

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

value

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

params

Map<string,any>

params object.

params.dateFormat ==’dd.MM.yyyy’

self

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.

all

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

default

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

path

string

xml specific path definition default value is path field of Parsing Element Object

parentPath

string

xml specific parentPath definition. default value is parentPath field of Parsing Element Object

attribute

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

xml

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

See also

path

parentPath

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

Apache JEXL

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.

See also

$extends

$ref

The following fields are available in the expression context.

Name

Data Type

Description

Example

params

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

params

Map<string,any>

params object.

params.dateFormat ==’dd.MM.yyyy’

all

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

self

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:
  1. if field not exist in source, copy value of target to source.

  2. 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
  }]