function _validateWebsiteConfigXml(parsingResult) {
    const websiteConfig = new WebsiteConfiguration();
    let errMsg;

    function _isValidString(value) {
        return (typeof value === 'string' && value !== '');
    }

    if (!parsingResult.IndexDocument && !parsingResult.RedirectAllRequestsTo) {
        errMsg = 'Value for IndexDocument Suffix must be provided if ' +
        'RedirectAllRequestsTo is empty';
        return errorInstances.InvalidArgument.customizeDescription(errMsg);
    }

    if (parsingResult.RedirectAllRequestsTo) {
        const parent = parsingResult.RedirectAllRequestsTo;
        const redirectAllObj = {};
        if (parsingResult.IndexDocument || parsingResult.ErrorDocument ||
        parsingResult.RoutingRules) {
            errMsg = 'RedirectAllRequestsTo cannot be provided in ' +
            'conjunction with other Routing Rules.';
            return errorInstances.InvalidRequest.customizeDescription(errMsg);
        }
        if (!xmlContainsElem(parent, 'HostName')) {
            errMsg = 'RedirectAllRequestsTo not well-formed';
            return errorInstances.MalformedXML.customizeDescription(errMsg);
        }
        if (!_isValidString(parent[0].HostName[0])) {
            errMsg = 'Valid HostName required in RedirectAllRequestsTo';
            return errorInstances.InvalidRequest.customizeDescription(errMsg);
        }
        redirectAllObj.hostName = parent[0].HostName[0];
        if (xmlContainsElem(parent, 'Protocol', { validateParent: false })) {
            if (parent[0].Protocol[0] !== 'http' &&
            parent[0].Protocol[0] !== 'https') {
                errMsg = 'Invalid protocol, protocol can be http or https. ' +
                'If not defined, the protocol will be selected automatically.';
                return errorInstances.InvalidRequest.customizeDescription(errMsg);
            }
            redirectAllObj.protocol = parent[0].Protocol[0];
        }
        websiteConfig.setRedirectAllRequestsTo(redirectAllObj);
    }

    if (parsingResult.IndexDocument) {
        const parent = parsingResult.IndexDocument;
        if (!xmlContainsElem(parent, 'Suffix')) {
            errMsg = 'IndexDocument is not well-formed';
            return errorInstances.MalformedXML.customizeDescription(errMsg);
        } else if (!_isValidString(parent[0].Suffix[0])
        || parent[0].Suffix[0].indexOf('/') !== -1) {
            errMsg = 'IndexDocument Suffix is not well-formed';
            return errorInstances.InvalidArgument.customizeDescription(errMsg);
        }
        websiteConfig.setIndexDocument(parent[0].Suffix[0]);
    }

    if (parsingResult.ErrorDocument) {
        const parent = parsingResult.ErrorDocument;
        if (!xmlContainsElem(parent, 'Key')) {
            errMsg = 'ErrorDocument is not well-formed';
            return errorInstances.MalformedXML.customizeDescription(errMsg);
        }
        if (!_isValidString(parent[0].Key[0])) {
            errMsg = 'ErrorDocument Key is not well-formed';
            return errorInstances.InvalidArgument.customizeDescription(errMsg);
        }
        websiteConfig.setErrorDocument(parent[0].Key[0]);
    }

    if (parsingResult.RoutingRules) {
        const parent = parsingResult.RoutingRules;
        if (!xmlContainsElem(parent, 'RoutingRule', { isList: true })) {
            errMsg = 'RoutingRules is not well-formed';
            return errorInstances.MalformedXML.customizeDescription(errMsg);
        }
        for (let i = 0; i < parent[0].RoutingRule.length; i++) {
            const rule = parent[0].RoutingRule[i];
            const ruleObj = { redirect: {} };
            if (!_isValidElem(rule.Redirect)) {
                errMsg = 'RoutingRule requires Redirect, which is ' +
                'missing or not well-formed';
                return errorInstances.MalformedXML.customizeDescription(errMsg);
            }
            // Looks like AWS doesn't actually make this check, but AWS
            // documentation specifies at least one of the following elements
            // must be in a Redirect rule. We also need at least one of the
            // elements to know how to implement a redirect for a rule.
            // http://docs.aws.amazon.com/AmazonS3/latest/API/
            // RESTBucketPUTwebsite.html
            if (!xmlContainsElem(rule.Redirect, ['Protocol', 'HostName',
                'ReplaceKeyPrefixWith', 'ReplaceKeyWith', 'HttpRedirectCode'],
            { validateParent: false })) {
                errMsg = 'Redirect must contain at least one of ' +
                'following: Protocol, HostName, ReplaceKeyPrefixWith, ' +
                'ReplaceKeyWith, or HttpRedirectCode element';
                return errorInstances.MalformedXML.customizeDescription(errMsg);
            }
            if (rule.Redirect[0].Protocol) {
                if (!_isValidElem(rule.Redirect[0].Protocol) ||
                (rule.Redirect[0].Protocol[0] !== 'http' &&
                rule.Redirect[0].Protocol[0] !== 'https')) {
                    errMsg = 'Invalid protocol, protocol can be http or ' +
                    'https. If not defined, the protocol will be selected ' +
                    'automatically.';
                    return errorInstances.InvalidRequest.customizeDescription(errMsg);
                }
                ruleObj.redirect.protocol = rule.Redirect[0].Protocol[0];
            }
            if (rule.Redirect[0].HttpRedirectCode) {
                errMsg = 'The provided HTTP redirect code is not valid. ' +
                'It should be a string containing a number.';
                if (!_isValidElem(rule.Redirect[0].HttpRedirectCode)) {
                    return errorInstances.MalformedXML.customizeDescription(errMsg);
                }
                const code = parseInt(rule.Redirect[0].HttpRedirectCode[0], 10);
                if (Number.isNaN(code)) {
                    return errorInstances.MalformedXML.customizeDescription(errMsg);
                }
                if (!(code > 300 && code < 400)) {
                    errMsg = `The provided HTTP redirect code (${code}) is ` +
                    'not valid. Valid codes are 3XX except 300';
                    return errorInstances.InvalidRequest.customizeDescription(errMsg);
                }
                ruleObj.redirect.httpRedirectCode = code;
            }
            for (let j = 0; j < redirectValuesToCheck.length; j++) {
                const elemName = redirectValuesToCheck[j];
                const elem = rule.Redirect[0][elemName];
                if (elem) {
                    if (!_isValidElem(elem) || !_isValidString(elem[0])) {
                        errMsg = `Redirect ${elem} is not well-formed`;
                        return errorInstances.InvalidArgument
                            .customizeDescription(errMsg);
                    }
                    ruleObj.redirect[`${elemName.charAt(0).toLowerCase()}` +
                    `${elemName.slice(1)}`] = elem[0];
                }
            }
            if (xmlContainsElem(
                rule.Redirect,
                ['ReplaceKeyPrefixWith', 'ReplaceKeyWith'],
                { validateParent: false, checkForAll: true })) {
                errMsg = 'Redirect must not contain both ReplaceKeyWith ' +
                'and ReplaceKeyPrefixWith';
                return errorInstances.InvalidRequest.customizeDescription(errMsg);
            }
            if (Array.isArray(rule.Condition) && rule.Condition.length === 1) {
                ruleObj.condition = {};
                if (!xmlContainsElem(rule.Condition, ['KeyPrefixEquals',
                    'HttpErrorCodeReturnedEquals'])) {
                    errMsg = 'Condition is not well-formed. ' +
                    'Condition should contain valid KeyPrefixEquals or ' +
                    'HttpErrorCodeReturnEquals element.';
                    return errorInstances.InvalidRequest.customizeDescription(errMsg);
                }
                if (rule.Condition[0].KeyPrefixEquals) {
                    const keyPrefixEquals = rule.Condition[0].KeyPrefixEquals;
                    if (!_isValidElem(keyPrefixEquals) ||
                    !_isValidString(keyPrefixEquals[0])) {
                        errMsg = 'Condition KeyPrefixEquals is not well-formed';
                        return errorInstances.InvalidArgument
                            .customizeDescription(errMsg);
                    }
                    ruleObj.condition.keyPrefixEquals = keyPrefixEquals[0];
                }
                if (rule.Condition[0].HttpErrorCodeReturnedEquals) {
                    errMsg = 'The provided HTTP error code is not valid. ' +
                    'It should be a string containing a number.';
                    if (!_isValidElem(rule.Condition[0]
                        .HttpErrorCodeReturnedEquals)) {
                        return errorInstances.MalformedXML.customizeDescription(errMsg);
                    }
                    const code = parseInt(rule.Condition[0]
                        .HttpErrorCodeReturnedEquals[0], 10);
                    if (Number.isNaN(code)) {
                        return errorInstances.MalformedXML.customizeDescription(errMsg);
                    }
                    if (!(code > 399 && code < 600)) {
                        errMsg = `The provided HTTP error code (${code}) is ` +
                        'not valid. Valid codes are 4XX or 5XX.';
                        return errorInstances.InvalidRequest
                            .customizeDescription(errMsg);
                    }
                    ruleObj.condition.httpErrorCodeReturnedEquals = code;
                }
            }
            websiteConfig.addRoutingRule(ruleObj);
        }
    }
    return websiteConfig;
}
Validate XML, returning an error if any part is not valid
@param {object} parsingResult - object parsed from xml to be validated
@param {object[]} parsingResult.IndexDocument -
  Required if RedirectAllRequestsTo is not defined
@param {string[]} parsingResult.IndexDocument[].Suffix -
  Key that specifies object in bucket to serve as index
@param {object[]=} parsingResult.ErrorDocument - Optional
@param {string[]} parsingResult.ErrorDocument[].Key -
  Key that specifies object in bucket to serve as error document.
@param {object[]} parsingResult.RedirectAllRequestsTo -
  Contains fields to specify how to redirect all requests to bucket.
@param {string[]} parsingResult.RedirectAllRequestsTo[].HostName -
  Hostname to use when redirecting all requests.
@param {string[]=} parsingResult.RedirectAllRequestsTo[].Protocol -
  Optional, protocol to use when redirecting all request ('http' or 'https')
@param {object[]=} parsingResult.RoutingRules -
  Contains list of rules for redirecting specific requests.
@param {object[]} parsingResult.RoutingRules[].RoutingRule -
  Contains redirect and condition information for specific redirects.
@param {object[]} parsingResult.RoutingRules[].RoutingRule[].Redirect -
  Contains information for how to redirect, required for a RoutingRule.
@param {string[]=} parsingResult.RoutingRules[].RoutingRule[].Redirect[]
  .Protocol - Protocol to use for a specific redirect.
@param {string[]=} parsingResult.RoutingRules[].RoutingRule[].Redirect[]
  .HostName - Hostname to use in a specific redirect.
@param {string[]=} parsingResult.RoutingRules[].RoutingRule[].Redirect[]
  .ReplaceKeyPrefixWith - What to replace a key prefix specified in a
  Condition with in a redirect
@param {string[]=} parsingResult.RoutingRules[].RoutingRule[].Redirect[]
  .ReplaceKeyWith - What to replace the object key with in a redirect
@param {string[]=} parsingResult.RoutingRules[].RoutingRule[].Redirect[]
  .HttpRedirectCode - Http code (301-399) to use in redirect.
@param {object[]=} parsingResult.RoutingRules[].RoutingRule[].Condition
    - Optional, contains fields for conditions to make a specific redirect
@param {string[]=} parsingResult.RoutingRules[].RoutingRule[]
  .Condition[].KeyPrefixEquals - Specify the prefix to match for a redirect
@param {string[]=} parsingResult.RoutingRules[].RoutingRule[]
  .Condition[].HttpErrorCodeReturnedEquals - Error code to match for redirect
@return {(Error|WebsiteConfiguration)} return WebsiteConfiguration on success;
  otherwise return error