dataschema.js revision 2390f77db0b974f19412b6ee655c3983bfcaa812
140N/A * Provides the base DataSchema implementation, which can be extended to 140N/A * create DataSchemas for specific data formats, such XML, JSON, Text and 140N/A * @submodule dataschema-base 140N/A * Base class for the YUI DataSchema utility. 140N/A * @class DataSchema.Base 140N/A * Overridable method returns data as-is. 140N/A * @param schema {Object} Schema to apply. 140N/A * @param data {Object} Data. 140N/A * @return {Object} Schema-parsed data. 140N/A * Applies field parser, if defined 140N/A * @param value {Object} Original value. 140N/A * @param field {Object} Field. 140N/A * @return {Object} Type-converted value. * Provides a DataSchema implementation which can be used to work with JSON data * @submodule dataschema-json * JSON subclass for the YUI DataSchema utility. * @extends DataSchema.Base ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// * Utility function converts JSON locator strings into walkable paths * @param locator {String} JSON value locator. * @return {String[]} Walkable path to data value. // Strip the ["string keys"] and [1] array indexes function (x,$1,$2) {keys[i]=$2;return '.@
'+(i++);}). function (x,$1) {keys[i]=parseInt($1,10)|0;return '.@
'+(i++);}). replace(/^\./,''); // remove leading dot // Validate against problematic characters. if (!/[^\w\.\$@]/.test(locator)) { path = locator.split('.
'); for (i=path.length-1; i >= 0; --i) { if (path[i].charAt(0) === '@
') { path[i] = keys[parseInt(path[i].substr(1),10)]; * Utility function to walk a path and return the value located there. * @param path {String[]} Locator path. * @param data {String} Data to traverse. * @return {Object} Data value at location. getLocationValue: function (path, data) { if(!LANG.isUndefined(data[path[i]])) { * Applies a given schema to given JSON data. * @param schema {Object} Schema to apply. * @param data {Object} JSON data. * @return {Object} Schema-parsed data. apply: function(schema, data) { data_out = {results:[],meta:{}}; // Convert incoming JSON strings if(!LANG.isObject(data)) { data_in = Y.JSON.parse(data); if(LANG.isObject(data_in) && schema) { if(!LANG.isUndefined(schema.resultListLocator)) { data_out = SchemaJSON._parseResults(schema, data_in, data_out); if(!LANG.isUndefined(schema.metaFields)) { data_out = SchemaJSON._parseMeta(schema.metaFields, data_in, data_out); data_out.error = new Error("JSON schema parse failure"); * Schema-parsed list of results from full data * @param schema {Object} Schema to parse against. * @param json_in {Object} JSON to parse. * @param data_out {Object} In-progress parsed data to update. * @return {Object} Parsed data object. _parseResults: function(schema, json_in, data_out) { if(schema.resultListLocator) { path = SchemaJSON.getPath(schema.resultListLocator); results = SchemaJSON.getLocationValue(path, json_in); if (results === undefined) { error = new Error("JSON results retrieval failure"); if(LANG.isArray(schema.resultFields) && LANG.isArray(results)) { data_out = SchemaJSON._getFieldValues(schema.resultFields, results, data_out); error = new Error("JSON Schema fields retrieval failure"); error = new Error("JSON Schema results locator failure"); * Get field data values out of list of full results * @method _getFieldValues * @param fields {Array} Fields to find. * @param array_in {Array} Results to parse. * @param data_out {Object} In-progress parsed data to update. * @return {Object} Parsed data object. _getFieldValues: function(fields, array_in, data_out) { field, key, path, parser, simplePaths = [], complexPaths = [], fieldParsers = [], // First collect hashes of simple paths, complex paths, and parsers field = fields[i]; // A field can be a simple string or a hash key = field.key || field; // Find the key // Validate and store locators for later path = SchemaJSON.getPath(key); simplePaths[simplePaths.length] = {key:key, path:path[0]}; complexPaths[complexPaths.length] = {key:key, path:path}; // Validate and store parsers for later //TODO: use Y.DataSchema.parse? parser = (LANG.isFunction(field.parser)) ? field.parser : Y.Parsers[field.parser+'']; fieldParsers[fieldParsers.length] = {key:key, parser:parser}; // Traverse list of array_in, creating records of simple fields, // complex fields, and applying parsers as necessary for (i=array_in.length-1; i>=0; --i) { // Cycle through simpleLocators for (j=simplePaths.length-1; j>=0; --j) { // Bug 1777850: The result might be an array instead of object record[simplePaths[j].key] = Y.DataSchema.Base.parse( (LANG.isUndefined(result[simplePaths[j].path]) ? result[j] : result[simplePaths[j].path]), simplePaths[j]); // Cycle through complexLocators for (j=complexPaths.length - 1; j>=0; --j) { record[complexPaths[j].key] = Y.DataSchema.Base.parse( (SchemaJSON.getLocationValue(complexPaths[j].path, result)), complexPaths[j] ); // Cycle through fieldParsers for (j=fieldParsers.length-1; j>=0; --j) { key = fieldParsers[j].key; record[key] = fieldParsers[j].parser(record[key]); if (LANG.isUndefined(record[key])) { data_out.results = results; * Parses results data according to schema * @param metaFields {Object} Metafields definitions. * @param json_in {Object} JSON to parse. * @param data_out {Object} In-progress parsed data to update. * @return {Object} Schema-parsed meta data. _parseMeta: function(metaFields, json_in, data_out) { if(LANG.isObject(metaFields)) { if (metaFields.hasOwnProperty(key)) { path = SchemaJSON.getPath(metaFields[key]); data_out.meta[key] = SchemaJSON.getLocationValue(path, json_in); data_out.error = new Error("JSON meta data retrieval failure"); * Provides a DataSchema implementation which can be used to work with XML data * @submodule dataschema-xml * XML subclass for the YUI DataSchema utility. * @extends DataSchema.Base ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// * Applies a given schema to given XML data. * @param schema {Object} Schema to apply. * @param data {XMLDoc} XML document. * @return {Object} Schema-parsed data. apply: function(schema, data) { data_out = {results:[],meta:{}}; if(xmldoc && xmldoc.nodeType && xmldoc.nodeType === 9 && schema) { data_out = SchemaXML._parseResults(schema, xmldoc, data_out); data_out = SchemaXML._parseMeta(schema.metaFields, xmldoc, data_out); data_out.error = new Error("XML schema parse failure"); * Get an XPath-specified value for a given field from an XML node or document. * @method _getLocationValue * @param field {String | Object} Field definition. * @param context {Object} XML node or document to search within. * @return {Object} Data value or null. _getLocationValue: function(field, context) { var locator = field.locator || field.key || field, xmldoc = context.ownerDocument || context, result, res, value = null; if(!LANG.isUndefined(xmldoc.evaluate)) { result = xmldoc.evaluate(locator, context, xmldoc.createNSResolver(!context.ownerDocument ? context.documentElement : context.ownerDocument.documentElement), 0, null); while(res = result.iterateNext()) { xmldoc.setProperty("SelectionLanguage", "XPath"); result = context.selectNodes(locator)[0]; value = result.value || result.text || null; return Y.DataSchema.Base.parse(value, field); * Parses results data according to schema * @param xmldoc_in {Object} XML document parse. * @param data_out {Object} In-progress schema-parsed data to update. * @return {Object} Schema-parsed data. _parseMeta: function(metaFields, xmldoc_in, data_out) { if(LANG.isObject(metaFields)) { xmldoc = xmldoc_in.ownerDocument || xmldoc_in; if (metaFields.hasOwnProperty(key)) { data_out.meta[key] = SchemaXML._getLocationValue(metaFields[key], xmldoc); * Schema-parsed list of results from full data * @param schema {Object} Schema to parse against. * @param xmldoc_in {Object} XML document parse. * @param data_out {Object} In-progress schema-parsed data to update. * @return {Object} Schema-parsed data. _parseResults: function(schema, xmldoc_in, data_out) { if(schema.resultListLocator && LANG.isArray(schema.resultFields)) { var nodeList = xmldoc_in.getElementsByTagName(schema.resultListLocator), fields = schema.resultFields, node, field, result, i, j; // Loop through each result node for(i=nodeList.length-1; i>= 0; i--) { for(j=fields.length-1; j>= 0; j--) { result[field.key || field] = SchemaXML._getLocationValue(field, node); data_out.results = results; data_out.error = new Error("XML schema result nodes retrieval failure"); * The DataSchema utility provides a common configurable interface for widgets to * apply a given schema to a variety of data. * Provides a DataSchema implementation which can be used to work with data stored in arrays * @submodule dataschema-array * Array subclass for the YUI DataSchema utility. * @class DataSchema.Array * @extends DataSchema.Base ///////////////////////////////////////////////////////////////////////////// // DataSchema.Array static methods ///////////////////////////////////////////////////////////////////////////// * Applies a given schema to given Array data. * @param schema {Object} Schema to apply. * @param data {Object} Array data. * @return {Object} Schema-parsed data. apply: function(schema, data) { data_out = {results:[],meta:{}}; if(LANG.isArray(data_in)) { if(LANG.isArray(schema.resultFields)) { data_out = SchemaArray._parseResults(schema.resultFields, data_in, data_out); data_out.results = data_in; data_out.error = new Error("Array schema parse failure"); * Schema-parsed list of results from full data * @param fields {Array} Schema to parse against. * @param array_in {Array} Array to parse. * @param data_out {Object} In-progress parsed data to update. * @return {Object} Parsed data object. _parseResults: function(fields, array_in, data_out) { result, item, type, field, key, value, i, j; for(i=array_in.length-1; i>-1; i--) { type = (LANG.isObject(item) && !LANG.isFunction(item)) ? 2 : (LANG.isArray(item)) ? 1 : (LANG.isString(item)) ? 0 : -1; for(j=fields.length-1; j>-1; j--) { key = (!LANG.isUndefined(field.key)) ? field.key : field; value = (!LANG.isUndefined(item[key])) ? item[key] : item[j]; result[key] = Y.DataSchema.Base.parse(value, field); data_out.results = results; Y.DataSchema.Array = Y.mix(SchemaArray, Y.DataSchema.Base); * Provides a DataSchema implementation which can be used to work with Text data * @submodule dataschema-text * Text subclass for the YUI DataSchema utility. * @extends DataSchema.Base ///////////////////////////////////////////////////////////////////////////// // DataSchema.Text static methods ///////////////////////////////////////////////////////////////////////////// * Applies a given schema to given delimited text data. * @param schema {Object} Schema to apply. * @param data {Object} Text data. * @return {Object} Schema-parsed data. apply: function(schema, data) { data_out = {results:[],meta:{}}; if(LANG.isString(data_in) && LANG.isString(schema.resultDelimiter)) { data_out = SchemaText._parseResults(schema, data_in, data_out); data_out.error = new Error("Text schema parse failure"); * Schema-parsed list of results from full data * @param schema {Array} Schema to parse against. * @param text_in {String} Text to parse. * @param data_out {Object} In-progress parsed data to update. * @return {Object} Parsed data object. _parseResults: function(schema, text_in, data_out) { var resultDelim = schema.resultDelimiter, results_in, fields_in, result, item, fields, field, key, value, i, j, // Delete final delimiter at end of string if there tmpLength = text_in.length-resultDelim.length; if(text_in.substr(tmpLength) == resultDelim) { text_in = text_in.substr(0, tmpLength); results_in = text_in.split(schema.resultDelimiter); for(i=results_in.length-1; i>-1; i--) { if(LANG.isString(schema.fieldDelimiter)) { fields_in = item.split(schema.fieldDelimiter); if(LANG.isArray(schema.resultFields)) { fields = schema.resultFields; for(j=fields.length-1; j>-1; j--) { key = (!LANG.isUndefined(field.key)) ? field.key : field; value = (!LANG.isUndefined(fields_in[key])) ? fields_in[key] : fields_in[j]; result[key] = Y.DataSchema.Base.parse(value, field); data_out.results = results; Y.DataSchema.Text = Y.mix(SchemaText, Y.DataSchema.Base);