BpcSMScriptLibrary 2

From RiskWiki
Revision as of 03:38, 12 September 2019 by Bishopj (talk | contribs) (Created page with "=bpcXML Language Version 1= Language: Delphi 7 - 2007 ==Interpreter Routines== <pre> uses Classes, DB, XMLIntf, XMLDoc, DBGrids, Grids, bpcDBBookMarkList; // These routi...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

bpcXML Language Version 1

Language: Delphi 7 - 2007


Interpreter Routines

uses Classes, DB, XMLIntf, XMLDoc, DBGrids, Grids, bpcDBBookMarkList;

// These routines support the bpcXML Language Version 1 (bpcXML-1)  which is a
// distributed database update language.  The routines herein assemble and dissassemble
// bpcXML-1 language elements.

// Refer to the language definition comment at the end of the implementation section

Type
   TbpcXMLFType=(xrsfVAR, xrsfSTR, xrsfQSTR);
   TbpcValidfunc = function ( sOID, sPID : string ) : string of object;
   TbpcsmDSMapperfunc = function ( const sDataSetName : string ) : string of object;

// This class used for holding dataset.locate routine indexes. The locate routine
// expects a field list of the form 'field1;field2;field3' and a variant array of
// corresponding values.  This class provides a place to store both the field list
// and the variant array (as well as the original index string.
   TbpcLocateIndexList= class (TObject )
   private
     myIndexes : string;
   protected
     function GetLocators : string;
     procedure SetLocators( const destindexby : string);
     function GetSQLCondition : string;
     procedure SetSQLCondition( const sqlstr : string);
   public
     findexlist : TStringList;
     locarray : variant;
     count : integer;
     // Consructs an index by translating the desindexby string of the form 'field1;field2;field3'
     // into a stringlist of the field names, and a variant array of the same length
     constructor create( const destindexby : string ) ;
     destructor destroy; override;
     // Clear the index list
     procedure Clear;
     // Sets each value in the vararray to 'unassigned' and, if count=0, the array itself
     procedure ClearVarArray;
     // Set or Read the index list as a string
     property AsString : string read GetLocators write SetLocators;
     // Set or Read the index list as an SQL conditional 'and' expression of the form
     // "( field1=value1 ) and ( field2='text value2' )"  where fields are in findex and the
     // values are in the vararray. Works with a TbpcXMLFType of xrsfQSTR
     property AsSQLCondition : string read GetSQLCondition write SetSQLCondition;
   end;

// Returns a XML block START tag with attributes
function smXMLStartTag( sTag, sAttributes : string ) : string;
// Returns a XML block END tag
function smXMLEndTag( sTag : string ) : string;
// Returns a XML block tagged object
function smXMLDualTag( sTag, sContains : string ) : string;
// Returns a bpcXML-1 XML 'Authority' packet
function smXMLAuthorityPacket( sOID, sPID : string; sUpMap : string='' ) : string; overload;
function smXMLAuthorityPacket( sOID, sPID : string; sUpOrgMap, sUpSIDMap: string ) : string; overload;
// Returns a bpcXML-1 XML 'Action' packet
function smXMLActionPacket( sAction: string; source : string= ''; dest : string = ''  ) : string;
// Returns a bpcXML-1 XML 'Message' packet
function smXMLMessagePacket( sMessage : string ) : string;
// Returns a bpcXML-1 XML 'Data' packet
function smXMLDataPacket( sMessages : string ) : string;
// Returns one or more bpcXML-1 XML 'Message' packets depending on bAsSingleMessage
// If bAsSingleMessage then a datasource referenced more than once in the action list
// will appear ONLY ONCE in the message, otherwise each message gets its own copy of the
// data source.

function smXMLMessagesFromActionsPacket( sActions : TStringList; bAsSingleMessage : boolean=False; FieldRefList : TbpcLocateIndexList=nil; BookMarks : TBookmarklist=nil; bpcBookMarks : TbpcBookmarkList=nil; FieldMapList : string=''; SubFieldMapList : string='' ) : string;
// Returns a bpcXML-1 XML 'smXMLPacket' block packet containing sContains
function smXMLPacket( sContains : string ) : string;
// Returns a bpcXML-1 XML 'smXMLPacket' block packet with an authorisation request
// for organisation sOID and person sPID, and list of actions and their datasets in
// a stringlist sActions.  The datasets are held on the object pointer of the string entry
// Each action string should contain all the desired attributes of the action
// except the datasource, which will be taken from the dataset object.
// Refer to the language definition comment at the end of the implementation section
// Exanple call:
//   XMLPacketList.AddObject('update indexby="OrgID;SID"', WebSurvMaintDM.ADOTable1);
//   XMLPacket:=smXMLPacketCreate( trim(OIDEdit.Text), trim(PIDEdit.Text), XMLPacketList);
function smXMLPacketCreate( sOID, sPID : string; sActions : TStringList; BookMarks : TBookmarklist=nil; bpcBookMarks : TbpcBookmarkList=nil; sUpMap : string='' ) : string; overload;
function smXMLPacketCreate( sOID, sPID : string; sActions : TStringList; BookMarks : TBookmarklist; bpcBookMarks : TbpcBookmarkList; sUpMap, sMapSID : string ) : string; overload;
// As above but also does full field substitution and partial field substitution to allow effective copying of a group of tables from one group of keys to another.
// The routine allows for full field and part field string replacement.  Usually used on key fields to enable storing of a set of tables in a key independent manner, and subsequent
// pasting into a table with new keys/strings for the mapped ones.
// Example field map lists are of the form:
//    sMapArgs := 'OrgID=@@OID$OID@@,SID=@@SID$SID@@,ssqOrgID=@@OID$OID@@';
//    sMapPartArgs := 'QID=ACFE1999:@@SID$SID@@,ssqQID=ACFE1999:@@SID$SID@@ ;
//  In sMapPatArgs the QID field content will have the first sub-string matching 'ACFE1999' replaced with @@SUD$SID@@, commas seperate the fields, while the ':' seperates the target
//  substring from its replacement.
//  The entire matching field name will be replaced in sMapArgs.
//  Generally the sUpMap will be the same as the OrgID in sMapArgs, and the sMapSID will be the same as the SID - @@OID$OID@@ and @@SID$SID@@ in the above example
//  These strings can then be replaced for the real orgid and sid in a subsequent string replacement operation before being sent to the database.
//  While the examples are about OrgID and SID, any fields can be mapped, and if OID and SID are not involved in the maps then the real OID and SID should be used.
function smXMLPacketCreate2( sOID, sPID : string; sActions : TStringList; BookMarks : TBookmarklist; bpcBookMarks : TbpcBookmarkList; sUpMap, sMapSID, sMapArgs, sMapPartArgs : string ) : string;
// As above, but asumes the contents of the data segment has been built
function smXMLPacketCreate( sOID, sPID : string; sDataContent : string; sUpMap : string='' ) : string; overload;

// Get the data portion of the smXMLpacket, or if no data tags return ''.
// Essentially unwraps the data block from the smXMLpacket - seeks, so a burried data block will confuse the routine.
// Allows:
// smxmlpacket.authority.data../data./smxmlpacket
// smxmlpacket.data../data./smxmlpacket
// data...data
// anyother arbitrary content.
function smXMLPacketDataExtract( smXMLPacketOrDataPacket : string; NoHTMLDecode : boolean=false ) : string;

// Join two bpcXML-1 XML 'smXMLPacket's together at the data tag level, treating the smXMLAuthorityMaster as the first (containing the authority node,
// and the smXMLChild as the second. I.e the Data packet from the second is added to the end of the data packet of the first.
function smXMLPacketAdd( smXMLAuthorityMaster, smXMLChild : string ) : string;

// Returns an bpcXML-1 XML envelope with sXML as the content. sDocTypeName is any legal
// string used to identify the document.
function bpcXMLWrapinEnvelope( sDocTypeName : string; sXML : string ) : string;
// Builds & returns a bpcXML-1 data packet representing the current row in a dataset
// tagged with block tags '<SdtsName >xxx</SdtsName >'
function bpcXMLDataSetRecordToXML( SdtsName : string; SourceDts : TDataSet; FieldRefList : TbpcLocateIndexList=nil; FieldMapList : TStringList=nil; SubFieldMapList : TStringList=nil ) : string;
// Builds & returns a bpcXML-1 data packet representing all rows (if not singleonly)
// or just the current row (if singleonly is true) in a dataset
// The entire packet will be tagged with SdtsGroup, and each record set (row) will be
// wrapped in tags named SdtsName.
function bpcXMLDataSetToXML( SdtsGroup, SdtsName : string; SourceDts : TDataSet; singleonly : boolean; FieldRefList : TbpcLocateIndexList=nil; BookMarks : TBookmarklist=nil; bpcBookMarks : TbpcBookmarkList=nil; FieldMapList : string=''; SubFieldMapList : string='' ) : string;  overload;
// Builds & returns a bpcXML-1 data packet representing all rows (if not singleonly)
// or just the current row (if singleonly is true) in a dataset
// The entire packet will be tagged with SdtsGroup, and each record set (row) will be
// wrapped in tags named SdtsName. The result is stored in myXMLStream which is created if nil and
// which is always returned as the result.
function bpcXMLDataSetToXML( myXMLStream : TStringStream; SdtsGroup, SdtsName : string; SourceDts : TDataSet; singleonly : boolean; FieldRefList : TbpcLocateIndexList; BookMarks : TBookmarklist; bpcBookMarks : TbpcBookmarkList; FieldMapList : string=''; SubFieldMapList : string='' ) : TStringStream; overload;
// Designed for speed on large data, this Builds & returns a bpcXML-1 data packet representing all rows (if not singleonly)
// or just the current row (if singleonly is true) in a dataset
// The entire packet will be tagged with Prefix + SdtsGroup + PostFix, and each record set (row) will be
// wrapped in tags named SdtsName. The result is stored in myXMLStream which is created if nil and
// which is always returned as the result. Prefix and PostFix allows the often smaller leadin and leadout strings to be assembled
// before the stream is filled, and particularly in the case of Prefix, will save an entire copy of the string.
function bpcXMLDataSetToXML( myXMLStream : TStringStream; Prefix, PostFix, SdtsGroup, SdtsName : string; SourceDts : TDataSet; singleonly : boolean; FieldRefList : TbpcLocateIndexList; BookMarks : TBookmarklist; bpcBookMarks : TbpcBookmarkList; FieldMapList : string=''; SubFieldMapList : string='' ) : TStringStream; overload;
// Builds & returns a bpcXML-1 data packet representing bookmarked rows, or if nil, all rows (if not singleonly)
// or just the current row (if singleonly is true) in a dataset
// The entire packet will be tagged with StoreID, and each record set (row) will be
// wrapped in tags named 'rowset'.
function bpcXMLCopyDbToXML( StoreID : string; SourceDts : TDataSet; singleonly : boolean; myBookMarks : TBookMarkList; FieldRefList : TbpcLocateIndexList=nil; bpcBookMarks : TbpcBookmarkList=nil  ) : string;
// Paste the rowset contents of the XMLPacket into the DestDts dataset (either all, or just the first record). Filter the contents by the fields in the reflist
// of the form "field1;field2;field3" and/or excluding those in the exclist. If the RefList is nil or '' then all fields (but for those in the exclist) are pasted
function bpcXMLPasteXmlToDb( XMLPacket : string; DestDts : TDataSet; singleonly : boolean; myBookMarks : TBookMarkList; sFieldRefList : string=''; sFieldExcList : string=''; bpcBookMarks : TbpcBookmarkList=nil  ) : boolean;
// Return an XML clause from the currow of a stringgrid
function bpcXMLSGRecordToXML( SdtsName : string; SourceSG : TStringGrid; CurRow : integer; FieldRefList : TbpcLocateIndexList=nil ) : string;
// Builds & returns a bpcXML-1 data packet representing all rows (if not singleonly)
// or just the current row (if singleonly is true) in a stringgrid
// The entire packet will be tagged with SdtsGroup, and each record set (row) will be
// wrapped in tags named SdtsName.
function bpcXMLSGToXML( SdtsGroup, SdtsName : string; SourceSG : TStringGrid; singleonly : boolean; FieldRefList : TbpcLocateIndexList=nil; BookMarks : TBookmarklist=nil; bpcBookMarks : TbpcBookmarkList=nil ) : string;
// Builds & returns a bpcXML-1 data packet representing bookmarked rows, or if nil, all rows (if not singleonly)
// or just the current row (if singleonly is true) in a stringgrid
// The entire packet will be tagged with StoreID, and each record set (row) will be
// wrapped in tags named 'rowset'.
function bpcXMLCopySGToXML( StoreID : string; SourceSG : TStringGrid; singleonly : boolean; myBookMarks : TBookMarkList; FieldRefList : TbpcLocateIndexList=nil; bpcBookMarks : TbpcBookmarkList=nil  ) : string;
function bpcXMLPasteXmlToSG( XMLPacket : string; DestSG : TStringGrid; currow : integer; singleonly : boolean; myBookMarks : TBookMarkList; sFieldRefList, sFieldExcList : string; bpcBookMarks : TbpcBookmarkList  ) : boolean;
// Returns a string with any character &, <, >, ', " or greater than 127
// replaced with '&xxx;' versions or space if >127.
// Suitable for encoding general strings into into 7 bit XML ascii for XML engines
function bpcXMLEscape( unescapedstring : string ) : string;
// Mainly meant for bpcXMLExecute - returns true if the required right is a substring of srightslist, or srightslist is '*'
// sRequiredRight and sRightsList can be any legal string.
// Notionally it verifies that a 'right' is held in the 'rightslist', or the rightlist allows all rights (ie. '*').
function bpcValidateSMAccessRights( sRequiredRight : string; sRightsList : string ) : boolean;
// Execute a string containing a bpcXML-1 smxmlpacket (in XMLPacket) using the XML Engine contained in XMLDocument1
// Return the result of executing the packet - usually an html response.
// The role of the myDataSetCollection is critical as it contains tdataset objects with names
// corresponding to the datasources referenced in the action items.  Examples of such objects
// are TDataModule, or TWebModule - or any other component that can "own" dataset components
function bpcXMLExecute( const XMLPacket : string; var XMLDocument1: TXMLDocument; fValidateSMAccess : TbpcValidfunc; myDataSetCollection : TComponent; bXMLOut : boolean; sUploadMap : string=''; fMapDataSetName: TbpcsmDSMapperfunc=nil ) : string; overload;
function bpcXMLExecute( const XMLPacket : string; var XMLDocument1: TXMLDocument;  fValidateSMAccess, fGetSMAccessRights: TbpcValidfunc; myDataSetCollection : TComponent; bXMLOut : boolean; sUploadMap : string; fMapDataSetName: TbpcsmDSMapperfunc ) : string; overload;
// Performs a tdataset.locate operation on SourceDataSet using destindexby as the locate key fields and
// drawing the vararray for the look-up values from the locindexlist, which will be built if locindexlist is
// not assigned, and rebuilt if the destindexby<>locindexlist  otherwise it is reused.
function bpcXMLLocate( SourceRowNode : IXMLNode; destindexby : string; var SourceDataSet : TDataSet; var locindexlist : TbpcLocateIndexList; sUploadMap : string{=''} ) : boolean;
// Attempts to put the SourceDataSet into an updatable state (Insert or Edit) and
// Returns the ds state achieved (dsInsert, dsEdit, dsInactive) based on:
// -No destindexby -> Insert
// -Else bpcXMLLocate can locate a row in sourcedataset that matches the index fields of SourceRowNode -> Edit
// -Else bpcXMLLocate can't locate -> Insert
// -Failed -> dsInactive
// The current row of the sourcedataset will be moved to the target if dsEdit, else the first row.
function bpcXMLEditOnLocate( SourceRowNode : IXMLNode; destindexby : string; var SourceDataSet : TDataSet; var locindexlist : TbpcLocateIndexList; sUploadMap : string{=''} ) : TDataSetState;
// Attempts to delete from the SourceDataSet and
// Returns the ds state achieved (dsInsert, dsEdit, dsInactive) based on:
// -No destindexby -> NoChange
// -Else bpcXMLLocate can locate a row in sourcedataset that matches the index fields of SourceRowNode -> dsBrowse
// -Failed -> dsBrowse
// The current row of the sourcedataset will be moved to the row after the target, else the first row.
function bpcXMLDeleteOnLocate( SourceRowNode : IXMLNode; destindexby : string; var SourceDataSet : TDataSet; var locindexlist : TbpcLocateIndexList; sUploadMap : string{=''} ) : TDataSetState;
// Scan a rowset for the field names and return them in FieldList, making the obect as a stringlist if not provided.
function bpcXMLRowSetToFieldList( SourceRowNode : IXMLNode; FieldList : TStrings=nil ) : TStrings;
// Copies a  bpcXML-1 rowset node into the current TDataSet rowset. Returns false on error, else true.
// Filter the contents by the fields in the reflist of the form "field1;field2;field3" and/or excluding those in the exclist.
// If the RefList is nil or '' then all fields (but for those in the exclist) are pasted. The upload map is used to map orgid's - this is a
// temporary hack. Leaving it '' will cause it to have no effect.
function bpcXMLCopyRowSet( var DestDataSet : TDataSet; SourceRowNode : IXMLNode; var tempresult : string; sUploadMap : string=''; FieldRefList : TbpcLocateIndexList=nil; FieldExcList : TbpcLocateIndexList=nil ) : boolean; overload;
function bpcXMLCopyRowSet( var DestSG : TStringGrid; currow : integer; SourceRowNode : IXMLNode; var tempresult : string; sUploadMap : string; FieldRefList : TbpcLocateIndexList; FieldExcList : TbpcLocateIndexList ) : boolean; overload;
// Populates a single term (TargetIndexField) of the vararray of the locindexlist with a value drawn from
// the SourceVal. Only those fields named in the locindexlist are effected
// with the SourceVal. The SourceDataset is used to find the correct type of the variant.
// for the value in the VarArray.  The UseVarType may be one of (xrsfVAR, xrsfSTR,
// or xrsfQSTR). It modifies the individual variant type to one of a natural type, a string
// or a 'quoted if text else unquoted' string. The latter type is used for
// database datafields in sql expressions, while the first is usd for dataset.locate commands
// and the second is used in XML packets. If SourceDataSet is nil, or a field can not be
// found the standard XML string type is used (ie unquoted string).
function bpcSetLocIndValAsVarTerm( TargetIndexField, SourceVal : String; var SourceDataSet : TDataSet; var locindexlist : TbpcLocateIndexList; UseVarType : TbpcXMLFType; sUploadMap : string) : boolean;
// Populates the vararray of the locindexlist with values drawn from a simple name/value pair stringlist
// at SourceNameValPair. Only those fields named in the locindexlist are retrieved
// from the SourceNameValPair. The SourceDataset is used to find the correct type of the variant.
// for the value in the VarArray.  The UseVarType may be one of (xrsfVAR, xrsfSTR,
// or xrsfQSTR). It modifies the individual variant type to one of a natural type, a string
// or a 'quoted if text else unquoted' string. The latter type is used for
// database datafields in sql expressions, while the first is usd for dataset.locate commands
// and the second is used in XML packets. If SourceDataSet is nil, or a field can not be
// found the standard XML string type is used (ie unquoted string).
function bpcNameValPairAsVarArray( SourceNameValPair : TStrings; var SourceDataSet : TDataSet; var locindexlist : TbpcLocateIndexList; UseVarType : TbpcXMLFType; sUploadMap : string) : boolean;
// Populates the vararray of the locindexlist with values drawn from a bpcXML-1
// rowset at SourceRowNode. Only those fields named in the locindexlist are retrieved
// from the SourceRowNode. The SourceDataset is used to find the correct type of the variant.
// for the value in the VarArray.  The UseVarType may be one of (xrsfVAR, xrsfSTR,
// or xrsfQSTR). It modifies the individual variant type to one of a natural type, a string
// or a 'quoted if text else unquoted' string. The latter type is used for
// database datafields in sql expressions, while the first is usd for dataset.locate commands
// and the second is used in XML packets. If SourceDataSet is nil, or a field can not be
// found the standard XML string type is used (ie unquoted string).
function bpcXMLRowSetAsVarArray( SourceRowNode : IXMLNode; var SourceDataSet : TDataSet; var locindexlist : TbpcLocateIndexList; UseVarType : TbpcXMLFType; sUploadMap : string{=''} ) : boolean;
// Returns a string presenting the bpcXML-1 rowset (in SourceRowNode) as a
// conditional expression using the index list (in locindexlist).  The result
// has the form: "( field1='text value') and ( field2=number )" - comprising
// each field in the index list paired with its value in the vararray.
// Use it with the xrsfQSTR in bpcXMLRowSetAsVararray to build dataset filters
// from bpcXML-1 rowsets and actions. The Source DataSet provides the field type info
function bpcXMLRowSetAsFilter( var SourceDataSet : TDataSet; SourceRowNode : IXMLNode; var locindexlist : TbpcLocateIndexList; sUploadMap : string{=''} ) : string;
// TbpcXMLFType=(xrsfVAR, xrsfSTR, xrsfQSTR);
// Returns a variant translation of a string based on FieldKind as the type determinant
// xUseVarType modifies the variant type to one of a natural type, a string
// or a 'quoted if text else unquoted' string. The latter type is used for
// database datafields in sql expressions
function bpcReturnStrAsType( StrVar : string; xUseVarType : TbpcXMLFType; FieldKind : TFieldType  ) : variant;
// Returns a filtered dataset based on the rowset and the locindexlist. Uses bpcXMLRowSetAsFilter.
function bpcXMLApplyRowSetAsFilter( var SourceDataSet : TDataSet; SourceRowNode : IXMLNode; var locindexlist : TbpcLocateIndexList; sUploadMap : string{=''} ) : TDataSet;

BPCXML LANGUAGE DEFINITION

BPCXML Language 1 (bpcXML-1)

bpcXML-1 is a simple XML language for interfacing distributed databases.

It uses a messaging paradigm in which conversations consist of 'smxmlpacket' objects.

A syntax for the language is:

smxmlpacket='<smxmlpacket >'.authority.data.'</smxmlpacket >'
authority='<authority OID='.string.' PID='.string.' Pswd='.string.' />'
string='"'.value.'"'
value=sequence of letters or numbers
data='<data >'.messages.'</data >'
messages=message.[messages]
message='<message >'.actions.datasources.'</message >'
actions='<actions >'.actionlist.'</actions >'
actionlist=action.[actionlist]
action=updateaction| retrieveaction | commandaction | selectaction | -to be defined-
updateaction='<'.updatecommand.' source="'.string.'" indexby="'.fieldlist.'" />'
updatecommand='update'|'updateall'|'updatet'|'updatetall' (update a datasource or updatet an SQL table
retrieveaction='<'.retrievecommand.' source="'.string.'" indexby="'.fieldlist.'" fields="'.fieldlist.'" destination="'.string.'" returnindexby="'.fieldlist.'" table="'.on|off.'" />'
retrievecommand='retrieve'|'retrieveall'
commandaction='<'.commandcommand.' source="'.string.'" from="'.string.'" />'
commandcommand='cm'
selectaction='<'.selectcommand.' source="'.string.'" from="'.string.'" where="'.string.'" orderby="'.string.'" indexby="'.fieldlist.'" fields="'.fieldlist.'" destination="'.string.'" returnindexby="'.fieldlist.'" table="'.on|off.'" />'
selectcommand='select'
fieldlist=fieldname.[';'.fieldlist]
datasources='<'.datasourcename.' >'.rowsetlist.'</'.datasourcename.' >'
rowsetlist=rowset.[rowsetlist]
rowset='<rowset >'.fieldnamevaluelist.'</rowset >'
fieldnamevaluelist=fieldnamevalue.[fieldnamevaluelist]
fieldnamevalue='<'.fieldname.' >'.fieldvalue.'</'.fieldname.' >'
fieldname=value
fieldvalue=value

// Under consideration  Copy & Paste Support
First we copy:

<copy source="SurveyResponse" destination="SurveyResponse1" indexby="OrgID;SID;PID;InstanceID" fields="OrgID;SID;PID;QID;InstanceID;ResponseStr" />
--Make a packet called SurveyResponse1 from SurveyResponse using indexby to extract a match between the source template rowset packets and the datasource
--comprising the fields. If no fields specified, use all fields in datasource

We first have:


    <message >
      <actions >
         <copy source="myDataSource" destination="myDataSource1" indexby="FirstField;ThirdField" />
      </actions >
      <myDataSource >                               // This is the set of bookmark rowsets for copy to use to select from myDataSource
        <rowset >
           <FirstField >FieldValue</FirstField >
           <SecondField >FieldValue</SecondField >
           <ThirdField >FieldValue</ThirdField >
        </rowset >
        ...Other rows mentioned in the datasource packet
      </myDataSource >
    </message >

The Copy message is applied and it returns a set of rowsets called myDataSource1
We now have:

    <message >
      <actions >
         <store source="myDataSource1" indexby="FirstField;ThirdField" />
      </actions >
      <myDataSource1 >
        <rowset >
           <FirstField >FieldValue</FirstField >
           <SecondField >FieldValue</SecondField >
           <ThirdField >FieldValue</ThirdField >
        </rowset >
        ...Other rows mentioned in the datasource packet
      </myDataSource1 >
    </message >

Next we paste this clipped structure:

    <message >
      <actions >
         <paste store="myDataSource1" destination="myDataSource" flags="allfields;exclkey" />
      </actions >
    </message >

An alternative paste might look like this:
<paste source="SurveyResponse1" destination="SurveyResponse" indexby="OrgID;SID;PID;InstanceID" fields="OrgID;SID;PID;QID;InstanceID;ResponseStr" />

A typical message structure looks like this:

<smxmlpacket >
  <authority OID="myOID"  PID="myPID" Pswd="myPassword" />
  <data >
    <message >
      <actions >
         <update source="myDataSource" indexby="FirstField;ThirdField" />
         <updateall source="myDataSource2" indexby="FirstField;ThirdField" />
         ...Other actions - including more updates, etc.
      <actions >
      </myDataSource >
        <rowset >
           <FirstField >FieldValue</FirstField >
           <SecondField >FieldValue</SecondField >
           <ThirdField >FieldValue</ThirdField >
        <rowset >
        ...Other rows mentioned in the datasource packet
      </myDataSource >
      ...Other datasource mentioned in the actions
    </message >
    ...Other messages in this communication message batch
  </data >
</smxmlpacket >

Some specific examples of action Commands supported (nodes) are:

<update source="SurveyResponse" indexby="OrgID;SID;PID;InstanceID" /><SurveyResponse><rowset>...</rowset></surveyresponse>
// -------Update the component named source using the indexby with values drawn from the source rowsets

<updatet source="SurveyResponse" indexby="OrgID;SID;PID;InstanceID" /><SurveyResponse><rowset>...</rowset></surveyresponse>
// -------Update the table named source using the indexby with values drawn from the source rowsets

<retrieve source="SurveyResponse" destination="SurResponseTrnsf" indexby="OrgID;SID;PID;InstanceID" returnindexby="OrgID;SID;PID;QID;InstanceID" fields="OrgID;SID;PID;QID;InstanceID;ResponseStr" /><SurveyResponse><rowset>...</rowset></surveyresponse>
// -------Retrieve the component or table named source (depending on whether table=on) using the indexby with values drawn from the source rowsets and returning
// -------the rows in an update message packet using destination as the source table (or source if no destination) indexed by returnindexby and containing rowsets made up of fields.

<select source="SurveyResponse" from="SurveyResponse" destination="SurResponseTrnsf" where="(OrgID='default') and (PID='MELB001')" orderby="SID, QID" indexby="OrgID;SID;PID;InstanceID" returnindexby="OrgID;SID;PID;QID;InstanceID" fields="OrgID;SID;PID;QID;InstanceID;ResponseStr" />
// -------Retrieve the result of a select expression compised of tables listed in from  matching the where clause and in orderby order named source (depending on whether table=on) using the indexby with values drawn from the source rowsets and returning
// -------the fields matching fields.  (Note no rowset argument)

<cm source="SurveyResponse" from="update SurveyResponse set InstanceID='default', ResponseStr='1' where (OrgID='default') and (PID='MELB001') and (SID='MENU2')" />
// -------Apply a non returning command using an sql command in from. (Note no rowset argument)


The language relies on the client and the server agreeing on the definition of
data objects held in the messages.  The L-1 statetment consists of an authority packet
that is used to validate the packet, and a data packet containing N messages.

Each message consists of a set of actions (in some cases requiring data from datasources)
and a list of the datasources and the contents of the relevant data records presented as rowsets.
Each datasource can contain any number of rowsets.  Each rowset represents the
data contained in one row of the datasource.

Within a message a given datasource can be referenced by as many actions as you choose,
but only the first definition of that datasource will be used for all actions.
Datasources are defined by their rowsets, following the actions object which contains
a list of actions.

An action is comprised of a command (eg update or updateall), a datasource (the tag name of
a set of rowsets), a (optional) datadestination (tells the server the name of the
intended recipient of the datasource), a (optional) indexby list (which lists the fields
to use for matching records in the datasource to records in the datadestination).

The indexby list should match tags appearing in the rowsets and be separated by ';'

If the datadestination is not provided, the datasource is assumed to be the datadestination
If the indexby field list is not included, 'insert only' is assumed on the destination dataset
in the update commands. If the indexby list is provided, the record is edited if it already exists
and inserted if it doesn't - based on treating the indexby list as a primary index.

The following message causes the Survey S0001 in MyOrg to be created (if it doesn't exist)
and updated (otherwise) on the server with the contents of the listed fields.
It contains
-An Authority object for person P0001 on organisation MyOrg
-An update action using data sourced from 'Survey'
-A Rowset for the current record drawn from the datasource 'Survey'

<smxmlpacket >
  <authority OID="MyOrg"  PID="P0001" Pswd="myPwd"/>
  <data >
    <message >
      <actions >
         <update source="Survey" indexby="OrgID;SID" />
      <actions >
      <Survey >
        <rowset >
         <OrgID>MyOrg</OrgID >
         <SID>S0001</SID >
         <surveyname >My Staff Survey</surveyname >
         <owner>Mr. Squiggle</owner >
        </rowset >
      </Survey >
    </message >
  </data >
</smxmlpacket >

The following message causes the Survey S0001 in MyOrg to be created (if it doesn't exist)
and updated (otherwise) on the server with the contents of the listed fields in the Survey
datasource. It then causes all the questions in the SurveyQues datasource object to
be added to the survey-questions table

It contains
-An Authority object for person P0001 on organisation MyOrg
-An update action using data sourced from 'Survey'
-A single Rowset for the current record drawn from the datasource 'Survey'
-An updateall action using data sourced from 'SurveyQues'
-Multiple Rowsets for the records drawn from the datasource 'Survey'

<smxmlpacket >
  <authority OID="MyOrg"  PID="P0001" Pswd="myPwd"/>
  <data >
    <message >
      <actions >
         <update source="Survey" indexby="OrgID;SID" />
         <updateall source="SurveyQues" indexby="OrgID;SID;QID" />
      <actions >
      <Survey >
        <rowset >
         <OrgID>MyOrg</OrgID >
         <SID>S0001</SID >
         <surveyname >My Staff Survey</surveyname >
         <owner>Mr. Squiggle</owner >
        </rowset >
      </Survey >
      <survques >
        <rowset >
         <OrgID>default</OrgID >
         <SID>S0001</SID >
         <QID>S0001</QID >
         <question>What is your name?</question >
         <quesgroup>abcdefg</quesgroup>
        </rowset >
        <rowset >
         <OrgID>default</OrgID >
         <SID>S0001</SID >
         <QID>S0002</QID >
         <question>What is your foot size?</question >
         <quesgroup>abcdefg</quesgroup>
        </rowset >
      </survques >
    </message >
  </data >
</smxmlpacket >


In fact update and updateall are the same on the server - all the rowsets in a
datasource are applied in both cases.

This packet retrieves a message containing the 'fields' for all the records in
SurveyResponse matching the fields in indexby with values given in the rowsets.
The packet returned is an update packet, with returnindexby provided as the
indexby attribute of the returned update action (see below).

<smxmlpacket >
  <authority OID="MyOrg"  PID="P0001" Pswd="myPwd"/>
  <data >
    <message >
      <actions >
         <retrieve source="SurveyResponse" indexby="OrgID;SID;PID;InstanceID" returnindexby="OrgID;SID;PID;QID;InstanceID" fields="OrgID;SID;PID;QID;InstanceID;ResponseStr" />
      <actions >
      <SurveyResponse >
        <rowset >
         <OrgID>MyOrg</OrgID >
         <SID>S0001</SID >
         <PID >P0001</PID >
         <InstanceID>January</InstanceID >
        </rowset >
      </SurveyResponse >
    </message >
  </data >
</smxmlpacket >

The packet returned might look like:

<smxmlpacket >
  <authority OID="MyOrg"  PID="P0001" Pswd="myPwd"/>
  <data >
    <message >
      <actions >
         <update source="SurveyResponse" indexby="OrgID;SID;PID;QID;InstanceID" />
      <actions >
      <SurveyResponse >
        <rowset >
         <OrgID>MyOrg</OrgID >
         <SID>S0001</SID >
         <PID >P0001</PID >
         <QID >Q0001</QID >
         <InstanceID>January</InstanceID >
         <ResponseStr >1</ResponseStr >
        </rowset >
        <rowset >
         <OrgID>MyOrg</OrgID >
         <SID>S0001</SID >
         <PID >P0001</PID >
         <QID >Q0002</QID >
         <InstanceID>January</InstanceID >
         <ResponseStr >3</ResponseStr >
        </rowset >
      </SurveyResponse >
    </message >
  </data >
</smxmlpacket >


finally a large Example updating bpcXML-1 data packet:

<smxmlpacket >
  <authority OID="myOID"  PID="myPID" Pswd="myPwd"/>
  <data >
    <message >
      <actions >
         <update source="adotable1" indexby="OrgID;SID" />
         <update source="survques" indexby="OrgID;SID;QID" />
      <actions >
      <adotable1 >
        <rowset >
         <OrgID>default</OrgID >
         <SID>S0001</SID >
         <surveyname >xxxyyy</surveyname >
         <ShellHTML>abcdefg</ShellHTML>
        </rowset >
      </adotable1 >
      <survques >
        <rowset >
         <OrgID>default</OrgID >
         <SID>S0001</SID >
         <QID>S0001</QID >
         <question>xxxyyy</question >
         <quesgroup>abcdefg</quesgroup>
        </rowset >
      </survques >
    </message >
    <message >
      <actions >
         <update source="adotable1" indexby="OrgID;SID" />
         <updateall source="survques" indexby="OrgID;SID;QID" />
      <actions >
      <adotable1 >
        <rowset >
         <SID>S0001</SID >
         <surveyname >xxxyyy</surveyname >
         <ShellHTML>abcdefg</ShellHTML>
        </rowset >
      </adotable1 >
      <survques >
        <rowset >
         <OrgID>default</OrgID >
         <SID>S0001</SID >
         <QID>Q0001</QID >
         <question>xxxyyy</question >
         <quesgroup>abcdefg</quesgroup>
        </rowset >
        <rowset >
         <OrgID>default</OrgID >
         <SID>S0001</SID >
         <QID>Q0002</QID >
         <question>xxxyyy</question >
         <quesgroup>abcdefg</quesgroup>
        </rowset >
        <rowset >
         <OrgID>default</OrgID >
         <SID>S0001</SID >
         <QID>Q0003</QID >
         <question>xxxyyy</question >
         <quesgroup>abcdefg</quesgroup>
        </rowset >
      </survques >
    </message >
  </data >
</smxmlpacket >



BackLinks