<@doc alias="persist" hierarchy="GMLDOM"> A helper object that deals with conversion of Units and GMLObjects to and from XML format. (c) SAP AG 2003-2006. All rights reserved. Class ModelSerializer inherit core.gml:Object virtual property model = ^core.gml:Model; virtual property unusedUnits = ^core.gml:Unit[id]; constructor(model) this.model = model; end method deserializeJSUnit(gml , id) if(!gml || !id ) return null; var unit = null; try{ var _CLASS = CLASS; //For performance reaseons only. // Remove the CDATA tag from the string //var startT = NOW(); var startStr = gml.indexOf("\<\!\[CDATA\["); var endStr = gml.lastIndexOf("\]\]\>"); gml = gml.substring(startStr+9 , endStr); //WRITE( "UNIT phase 1 " + id +" took " + DSUB(NOW(), startT, 'z')); //startT = NOW(); eval(gml); eval('unit=$_'+id); //WRITE( "UNIT phase 2 " + id +" took " + DSUB(NOW(), startT, 'z')); }catch(e){ #LOG[4,"Error while evaluting Unit: " +id +", Error Description: "+ e.description ] } return unit; end <@doc scope="private"> Deserializes GML representation into the corresponding unit object. The GML representation of the unit The parsed unit object method deserializeUnit(gml) try { // build aspect prefixes map var model=this.model, unit=null, aspectsMap={}, derefList=[], onloadList=[]; for (var i=0, A=gml.attributes, B=$ENV.kitsManifest.aspects, len=A.length, flag=false; i 0) { var m=aspectsMap[n.substring(0,j)]; if (!m) throw new Error(-1, 'Unknown aspect property "'+n+'"'); n = m + '$' + n.substring(j+1); } } var v=A[i].text, p=P[n]; if (!p || p.isStatic || p.isVirtual) throw new Error(-1, '#TEXT[XMSG_INVALID_PROPERTY]' + ' "'+n+'" ' + 'for class'+ ' "'+N+'"'); // convert property values to their native data types // pointers are not converted at this stage // Added the Dynamic Expressions handling the '=' character - mhoter July05 if(v.charAt(0) == '=') { // Treat it as a dynamic expressions (a string that begins with '=') V[n] = UNESCAPEXML(v); } else { switch (p.type.charAt(0)) { case 'b': V[n] = BOOL(v); break; case 'n': V[n] = FLOAT(v); break; case 's': V[n] = UNESCAPEXML(v); break; case 'p': // fall-through case 'v': // fall-through case 'c': // fall-through default: if (!v) break; V[n] = v; derefList.push({name:n, value:v, def:p}); break; } } } // create new object and hook it to parent and unit, as needed var obj = new C(V); //this is where an object is created from the class, and V is the collection of all read attributes for (var i=derefIndex; i < derefList.length; i++) derefList[i].obj = obj; if (!parent) { unit = obj; obj.model = model; } else { obj.unit = unit; obj.parent = parent; if(!parent.children) parent.children={}; //orig code parent.children[obj.id] = obj; parent.assignChild(obj, agg_name); unit.all_elements[obj.id] = obj; //patch - for deref ?? } if (typeof obj.onLoad == 'function') onloadList.push(obj); // recursively parse the child nodes, if any if (!node.hasChildNodes()) return; var chlist = node.childNodes, ch; while (ch = chlist.nextNode()) { var prop = ch.baseName; if(!P[prop]) { var msg = '#TEXT[XMSG_INVALID_PROPERTY]' + ' "'+prop+'" ' + 'for class'+ ' "'+C.name+'"'; #LOG[4, msg]; throw new Error(-1, msg ); } //each node is a "strong" property. verify that. if (!P[prop].isStrong) { var msg1='#TEXT[XMSG_ERROR_LOADING_MODEL]'.replace('{0}', prop); #LOG[4, msg1]; continue; } if (ch.hasChildNodes()) { //property has content var chlist2 = ch.childNodes; var ch2; while (ch2 = chlist2.nextNode()) { parseBranch(ch2, obj, prop); } } else { obj[prop] = null; } } } } catch (e) { var unitId = gml && gml.firstChild && gml.firstChild.getAttribute('id') || null; var msg='#TEXT[XMSG_MODEL_SERIALIZER]' + ' ' + e.description; if(unitId) msg += ' in unit ' + unitId ; #LOG[4, msg ]; return null; } end /*<@doc scope="private"> Serializes a unit object into GML representation The unit to serialize Indicates whether to return the results as an XML object or as a string The GML representation of the unit object */ method serializeUnitOld(unitobj, asXML) var buf=[], NS={}; var model = this.model; // print unit tag unitobj.modified = DSTR(new Date(), 'DD/MM/YYYY'); unitobj.version = '1.0'; if (#SYS[SUPPORT_TRANSLATION] && ISA(unitobj, 'core.gml:Scenario')) { // Validating that the Text objects do not have a reference to non existing elements. // This is a part of a greater unit validation process: this.validateTextRef(unitobj); } printObj(unitobj); // build kit namespaces map var nslist=[], nsmap=$ENV.kitsManifest.prefixes; var NSarr = []; for( var k in NS ){ NSarr.push(k); } NSarr = NSarr.sort(collate); function collate(a,b) { return (ab ? 1 : 0)); } var NSarrLen = NSarr.length; for (var i=0 ; i < NSarrLen; i++) { var name = NSarr[i]; if (!name) { var msg = 'Invalid package prefix for package: ' + nsmap[name]; #LOG[4, msg]; throw new Error(-1, msg); } nslist.push('xmlns:'+name+'="'+nsmap[name]+'"'); } /* for (var k in NS) { if (null == k) { var msg = '#TEXT[XMSG_INVALID_PACKAGE_PREFIX]: ' + nsmap[k]; #LOG[4, msg]; throw new Error(-1, msg); } nslist.push('xmlns:'+k+'="'+nsmap[k]+'"'); } */ // print the outer GML tag buf.unshift(''); buf.push(''); // return the results if (asXML === false) return JOIN(buf); var gml = PARSEXML(JOIN(buf)); var err = CHECKXML(gml); if (err) { var msg = '#TEXT[XMSG_ERROR_SERIALIZING_UNIT]' + ': '+unitobj.id +' '+ err ; #LOG[4, msg]; throw new Error(-1,msg); } return gml; // recursively print a composite GmlObject into a corresponding GML branch function printObj(obj) { var C=obj.Class, P=C.persistent, tag=[], tagName=C.prefix+':'+C.name; NS[C.prefix] = true; tag.push(tagName); for (var k in P) { var p=P[k], v=obj[k]; if (p.isStatic || p.isVirtual || p.isStrong) continue; if (!obj.hasOwnProperty(k) || v === null || v === undefined) continue; // If the current element value (v) type is 'string' and different than the expected value type of the // persistent element(p) - by different I mean bool or number only, it means that the request // is for persisting a dynamic expression as the value. // Thus, treat the persistent type as a string (and so prepare it for XML): - mhoter July05 if(typeof v == 'string') { if(('boolean' == p.type) || ('number' == p.type)) p.type = typeof v; } switch (p.type.charAt(0)) { case 'p': if ((typeof v == 'string')) { if (!model.isFullId(v)) { var msg1='#TEXT[XMSG_POINTER]'; var msg2='value'; var msg3='is a string that does not represent an element in object'; #LOG[4, msg1+' ' + k + '(' + msg2 + ' ' + v + ') ' + msg3 +' "'+obj+'"']; continue; } break; } if (!ISA(v, 'core.gml:Element')) { var msg1 = '#TEXT[XMSG_INVALID_POINTER]'; var msg2 = 'in object'; #LOG[4, msg1 +' "'+k+'" '+ msg2 +' "'+obj+'"']; continue; } if(!v.unit) { var msg = 'In element ' + v.id + ' type '+ (v.Class && v.Class.name) +' #TEXT[XMSG_UNIT_PROPERTY_NULL]' ; #LOG[4, msg]; } if (v.unit.id != unitobj.id) { //pointer to element in other unit - serialize full ID v = model.getFullId(v); } else { //pointer to element in same unit - serialize ID v = v.id; } break; case 'v': var V=[]; for (var i=0, len=v.length; i 0) NS[k.substring(0,j)]=true, k=k.replace('$',':'); tag.push(k+'="'+v+'"'); } buf.push('<'+JOIN(tag,' ')+'>'); //loop on all strong properties var Props = P=C.properties; for (var k in Props) { var p=Props[k], v=obj[k]; if (!p.isStrong) continue; if (!obj.hasOwnProperty(k) || v === null || v === undefined) continue; var V=[]; //collect elements aggregated by this strong property switch (p.type.charAt(0)) { case 'p': if (!ISA(v, 'core.gml:Element')) { var msg1='#TEXT[XMSG_INVALID_STRONG_POINTER]'; var msg2='in object'; #LOG[4, msg1+' "'+k+'" '+msg2+' "'+obj+'"']; continue; } V.push(v); break; case 'v': for (var i=0, len=v.length; i 0) { buf.push('<' + k + '>'); for (var i=0, len=V.length; i'); } } buf.push(''); } end // Validating that the Text objects do not have a reference to non existing elements. // This is a part of a greater unit validation process (mickey hoter May06) method validateTextRef(unit) if(unit.translationTable) { // Go over the translation table and remove non valid Text items (have bad references): for(var text in unit.translationTable.items) { var ref = unit.translationTable.items[text].objID; if(ref == unit.id) { // This means a translation of property that belongs to the unit itself! // For example a translatable property 'title' on a scenario. continue; } var refElement = unit.getElement(ref,true); if(refElement) { // This one is valid: continue; } // Remove - contains non valid reference: delete unit.translationTable.items[text]; } } end <@doc scope="private"> Serializes a unit object into GML representation The unit to serialize Indicates whether to return the results as an XML object or as a string The GML representation of the unit object method serializeUnit(unitobj, asXML) var self = this; var buf=[], NS={}; var model = this.model; // for perfomance reasons hold a pointer to the methods: var isElementDeleted = model.isElementDeleted; var escapeXml = ESCAPEXML ; var errorsList = []; // this.unusedUnits = model.organizer.getUnusedUnits(); // print unit tag unitobj.modified = DSTR(new Date(), 'DD/MM/YYYY'); unitobj.version = '1.0'; serializeGSObj(unitobj); //if (!ISEMPTY( errorsList)) { // features = {msg:"Errors while validating Unit " + unitobj.id + " press OK for fixing press Cancel to save anyway." , buttons:'OK Cancel', moreinfo:'', showmore:true, errors:errorsList }; // var result = AMODAL('#URL[core.dev:common.ErrorsDlg.htm]' , features,true); // //} // build kit namespaces map var nslist=[], nsmap=$ENV.kitsManifest.prefixes; var NSarr = []; for( var k in NS ){ NSarr.push(k); } NSarr = NSarr.sort(collate); function collate(a,b) { return (ab ? 1 : 0)); } //var NSarrLen = NSarr.length; for (var i=0 ,len = NSarr.length; i < len; i++) { var name = NSarr[i]; if (!name) { var msg = 'Invalid package prefix for package: ' + nsmap[name]; #LOG[4, msg]; throw new Error(-1, msg); } nslist.push('xmlns:'+name+'="'+nsmap[name]+'"'); } /* for (var k in NS) { if (null == k) { var msg = 'Invalid package prefix for package: ' + nsmap[k]; #LOG[4, msg]; throw new Error(-1, msg); } nslist.push('xmlns:'+k+'="'+nsmap[k]+'"'); } */ // print the outer GML tag buf.unshift(''); buf.push(''); // return the results if (asXML === false) return JOIN(buf); var gml = PARSEXML(JOIN(buf)); var err = CHECKXML(gml); if (err) throw new Error(-1, err); return gml; // recursively serialize a gml object function serializeGSObj(obj) { var C=obj.Class, P=C.persistent; var anchor=buf.length, attrs={}, tagName=C.prefix+':'+C.name; // Only valided Elements if( unitobj!== obj){ RULE('validateElement',unitobj, obj,errorsList); if( isElementDeleted.call(model,obj)){ return; } } buf.push('<'+tagName); NS[C.prefix] = true; // loop over all persistent properties and serialize each in turn for (var k in P) { var p=P[k], v=obj[k]; if (p.isStatic || p.isVirtual) continue; if (!obj.hasOwnProperty(k) || v === null || v === undefined ) continue; switch (p.type.charAt(0)) { case 's': // string if (v === p.value && !p.isOverride) continue; attrs[k] = escapeXml(v); break; case 'b': // boolean case 'n': // number if (v === p.value && !p.isOverride) continue; // In case the propery is dynamic experssion if( typeof v == 'string' ){ attrs[k] = escapeXml(v); }else { attrs[k] = v+''; } break; case 'o': // object case 'a': // array if (v === p.value && !p.isOverride) continue; attrs[k] = escapeXml(v); break; case 'p': // pointer // if pointer is null, Do nothing. if(!v) break; // A pointer to an element in another unit which has not been loaded yet. if( typeof v == 'string' && model.isFullId(v) ){ attrs[k] = v; break; } // The element is loaded ( in memory.) if (!ISA(v, model.elementClassifier)) { #LOG[4, 'Invalid pointer "'+k+'" in object "'+obj+'"']; } else if (v.unit != unitobj) { // Check the element is valid. // If element has been deleted then don't serialize it. if( !isElementDeleted.call(model,v)){ var unitId = v.unit.id || v.unit; attrs[k] = unitId+"."+v.id ; } }else if (p.isStrong) { buf.push('<'+k+'>'); serializeGSObj(v); buf.push(''); }else { // If element has been deleted then don't serialize it. if( !isElementDeleted.call(model, v )){ attrs[k] = v.id; } } break; case 'v': // vector var V=[]; for (var i=0, len=v.length; i'); for (var i=0, len=V.length; i'); } else { attrs[k] = JOIN(V,' '); } break; case 'c': // collection var V=[]; for (var k2 in v) { if (!ISA(v[k2], model.elementClassifier) || v[k2].unit != unitobj || isElementDeleted.call(model,v[k2]) ) { #LOG[4, 'Invalid collection pointer "'+k+':'+k2+'" in object "'+obj+'"']; } else { V.push(p.isStrong ? v[k2] : v[k2].id); } } if (V.length == 0) break; if (p.isStrong) { buf.push('<'+k+'>'); for (var i=0, len=V.length; i'); } else { attrs[k] = JOIN(V,' '); } break; } } for (var k in attrs) { var j=k.indexOf('$'), n=k; if (j > 0) NS[k.substring(0,j)]=true, n=k.replace('$',':'); buf[anchor] += ' '+n+'="'+attrs[k]+'"'; } buf[anchor] += '>'; buf.push(''); } end