Json Transformer

JsonTransformer.TransformToken - Test Examples

This document provides comprehensive examples for testing the TransformToken method in the JsonTransformer class.

Table of Contents

  1. Basic Field Extraction
  2. Nested Property Access
  3. Field Combination
  4. Wildcard Usage
  5. Array Element Mapping
  6. Type Casting
  7. Complex Transformations
  8. Nested Object Mapping with Literal Values
  9. JSONPath Filter Expressions
  10. FormData Field Extraction
  11. Edge Cases

Basic Field Extraction

Example 1: Simple Property Mapping

Source JSON:

{
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe@example.com",
  "age": 30
}

Pattern:

{
  "name": "firstName",
  "contact": "email",
  "userAge": "age"
}

Expected Result:

{
  "name": "John",
  "contact": "john.doe@example.com",
  "userAge": 30
}

Nested Property Access

Example 2: Deep Nested Object Access

Source JSON:

{
  "user": {
    "profile": {
      "personal": {
        "firstName": "Jane",
        "lastName": "Smith"
      },
      "contact": {
        "email": "jane.smith@example.com",
        "phone": "+1-555-0123"
      }
    },
    "settings": {
      "theme": "dark",
      "language": "en"
    }
  }
}

Pattern:

{
  "fullName": "user.profile.personal.firstName",
  "emailAddress": "user.profile.contact.email",
  "phoneNumber": "user.profile.contact.phone",
  "preferredTheme": "user.settings.theme"
}

Expected Result:

{
  "fullName": "Jane",
  "emailAddress": "jane.smith@example.com",
  "phoneNumber": "+1-555-0123",
  "preferredTheme": "dark"
}

Field Combination

Example 3: Combining Multiple Fields

Source JSON:

{
  "firstName": "Robert",
  "middleName": "James",
  "lastName": "Johnson",
  "title": "Dr.",
  "suffix": "PhD"
}

Pattern:

{
  "fullName": "firstName + lastName",
  "formalName": "title + firstName + middleName + lastName + suffix",
  "displayName": "firstName + middleName + lastName"
}

Expected Result:

{
  "fullName": "Robert Johnson",
  "formalName": "Dr. Robert James Johnson PhD",
  "displayName": "Robert James Johnson"
}

Important Notes on Field Combination:

  • Fields are joined with a single space separator
  • Empty, null, or whitespace-only fields are automatically skipped
  • Internal whitespace, newlines, and special characters are preserved
  • Only leading and trailing spaces/tabs are trimmed from each field value
  • Newlines (\n, \r\n) within field values are preserved
  • Supports complex values like XML tags, multilingual text, and formatted strings

Complex Value Example:

{
  "name": "<km-KH>សៀវនី</km-KH>\n<en-US></en-US>",
  "code": "001"
}

Pattern:

{
  "nameCode": "name + code"
}

Result:

{
  "nameCode": "<km-KH>សៀវនី</km-KH>\n<en-US></en-US> 001"
}

The newlines and XML-like tags are preserved in the combined output.


Wildcard Usage

Example 4: Preserve Entire Object

Source JSON:

{
  "id": "user_123",
  "name": "Alice Cooper",
  "email": "alice@example.com",
  "metadata": {
    "createdAt": "2024-01-15T10:30:00Z",
    "updatedAt": "2024-11-23T14:45:00Z",
    "version": 2
  }
}

Pattern:

{
  "userId": "id",
  "userName": "name",
  "original": "*"
}

Expected Result:

{
  "userId": "user_123",
  "userName": "Alice Cooper",
  "original": {
    "id": "user_123",
    "name": "Alice Cooper",
    "email": "alice@example.com",
    "metadata": {
      "createdAt": "2024-01-15T10:30:00Z",
      "updatedAt": "2024-11-23T14:45:00Z",
      "version": 2
    }
  }
}

Array Element Mapping

Example 5: Simple Flat Array Mapping

Source JSON:

[
  {
    "orderId": "ORD001",
    "customerName": "Alice",
    "status": "completed",
    "total": 150.50
  },
  {
    "orderId": "ORD002",
    "customerName": "Bob",
    "status": "pending",
    "total": 200.00
  },
  {
    "orderId": "ORD003",
    "customerName": "Charlie",
    "status": "completed",
    "total": 75.25
  }
]

Pattern:

{
  "@array": "$[*]",
  "@map": {
    "id": "orderId",
    "customer": "customerName",
    "orderStatus": "status",
    "amount": "total:decimal"
  }
}

Expected Result:

[
  {
    "id": "ORD001",
    "customer": "Alice",
    "orderStatus": "completed",
    "amount": 150.50
  },
  {
    "id": "ORD002",
    "customer": "Bob",
    "orderStatus": "pending",
    "amount": 200.00
  },
  {
    "id": "ORD003",
    "customer": "Charlie",
    "orderStatus": "completed",
    "amount": 75.25
  }
]

Note: When the source JSON is already a flat array at the root level, use $[*] as the array path to reference all elements.


Example 6: Transform Array Elements with Field Mapping (Nested)

Source JSON:

{
  "data": {
    "users": [
      {
        "id": 1,
        "firstName": "John",
        "lastName": "Doe",
        "email": "john@example.com",
        "isActive": true
      },
      {
        "id": 2,
        "firstName": "Jane",
        "lastName": "Smith",
        "email": "jane@example.com",
        "isActive": false
      },
      {
        "id": 3,
        "firstName": "Bob",
        "lastName": "Wilson",
        "email": "bob@example.com",
        "isActive": true
      }
    ]
  }
}

Pattern:

{
  "@array": "data.users[*]",
  "@map": {
    "userId": "id",
    "fullName": "firstName + lastName",
    "contactEmail": "email",
    "status": "isActive"
  }
}

Expected Result:

[
  {
    "userId": 1,
    "fullName": "John Doe",
    "contactEmail": "john@example.com",
    "status": true
  },
  {
    "userId": 2,
    "fullName": "Jane Smith",
    "contactEmail": "jane@example.com",
    "status": false
  },
  {
    "userId": 3,
    "fullName": "Bob Wilson",
    "contactEmail": "bob@example.com",
    "status": true
  }
]

Type Casting

Example 6: Type Conversion in Array Mapping

Source JSON:

{
  "products": [
    {
      "productId": 101,
      "productName": "Laptop",
      "price": 999.99,
      "quantity": 5,
      "inStock": true,
      "tags": ["electronics", "computers"]
    },
    {
      "productId": 102,
      "productName": "Mouse",
      "price": 29.99,
      "quantity": 50,
      "inStock": true,
      "tags": ["electronics", "accessories"]
    }
  ]
}

Pattern:

{
  "@array": "products[*]",
  "@map": {
    "id": "productId:string",
    "name": "productName",
    "priceInt": "price:int",
    "priceDecimal": "price:decimal",
    "qty": "quantity:int",
    "available": "inStock:bool",
    "displayName": "productName + productId:string"
  }
}

Expected Result:

[
  {
    "id": "101",
    "name": "Laptop",
    "priceInt": 999,
    "priceDecimal": 999.99,
    "qty": 5,
    "available": true,
    "displayName": "Laptop 101"
  },
  {
    "id": "102",
    "name": "Mouse",
    "priceInt": 29,
    "priceDecimal": 29.99,
    "qty": 50,
    "available": true,
    "displayName": "Mouse 102"
  }
]

Complex Transformations

Example 7: Nested Object with Array Mapping

Source JSON:

{
  "company": {
    "name": "Tech Corp",
    "location": "San Francisco",
    "employees": [
      {
        "empId": "E001",
        "firstName": "Sarah",
        "lastName": "Johnson",
        "department": "Engineering",
        "salary": 120000,
        "skills": ["Python", "Java", "Docker"]
      },
      {
        "empId": "E002",
        "firstName": "Michael",
        "lastName": "Brown",
        "department": "Marketing",
        "salary": 85000,
        "skills": ["SEO", "Content Writing", "Analytics"]
      }
    ]
  }
}

Pattern:

{
  "companyName": "company.name",
  "office": "company.location",
  "staff": {
    "@array": "company.employees[*]",
    "@map": {
      "employeeId": "empId",
      "fullName": "firstName + lastName",
      "dept": "department",
      "annualSalary": "salary:decimal",
      "monthlySalary": "salary:decimal",
      "originalData": "*"
    }
  }
}

Expected Result:

{
  "companyName": "Tech Corp",
  "office": "San Francisco",
  "staff": [
    {
      "employeeId": "E001",
      "fullName": "Sarah Johnson",
      "dept": "Engineering",
      "annualSalary": 120000.0,
      "monthlySalary": 120000.0,
      "originalData": {
        "empId": "E001",
        "firstName": "Sarah",
        "lastName": "Johnson",
        "department": "Engineering",
        "salary": 120000,
        "skills": ["Python", "Java", "Docker"]
      }
    },
    {
      "employeeId": "E002",
      "fullName": "Michael Brown",
      "dept": "Marketing",
      "annualSalary": 85000.0,
      "monthlySalary": 85000.0,
      "originalData": {
        "empId": "E002",
        "firstName": "Michael",
        "lastName": "Brown",
        "department": "Marketing",
        "salary": 85000,
        "skills": ["SEO", "Content Writing", "Analytics"]
      }
    }
  ]
}

FormData Field Extraction

Example 9: Extract Field Value from FormData Array

This example demonstrates how to filter through a fieldDatas array to find a specific field by its fieldKey and extract nested data values.

Source JSON:

{
  "formData": {
    "id": "form_12345",
    "fieldDatas": [
      {
        "id": "field_001",
        "fieldKey": "FirstName",
        "data": {
          "value": "John",
          "displayValue": "John"
        }
      },
      {
        "id": "field_002",
        "fieldKey": "LicenseSelect",
        "data": {
          "value": "DL-2024-ABC123",
          "displayValue": "Driver's License: DL-2024-ABC123",
          "metadata": {
            "issueDate": "2024-01-15",
            "expiryDate": "2029-01-15"
          }
        }
      },
      {
        "id": "field_003",
        "fieldKey": "Email",
        "data": {
          "value": "john@example.com",
          "displayValue": "john@example.com"
        }
      }
    ]
  }
}

Pattern:

{
  "license_id": "formData.fieldDatas[?(@.fieldKey == 'LicenseSelect')].data.value"
}

Expected Result:

{
  "license_id": "DL-2024-ABC123"
}

Alternative Pattern (Multiple Fields):

{
  "license_id": "formData.fieldDatas[?(@.fieldKey == 'LicenseSelect')].data.value",
  "license_display": "formData.fieldDatas[?(@.fieldKey == 'LicenseSelect')].data.displayValue",
  "license_metadata": "formData.fieldDatas[?(@.fieldKey == 'LicenseSelect')].data.metadata",
  "first_name": "formData.fieldDatas[?(@.fieldKey == 'FirstName')].data.value",
  "email": "formData.fieldDatas[?(@.fieldKey == 'Email')].data.value"
}

Alternative Pattern Result:

{
  "license_id": "DL-2024-ABC123",
  "license_display": "Driver's License: DL-2024-ABC123",
  "license_metadata": {
    "issueDate": "2024-01-15",
    "expiryDate": "2029-01-15"
  },
  "first_name": "John",
  "email": "john@example.com"
}

Pattern with Type Casting:

{
  "license_id": "formData.fieldDatas[?(@.fieldKey == 'LicenseSelect')].data.value:string",
  "license_id_display": "formData.fieldDatas[?(@.fieldKey == 'LicenseSelect')].data.value",
  "first_name_upper": "formData.fieldDatas[?(@.fieldKey == 'FirstName')].data.value:string"
}

Type Casting Result:

{
  "license_id": "DL-2024-ABC123",
  "license_id_display": "DL-2024-ABC123",
  "first_name_upper": "John"
}

Use Case: This pattern is commonly used when working with dynamic form data where fields are stored in an array structure with keys and nested data objects. It allows you to extract specific field values by filtering on the fieldKey property. Type casting can be applied directly to the JSONPath expression using the :type syntax.


JSONPath Filter Expressions with Type Casting

Example 10: Extract and Cast Field Values from FormData Array

This example demonstrates type casting combined with JSONPath filter expressions to extract and transform field values.

Source JSON:

{
  "formSubmission": {
    "id": "sub_789",
    "fieldDatas": [
      {
        "id": "field_001",
        "fieldKey": "age",
        "data": {
          "value": "25",
          "displayValue": "25 years old"
        }
      },
      {
        "id": "field_002",
        "fieldKey": "salary",
        "data": {
          "value": "75000.50",
          "displayValue": "$75,000.50"
        }
      },
      {
        "id": "field_003",
        "fieldKey": "isActive",
        "data": {
          "value": "true",
          "displayValue": "Active"
        }
      },
      {
        "id": "field_004",
        "fieldKey": "employeeId",
        "data": {
          "value": 12345,
          "displayValue": "EMP-12345"
        }
      }
    ]
  }
}

Pattern:

{
  "age_int": "formSubmission.fieldDatas[?(@.fieldKey == 'age')].data.value:int",
  "age_string": "formSubmission.fieldDatas[?(@.fieldKey == 'age')].data.value:string",
  "salary_decimal": "formSubmission.fieldDatas[?(@.fieldKey == 'salary')].data.value:decimal",
  "salary_int": "formSubmission.fieldDatas[?(@.fieldKey == 'salary')].data.value:int",
  "is_active_bool": "formSubmission.fieldDatas[?(@.fieldKey == 'isActive')].data.value:bool",
  "employee_id_string": "formSubmission.fieldDatas[?(@.fieldKey == 'employeeId')].data.value:string",
  "employee_id_raw": "formSubmission.fieldDatas[?(@.fieldKey == 'employeeId')].data.value"
}

Expected Result:

{
  "age_int": 25,
  "age_string": "25",
  "salary_decimal": 75000.50,
  "salary_int": 75000,
  "is_active_bool": true,
  "employee_id_string": "12345",
  "employee_id_raw": 12345
}

Supported Type Casts with JSONPath Filters:

  • :string or :str - Convert to string
  • :int or :integer - Convert to 32-bit integer
  • :long or :int64 - Convert to 64-bit integer
  • :decimal - Convert to decimal (high precision)
  • :double - Convert to double-precision float
  • :float - Convert to single-precision float
  • :bool or :boolean - Convert to boolean
  • :date - Convert to date (time component removed)
  • :datetime - Convert to full datetime

Use Case: This pattern is useful when extracting form field values that need to be transformed to specific data types for API integration, database storage, or business logic processing. The type casting ensures that string representations of numbers, booleans, or dates are properly converted to their native types.


Example 8: Nested Object Mapping with Literal Values

This example demonstrates using nested object patterns within @map to create structured field metadata objects. The @literal:value syntax outputs literal strings without extracting from source data.

Source JSON:

[
  {
    "name": "Chenda da",
    "numberOfShares": 20,
    "from": 10,
    "to": 20,
    "startDate": "2025-11-29T00:00:00+07:00",
    "note": "First shareholder"
  },
  {
    "name": "រឹម ចំរើន",
    "numberOfShares": 10,
    "from": 1,
    "to": 10,
    "startDate": "2025-11-29T00:00:00+07:00",
    "note": null
  }
]

Pattern:

{
  "@array": "$[*]",
  "@map": {
    "name": {
      "fieldKey": "@literal:name",
      "data": "name"
    },
    "numberOfShares": {
      "fieldKey": "@literal:numberOfShares",
      "data": "numberOfShares:int"
    },
    "from": {
      "fieldKey": "@literal:from",
      "data": "from:int"
    },
    "to": {
      "fieldKey": "@literal:to",
      "data": "to:int"
    },
    "startDate": {
      "fieldKey": "@literal:startDate",
      "data": "startDate:datetime"
    },
    "note": {
      "fieldKey": "@literal:note",
      "data": "note"
    }
  }
}

Expected Result:

[
  {
    "name": {
      "fieldKey": "name",
      "data": "Chenda da"
    },
    "numberOfShares": {
      "fieldKey": "numberOfShares",
      "data": 20
    },
    "from": {
      "fieldKey": "from",
      "data": 10
    },
    "to": {
      "fieldKey": "to",
      "data": 20
    },
    "startDate": {
      "fieldKey": "startDate",
      "data": "2025-11-29T00:00:00"
    },
    "note": {
      "fieldKey": "note",
      "data": "First shareholder"
    }
  },
  {
    "name": {
      "fieldKey": "name",
      "data": "រឹម ចំរើន"
    },
    "numberOfShares": {
      "fieldKey": "numberOfShares",
      "data": 10
    },
    "from": {
      "fieldKey": "from",
      "data": 1
    },
    "to": {
      "fieldKey": "to",
      "data": 10
    },
    "startDate": {
      "fieldKey": "startDate",
      "data": "2025-11-29T00:00:00"
    },
    "note": {
      "fieldKey": "note",
      "data": null
    }
  }
]

Use Case: This pattern is useful when transforming data for dynamic form systems where each field needs metadata (like fieldKey, fieldType, label, etc.) alongside the actual data value. The @literal: prefix allows you to output static strings as values, while nested objects enable rich structured transformations.


Edge Cases

Source JSON:

{
  "orders": [
    {
      "orderId": "ORD001",
      "customerName": "Alice",
      "status": "completed",
      "total": 150.50
    },
    {
      "orderId": "ORD002",
      "customerName": "Bob",
      "status": "pending",
      "total": 200.00
    },
    {
      "orderId": "ORD003",
      "customerName": "Charlie",
      "status": "completed",
      "total": 75.25
    }
  ]
}

Pattern:

{
  "completedOrder": "orders[?(@.status == 'completed')].orderId",
  "pendingCustomer": "orders[?(@.status == 'pending')].customerName",
  "completedTotal": "orders[?(@.status == 'completed')].total"
}

Expected Result:

{
  "completedOrder": "ORD001",
  "pendingCustomer": "Bob",
  "completedTotal": 150.50
}

Edge Cases

Example 11: Null and Missing Values

Source JSON:

{
  "user": {
    "id": 123,
    "name": "Test User",
    "email": null,
    "phone": ""
  }
}

Pattern:

{
  "userId": "user.id",
  "userName": "user.name",
  "contact": "user.email",
  "phoneNumber": "user.phone",
  "missingField": "user.address",
  "fullInfo": "user.name + user.email + user.phone"
}

Expected Result:

{
  "userId": 123,
  "userName": "Test User",
  "contact": null,
  "phoneNumber": "",
  "missingField": null,
  "fullInfo": "Test User"
}

Example 12: Case-Insensitive Property Matching

Source JSON:

{
  "FirstName": "Emma",
  "lastName": "Watson",
  "EMAIL": "emma@example.com",
  "PhoneNumber": "+44-7700-900000"
}

Pattern (with ignoreCase=true):

{
  "name": "firstname + lastname",
  "email": "email",
  "phone": "phonenumber"
}

Expected Result:

{
  "name": "Emma Watson",
  "email": "emma@example.com",
  "phone": "+44-7700-900000"
}

Notes

  1. Case Sensitivity: Set ignoreCase=true for case-insensitive property matching
  2. Performance: Complex nested transformations may impact performance with large datasets
  3. Error Handling: Invalid paths return null, invalid type casts return null
  4. JSONPath Filters: Supports simple equality filters (==, !=) with type casting support (e.g., path[?(@.key == 'value')].field:int)
  5. Field Combination: Empty or null fields are skipped in combination
  6. Type Casting: Can be applied to any string pattern including JSONPath filters using :type syntax
  7. Array Mapping: Use @array and @map for transforming array elements with field mapping
  8. Nested Objects: @map supports nested object patterns for creating structured transformations
  9. Literal Values: Use @literal:value syntax to output literal strings instead of extracting from source data