AliasedValue attributes handling

Mar 18, 2015 at 11:56 AM
I think the toolkit could handle AliasedValue attributes better.

Currently the toolkit returns the type of these attributes as AliasedValue, rather than the underlying attribute type.

The following check will ensure the correct type is checked and attribute handled correctly.
if (sType.replace('c:', '').replace('a:', '') === "AliasedValue") {
    var subNode = tempNode.childNodes[2];
    sType = $(subNode).attr("i:type");
    tempNode = subNode;
}
This needs to be added in the deserialize function after the line:
// Determine the Type of Attribute value we should expect
var sType = tempNode.attributes.getNamedItem("i:type").value;
This will also fix an apparent bug in the toolkit where an EntityReference attribute from a linked entity is not handled correctly, because the check for an EntityReference attribute type for an AliasedValue is incorrectly checking for a:EntityReference instead of EntityReference.

I'm prettry sure that this block of code would no longer necessary.
//@Credit: Thanks for Tanguy92's code from CodePlex
else if (entCv.type === "AliasedValue") {
    var currentNode = tempNode.childNodes[2];
    entCv.value = getNodeText(currentNode);
    if (currentNode.attributes.getNamedItem("i:type").nodeValue.split(":")[1] === "EntityReference") {
        entCv = new xrmEntityReference();
        entCv.type = "EntityReference";
        entCv.id = getNodeText(currentNode.childNodes[0]);
        entCv.logicalName = getNodeText(currentNode.childNodes[1]);
        entCv.name = getNodeText(currentNode.childNodes[2]);
    }
}
Mar 19, 2015 at 10:54 AM
I've actually found another issue which doesn't affect the original published code but is an issue if using my "fix".

The default block in the switch statement extracts the text value like this:
entCv.value = getNodeText(tempParentNode.childNodes[1]);
with my changes in places this needs to be:
entCv.value = getNodeText(tempNode);
For clarity here is my amended deserialize function in full.
        /**
        * Deserialize an XML node into a CRM Business Entity object. The XML node comes from CRM Web Service's response.
        * @param {object} resultNode The XML node returned from CRM Web Service's Fetch, Retrieve, RetrieveMultiple messages.
        */
        deserialize: function (resultNode) {
            var obj = new Object();
            var resultNodes = resultNode.childNodes;

            for (var j = 0, lenj = resultNodes.length; j < lenj; j++) {
                var sKey;
                var parentNode = resultNodes[j];
                switch (parentNode.nodeName) {
                    case "a:Attributes":
                        var attr = parentNode;
                        for (var k = 0, lenk = attr.childNodes.length; k < lenk; k++) {

                            var tempParentNode = attr.childNodes[k];
                            // Establish the Key for the Attribute
                            var tempParentNodeChildNodes = tempParentNode.childNodes;

                            sKey = getNodeText(tempParentNodeChildNodes[0]);

                            var tempNode = tempParentNodeChildNodes[1];

                            // Determine the Type of Attribute value we should expect
                            var sType = tempNode.attributes.getNamedItem("i:type").value;

                            // check for AliasedValue
                            if (sType.replace('c:', '').replace('a:', '') === "AliasedValue") {
                                // reset the type to the actual attribute type
                                var subNode = tempNode.childNodes[2];
                                sType = $(subNode).attr("i:type");

                                // reset the node to the AliasedValue value node
                                tempNode = subNode;
                            }

                            var entRef;
                            var entCv;
                            switch (sType) {
                                case "a:OptionSetValue":
                                    var entOsv = new xrmOptionSetValue();
                                    entOsv.type = sType.replace('a:', '');
                                    entOsv.value = parseInt(getNodeText(tempNode));
                                    obj[sKey] = entOsv;
                                    break;

                                case "a:EntityReference":
                                    entRef = new xrmEntityReference();
                                    entRef.type = sType.replace('a:', '');
                                    var oChildNodes = tempNode.childNodes;
                                    entRef.id = getNodeText(oChildNodes[0]);
                                    entRef.logicalName = getNodeText(oChildNodes[1]);
                                    entRef.name = getNodeText(oChildNodes[2]);
                                    obj[sKey] = entRef;
                                    break;

                                case "a:EntityCollection":
                                    entRef = new xrmEntityCollection();
                                    entRef.type = sType.replace('a:', '');

                                    //get all party items....
                                    var items = [];
                                    var partyNodes = tempNode.childNodes;
                                    for (var y = 0, leny = partyNodes[0].childNodes.length; y < leny; y++) {
                                        var itemNodes = tempParentNode.childNodes[1].childNodes[0].childNodes[y].childNodes[0].childNodes;
                                        for (var z = 0, lenz = itemNodes.length; z < lenz; z++) {
                                            var itemNodeChildNodes = itemNodes[z].childNodes;
                                            var nodeText = getNodeText(itemNodeChildNodes[0]);
                                            if (nodeText === "partyid") {
                                                var itemRef = new xrmEntityReference();
                                                itemRef.id = getNodeText(itemNodeChildNodes[1].childNodes[0]);
                                                itemRef.logicalName = getNodeText(itemNodeChildNodes[1].childNodes[1]);
                                                itemRef.name = getNodeText(itemNodeChildNodes[1].childNodes[2]);
                                                items[y] = itemRef;
                                            }
                                        }
                                    }
                                    entRef.value = items;
                                    obj[sKey] = entRef;
                                    break;

                                case "a:Money":
                                    entCv = new xrmValue();
                                    entCv.type = sType.replace('a:', '');
                                    entCv.value = parseFloat(getNodeText(tempNode));
                                    obj[sKey] = entCv;
                                    break;

                                default:
                                    entCv = new xrmValue();
                                    entCv.type = sType.replace('c:', '').replace('a:', '');
                                    if (entCv.type === "int") {
                                        entCv.value = parseInt(getNodeText(tempNode));
                                    }
                                    else if (entCv.type === "decimal" || entCv.type === "double") {
                                        entCv.value = parseFloat(getNodeText(tempNode));
                                    }
                                    else if (entCv.type === "dateTime") {
                                        entCv.value = stringToDate(getNodeText(tempNode));
                                    }
                                    else if (entCv.type === "boolean") {
                                        entCv.value = (getNodeText(tempNode) === 'false') ? false : true;
                                    }
                                    // suspect this block of code is no longer required as AliasedValue is handled previously
                                    //@Credit: Thanks for Tanguy92's code from CodePlex
                                    else if (entCv.type === "AliasedValue") {
                                        var currentNode = tempNode.childNodes[2];
                                        entCv.value = getNodeText(currentNode);
                                        if (currentNode.attributes.getNamedItem("i:type").nodeValue.split(":")[1] === "EntityReference") {
                                            entCv = new xrmEntityReference();
                                            entCv.type = "EntityReference";
                                            entCv.id = getNodeText(currentNode.childNodes[0]);
                                            entCv.logicalName = getNodeText(currentNode.childNodes[1]);
                                            entCv.name = getNodeText(currentNode.childNodes[2]);
                                        }
                                    }
                                    else {
                                        // extract the text from the value node
                                        entCv.value = getNodeText(tempNode);
                                    }
                                    obj[sKey] = entCv;
                                    break;
                            }
                        }
                        this.attributes = obj;
                        break;

                    case "a:Id":
                        this.id = getNodeText(parentNode);
                        break;

                    case "a:LogicalName":
                        this.logicalName = getNodeText(parentNode);
                        break;

                    case "a:FormattedValues":
                        var foVal = parentNode;

                        for (var o = 0, leno = foVal.childNodes.length; o < leno; o++) {
                            // Establish the Key, we are going to fill in the formatted value of the already found attribute
                            var foNode = foVal.childNodes[o];
                            sKey = getNodeText(foNode.childNodes[0]);
                            this.attributes[sKey].formattedValue = getNodeText(foNode.childNodes[1]);
                            if (isNaN(this.attributes[sKey].value) && this.attributes[sKey].type === "dateTime") {
                                this.attributes[sKey].value = new Date(this.attributes[sKey].formattedValue);
                            }
                        }
                        break;
                }
            }
        }
Coordinator
Jun 29, 2015 at 9:50 AM
Hi There.

Many thanks for the submission of the bugs and the code to fix.

These should be included in the latest release.

Kind Regards,
Jaimie