Back to Code List
javascript

Data layer converter

This code takes an existing multi-level nested object (e.g. W3C digitalData object) and flattens into a single level format that most third party vendors prefer. This also helps simplify tag management implementations (such as Tealium) and organizes your data in a fashion that keeps information localized to single variables instead of split out between nested objects.

   converter.js

try {
    var output_layer = output_layer || "";
    var stuartrosk = stuartrosk || {};
    stuartrosk.com = stuartrosk.com || {};
    stuartrosk.com.stuartrosk_w3c = {};
    stuartrosk.com.stuartrosk_w3c.udo = {};

    // change the "digitalData" to the object you wish to convert
    var objectToConvert = digitalData;
    
    /*
     * change these mappings to convert items in the raw converted layer
     * to readable data variables. The items on the left will be a "contains"
     * where the matched key contains that value. The items on the right are
     * what they will be changed in to. For example, if you have a key named
     * "my-current-data_source" and want to change it to "sample_source", the
     * below item might look like "data_source" : "sample_source".
     *
     * To see the object before it is converted to find out its keys,
     * comment out line 226 and enter the following into the console to see
     * the output: stuartrosk.com.stuartrosk_w3c.udo
     */    
    stuartrosk.com.mapping_keys = {
        "product_id"              : "product_id",
        "product_sku"             : "product_sku",
        "product_name"            : "product_name",
        "primary_category"        : "product_category",
        "sub_category1"           : "product_subcategory",
        "price-total_price"       : "product_unit_price",
        "quantity"                : "product_quantity",
        "transaction_id"          : "order_id",
        "cart_total"              : "order_total",
        "base_price"              : "order_subtotal",
        "order_level_promo_total" : "order_discount",
        "total-shipping"          : "order_shipping",
        "currency"                : "order_currency",
        "profileinfo-profile_id"  : "customer_id",
        "profileinfo-user_name"   : "customer_username",
        "page_type"               : "page_type",
        "page_name"               : "page_name",
        "unit_price"              : "product_unit_price",
        "product_discount"        : "product_discount",
        "."                       : "product_brand",
        "."                       : "product_list_price",
        "."                       : "order_payment_type",
        "."                       : "order_tax",
        "."                       : "order_coupon_code",
        "."                       : "order_coupon_discount",
        "."                       : "order_store",
        "."                       : "order_type",
        "."                       : "customer_city",
        "."                       : "customer_state",
        "."                       : "customer_zip",
        "."                       : "customer_country",
        "."                       : "customer_email",
        "."                       : "customer_type",
        "."                       : "page_category",
        "."                       : "page_subcategory",
        "."                       : "search_results",
        "."                       : "search_term"
    };

    stuartrosk.com.convert_mapping_keys = function (obj) {
        /* 
         * This function takes an object and changes matching
         * key names found in the stuartrosk.com.mapping_keys object
         * @param obj: object to update all keys in
         */
         
        for (idx in obj) {
            val = obj[idx];
            temp = "";
            if (val instanceof Array) temp = obj[idx].slice(0);
            else if (typeof val == "object") {
                temp = {};
                for (k in val) temp[k] = val[k];
            }
            else temp = obj[idx];
            delete obj[idx];

            newIdx = false;
            for (key in stuartrosk.com.mapping_keys) {
                if (idx.indexOf(key) > -1) {
                    newIdx = stuartrosk.com.mapping_keys[key];
                    break;
                }
            }
            if (!newIdx) newIdx = idx;
            obj[newIdx] = temp;
        }
    };

    function varChange(obj) {
        /*
         * This function converts camelCase items to all lowercase
         * like so: camel_case. This keeps things on a standardized
         * level.
         * @param obj: object to update all keys in
         */
         
        for (idx in obj) {
            val = obj[idx];
            temp = "";
            if (val instanceof Array) temp = obj[idx].slice(0);
            else if (typeof val == "object") {
                temp = {};
                for (k in val)
                    temp[k] = val[k];
            }
            else temp = obj[idx];
            delete obj[idx];
            newIdx = idx.replace(/([a-z][A-Z])/g, function(a) {
                return a[0] + '_' + a[1];
            }).toLowerCase();
            obj[newIdx] = temp;
        }
    }
    
    stuartrosk.com.convert_data_layer = function (data) {
        /*
         * This is the meat of converting the data layer. It houses
         * several different functions for use in converting a given
         * data layer object.
         * @param data: the original object that we want to convert
         */
         
        var delim = "-";
        var result = {};

        function recurse(cur, prop) {
            /*
             * This function will completely flatten a nested object
             * which can then be manipulated in a reverse manner. The
             * result will go into the above "result" object.
             * @param cur: current level object we are looking at
             * @param prop: current object element property
             */
            if (Object(cur) !== cur) result[prop] = cur;
            else if (Array.isArray(cur)) {
                for (var i = 0, l = cur.length; i < l; i++) recurse(cur[i], prop + "[" + i + "]");
                if (l == 0) result[prop] = [];
            }
            else {
                var isEmpty = true;
                for (var p in cur) {
                    isEmpty = false;
                    recurse(cur[p], prop ? prop + delim + p : p);
                }
                if (isEmpty && prop) result[prop] = {};
            }
        }

        function findLikeItems(arr, obj) {
            /*
             * This function will take a given element name and loop through
             * the given object. If there are any like array items, this will
             * combine them into a single array, then remove the old ones from
             * the original object.
             * @param arr: an array with details about the current property:
             *      arr[0]: the property prefix before the array identifier "["
             *      arr[1]: the full property name
             *      arr[2]: the value assigned to this property
             * @param obj: the object to loop through and find like properties
             */
             
            newObj = {};
            currFront = arr[0].substr(0, arr[0].length - 3); //prefix before array identifier
            currFull = arr[1];                               //full variable name (key)
            val = arr[2];                                    //value of key,val pair
            currIdx = 0;
            for (r in obj) {
                if (r.indexOf(currFront) == 0) {
                    currBack = r.substr(currFront.length + 5, currFull.length);
                    newObj[currBack] = newObj[currBack] || [];
                    newObj[currBack].push(obj[r]);
                    delete obj[r];
                }
            }
            return newObj;
        }

        //checks each item in the given object
        function checkItem(obj) {
            /*
             * This function will check to see if a given property should
             * be grouped by arrays. It will either run the findLikeItems
             * function or will directly copy the property to our new
             * output object.
             * @param obj: the object we are looking to check for arrays
             * @output newResult: the new object that is grouped as needed
             */
             
            checkAgain = false;
            newResult = {};
            for (i in obj) {
                workingSet = [];
                terms = i.split(delim);
                hasArr = false;
                //look for an array identifier
                if (i.indexOf('[') > -1) {
                    hasArr = true;
                    checkAgain = true;
                }
                //not an array item, just put into our new object
                if (!hasArr) newResult[i] = obj[i];
                else {
                    //it was an array, we'll handle it by going backwards (if nested arr)
                    lastArrIdx = i.lastIndexOf('[');
                    workingSet = [ i.substr(0, lastArrIdx + 2), i, obj[i] ];
                    newObj = findLikeItems(workingSet, obj);
                    for (n in newObj) newResult[n] = newObj[n];
                }
            }
            //an array was found, recheck the obj in case of nested arrays
            if (checkAgain) checkItem(newResult); //objects pass by pointer, no need to assign to a variable
            return newResult;
        }

        recurse(data, "");          //flatten the object
        varChange(result);          //standardize the variables
        return checkItem(result);   //return the converted object with grouped arrays
    }
    stuartrosk.com.stuartrosk_w3c.udo = stuartrosk.com.convert_data_layer(objectToConvert) //convert the object
    
    //comment the following line to discover raw keys to use for your own mappings
    stuartrosk.com.convert_mapping_keys(stuartrosk.com.stuartrosk_w3c.udo);
    
    //comment this following line if you'd like to use the converted result even if output_layer already exists on the page
    if (!output_layer)                                                           
        output_layer = stuartrosk.com.stuartrosk_w3c.udo;
    
} catch (e) {
    utag.DB("Error in converting data layer: ", e);
}    

   cartSample.js

var digitalData = {
    "cart" : {
        "price" : {
            "basePrice" : "8.99",
            "currency" : "USD",
            "itemLevelPromoTotal" : "0.00",
            "orderLevelPromoTotal" : "",
            "shipping" : "7.99",
            "shippingDiscountAmount" : "0.00",
            "discountTotal" : "0.00",
            "cartTotal" : "16.98",
            "attributes" : {
                "orderLevelPromotion" : "[]"
            }
        },
        "item" : [{
                "productInfo" : {
                    "productID" : "30230516",
                    "productSKU" : "17676385",
                    "productName" : "Teenage Mutant Ninja Turtles Movie Basic Figure  Raphael"
                },
                "category" : {
                    "primaryCategory" : "Action Figures ",
                    "subCategory1" : "Movies & TV"
                },
                "quantity" : "1",
                "price" : {
                    "perUnitPrice" : "8.99",
                    "totalPrice" : "8.99",
                    "attributes" : {}

                }
            }
        ],
        "attributes" : {
            "numberOfProducts" : "1"
        }
    },
    "sessionID" : "670013788",
    "page" : {
        "pageInfo" : {
            "pageName" : "Shopping Bag",
            "pageType" : "Shopping Bag",
            "pageURL" : "trus-uat02.uat.gsipartners.com/cart/index.jsp?sub_store_code=TRU&pageType=cart&pageType_rr=cart&sub=tru&sub_rr=tru",
            "sysEnv" : "desktop"
        }
    },
    "user" : [{
            "profile" : [{
                    "profileinfo" : {
                        "profileID" : "",
                        "userName" : ""
                    }
                }
            ]
        }
    ],
    "version" : "1.0"
}
    

   transactionSample.js

var digitalData = {
    "transaction": {
        "transactionID": "4532929063",
        "total": {
            "basePrice": "4.99",
            "currency": "USD",
            "itemLevelPromoTotal": "0.00",
            "orderLevelPromoTotal": "",
            "shipping": "7.99",
            "shippingDiscountAmount": "0.00",
            "discountTotal": "0.00",
            "cartTotal": "13.38",
            "attributes": {}
        },
        "item": [
            {
                "productInfo": {
                    "productID": "2396157",
                    "productSKU": "3024275",
                    "productName": "CrayolaWashableKidsPaint10Pack"
                },
                "category": {
                    "primaryCategory": "Arts  CraftsSupplies",
                    "subCategory1": "Paint  PaintingSupplies"
                },
                "quantity": "1",
                "price": {
                    "totalPrice": "4.99",
                    "attributes": {}
                }
            }
        ],
        "profile": {
            "profileInfo": {
                "profileID": "3213814363",
                "userName": ""
            }
        },
        "attributes": {
            "numberOfProducts": "1"
        }
    },
    "sessionID": "931994234",
    "page": {
        "pageInfo": {
            "pageName": "Checkout: Final Purchase",
            "pageType": "Checkout: Final Purchase",
            "pageURL": "trus-uat02.uat.gsipartners.com/checkout.jsp?process=thanks",
            "sysEnv": "desktop"
        }
    },
    "user": [
        {
            "profile": [
                {
                    "profileinfo": {
                        "profileID": "3213814363",
                        "userName": ""
                    }
                }
            ]
        }
    ],
    "version": "1.0"
}