aping
Version:
apiNG is an AngularJS directive that enables you to receive, aggregate, limit, order and display data from one or more sources. The complete setup is dead simple, just by adding data-attributes to your html
278 lines (221 loc) • 11.6 kB
JavaScript
;
angular.module('jtt_aping_xml', [])
.directive('apingXml', ['apingUtilityHelper', 'xmlFactory', 'xmlService', function (apingUtilityHelper, xmlFactory, xmlService) {
return {
require: '?aping',
restrict: 'A',
replace: 'false',
link: function (scope, element, attrs, apingController) {
var appSettings = apingController.getAppSettings();
var requests = apingUtilityHelper.parseJsonFromAttributes(attrs.apingXml, 'xml', appSettings);
requests.forEach(function (request) {
if (request.path) {
//create requestObject for factory function call
var requestObject = {
path: request.path,
};
if (angular.isUndefined(request.items)) {
request.items = appSettings.items;
}
if (request.items === 0 || request.items === '0') {
return false;
}
// -1 is 'no explicit limit'. same for NaN value
if (request.items < 0 || isNaN(request.items)) {
request.items = undefined;
}
if (angular.isDefined(request.orderBy) && !angular.isString(request.orderBy)) {
request.orderBy = undefined;
}
if (angular.isDefined(request.orderReverse) && (request.orderReverse === true || request.orderReverse === 'true')) {
request.orderReverse = true;
}
xmlFactory.getData(requestObject)
.then(function (_data) {
var resultArray = [];
if (_data.data) {
var results = xmlService.xml2json(_data.data);
if (angular.isDefined(request.resultProperty)) {
results = apingUtilityHelper.getValueFromObjectByPropertyString(results, request.resultProperty, false);
}
if (results.constructor !== Array) {
resultArray.push(results);
} else {
angular.extend(resultArray, results);
if (angular.isDefined(request.orderBy)) {
if (request.orderBy === '$RANDOM') {
resultArray = apingUtilityHelper.shuffleArray(resultArray);
} else {
resultArray.sort(apingUtilityHelper.sortArrayByProperty(request.orderBy));
}
}
//order desc
if (angular.isDefined(request.orderReverse) && request.orderReverse === true && request.orderBy !== '$RANDOM') {
resultArray.reverse();
}
if (angular.isUndefined(request.items)) {
resultArray = results;
} else {
//crop spare
if (request.items > 0 && resultArray.length > request.items) {
resultArray = resultArray.splice(0, request.items);
}
}
}
}
apingController.concatToResults(resultArray);
});
}
});
}
}
}])
.factory('xmlFactory', ['$http', function ($http) {
var xmlFactory = {};
xmlFactory.getData = function (_requestObject) {
var params = {};
return $http({
method: 'GET',
url: _requestObject.path,
params: params
});
};
return xmlFactory;
}])
.service('xmlService', function () {
var _this = this;
/**
* Removes some characters that would break the recursive function.
*
* @param xmlStr
* @returns {*}
*/
this.cleanXML = function (xmlStr) {
xmlStr = xmlStr.replace(/\n|\t|\r/g, ''); //replace special characters
xmlStr = xmlStr.replace(/ {1,}<|\t{1,}</g, '<'); //replace leading spaces and tabs
xmlStr = xmlStr.replace(/> {1,}|>\t{1,}/g, '>'); //replace trailing spaces and tabs
xmlStr = xmlStr.replace(/<\?[^>]*\?>/g, ''); //delete docType tags
xmlStr = _this.replaceSelfClosingTags(xmlStr); //replace self closing tags
xmlStr = _this.replaceAloneValues(xmlStr); //replace the alone tags values
xmlStr = _this.replaceAttributes(xmlStr); //replace attributes
return xmlStr;
};
/**
* Replaces all the self closing tags with attributes with another tag containing its attribute as a property.
* The function works if the tag contains multiple attributes.
* Example : '<tagName attrName="attrValue" />' becomes
* '<tagName><attrName>attrValue</attrName></tagName>'
*/
this.replaceSelfClosingTags = function (xmlStr) {
var selfClosingTags = xmlStr.match(/<[^/][^>]*\/>/g);
if (selfClosingTags) {
for (var i = 0; i < selfClosingTags.length; i++) {
var oldTag = selfClosingTags[i];
var tempTag = oldTag.substring(0, oldTag.length - 2);
tempTag += '>';
var tagName = oldTag.match(/[^<][\w+$]*/)[0];
var closingTag = '</' + tagName + '>';
var newTag = '<' + tagName + '>';
var attrs = tempTag.match(/(\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)["']?/g);
if (attrs) {
for (var j = 0; j < attrs.length; j++) {
var attr = attrs[j];
var attrName = attr.substring(0, attr.indexOf('='));
var attrValue = attr.substring(attr.indexOf('"') + 1, attr.lastIndexOf('"'));
newTag += '<' + attrName + '>' + attrValue + '</' + attrName + '>';
}
}
newTag += closingTag;
xmlStr = xmlStr.replace(oldTag, newTag);
}
}
return xmlStr;
};
/**
* Replaces all the tags with attributes and a value with a new tag.
* Example : '<tagName attrName="attrValue">tagValue</tagName>' becomes
* '<tagName><attrName>attrValue</attrName><_@attribute>tagValue</_@attribute></tagName>'
* @param xmlStr
* @returns {*}
*/
this.replaceAloneValues = function(xmlStr) {
var tagsWithAttributesAndValue = xmlStr.match(/<[^\/][^>][^<]+\s+.[^<]+[=][^<]+>{1}([^<]+)/g);
if (tagsWithAttributesAndValue) {
for (var i = 0; i < tagsWithAttributesAndValue.length; i++) {
var oldTag = tagsWithAttributesAndValue[i];
var oldTagName = oldTag.substring(0, oldTag.indexOf('>') + 1);
var oldTagValue = oldTag.substring(oldTag.indexOf('>') + 1);
var newTag = oldTagName + '<_@ttribute>' + oldTagValue + '</_@ttribute>';
xmlStr = xmlStr.replace(oldTag, newTag);
}
}
return xmlStr;
};
/**
* Replaces all the tags with attributes with another tag containing its attribute as a property.
* The function works if the tag contains multiple attributes.
*
* Example : '<tagName attrName="attrValue"></tagName>' becomes '<tagName><attrName>attrValue</attrName></tagName>'
*/
this.replaceAttributes = function(xmlStr) {
var tagsWithAttributes = xmlStr.match(/<[^\/][^>][^<]+\s+.[^<]+[=][^<]+>/g);
if (tagsWithAttributes) {
for (var i = 0; i < tagsWithAttributes.length; i++) {
var oldTag = tagsWithAttributes[i];
var tagName = oldTag.match(/[^<][\w+$]*/)[0];
var newTag = '<' + tagName + '>';
var attrs = oldTag.match(/(\S+)=["']?((?:.(?!["']?\s+(?:\S+)=|[>"']))+.)["']?/g);
if (attrs) {
for (var j = 0; j < attrs.length; j++) {
var attr = attrs[j];
var attrName = attr.substring(0, attr.indexOf('='));
var attrValue = attr.substring(attr.indexOf('"') + 1, attr.lastIndexOf('"'));
newTag += '<' + attrName + '>' + attrValue + '</' + attrName + '>';
}
}
xmlStr = xmlStr.replace(oldTag, newTag);
}
}
return xmlStr;
}
/**
* Recursive function that creates a JSON object with a given XML string.
*/
this.xml2json = function(xmlStr) {
xmlStr = this.cleanXML(xmlStr);
var obj = {},
tagName, indexClosingTag, inner_substring, tempVal, openingTag;
while (xmlStr.match(/<[^\/][^>]*>/)) {
openingTag = xmlStr.match(/<[^\/][^>]*>/)[0];
tagName = openingTag.substring(1, openingTag.length - 1);
indexClosingTag = xmlStr.indexOf(openingTag.replace('<', '</'));
// account for case where additional information in the openning tag
if (indexClosingTag == -1) {
tagName = openingTag.match(/[^<][\w+$]*/)[0];
indexClosingTag = xmlStr.indexOf('</' + tagName);
if (indexClosingTag == -1) {
indexClosingTag = xmlStr.indexOf('<\\/' + tagName);
}
}
inner_substring = xmlStr.substring(openingTag.length, indexClosingTag);
if (inner_substring.match(/<[^\/][^>]*>/)) {
tempVal = _this.xml2json(inner_substring);
}
else {
tempVal = inner_substring;
}
// account for array or obj //
if (obj[tagName] === undefined) {
obj[tagName] = tempVal;
}
else if (Array.isArray(obj[tagName])) {
obj[tagName].push(tempVal);
}
else {
obj[tagName] = [obj[tagName], tempVal];
}
xmlStr = xmlStr.substring(openingTag.length * 2 + 1 + inner_substring.length);
}
return obj;
}
});