MakeXml
From Pickwiki
Back to BasicSource
This program generates XML using the standard dictionaries. One of the nice bits is that it can use phrases to reduce the input line size and to bundle stuff into sub-elements.
PROGRAM MAKEXML * ECL - KRJ - Generates XML using standard dictionaries * **** NOTE - ECL is what Unidata called TCL - it's not a company name, **** it's advising that this is a command line utility. **** KRJ are my iniials - Keith Robert Johnson. I wrote most of it, you use it at your own risk. **** SKR is Shayne Riches - the 10 line GRAPH subroutine is his, I think I asked him if I could **** use it, but it was so long ago I can't remember exactly. Don't use it if you don't want to. **** The rest of this program is Public Domain, you can do what you want with it - even change the **** source if you find a bug (just not just because you don't like my style - now please!) **** * You have to make the WRITESEQ lines work for the U2 brand * Unidata - WRITESEQ LINE APPEND ON ... * Universe & QM - WRITESEQ LINE ON ... * * Next lines for QM $MODE UV.LOCATE EQU ITATT TO 16 * Next lines for Universe * $OPTIONS PICK.FORMAT -STATIC.DIM * EQU ITATT TO 20 * Next lines for Unidata * $BASICTYPE 'P' * EQU ITATT TO 8 * VERSION = 'xml version="1.0"' COMD = 'MAKEXML' SENTENCE = OCONV(@SENTENCE,'MCU') TEST = INDEX(SENTENCE,COMD,1) IF TEST THEN SENTENCE = TRIM(@SENTENCE[TEST+LEN(COMD),LEN(@SENTENCE)]) END ELSE SENTENCE = @SENTENCE OPTIONS = FIELD(SENTENCE,'(',2) SENTENCE = FIELD(SENTENCE,'(',1) OPTIONS = OCONV(FIELD(OPTIONS,')',1),'MCU') * ESC = CHAR(27) AMPERSAND = CHAR(38) T1 = CHAR(9) T2 = T1:T1 T3 = T1:T1:T1 BELL = STR(CHAR(7),20) BAD = @TRUE FIRST = @TRUE * Get the operating system (text) file we want to create - and where from [[TYPE19FILE]] = FIELD(SENTENCE,' ',1) [[TYPE19ITEM]] = FIELD(SENTENCE,' ',2) FNAME = FIELD(SENTENCE,' ',3) DICTS = TRIM(SENTENCE[COL2(),LEN(SENTENCE)]) * If we haven't got the data source, give help IF FNAME EQ '' THEN CRT @(-1): CRT COMD:' - Generates XML' CRT CRT 'SYNTAX - ':COMD:' type19file item file [fields] (Options)' CRT CRT 'OPTIONS' CRT ' G - Generate a schema only (.XSD)' CRT ' D - DTD output only (.DTD)' CRT ' K - Kill empty attributes (IE ignore them in XML)' CRT ' Q - Quiet, do not display progress information' CRT ' X - XSL outout required (This creates XML as well)' CRT CRT 'NOTES' CRT 'If type19file is "CRT" output is to the screen.' CRT 'The output file will have extensions added to suit the type' CRT 'of output requested. If XSL file output is requested, then' CRT 'BOTH the XSL and XML outputs are produced.' STOP END * * Get the options IF INDEX(OPTIONS,'Q',1) THEN QUIET = @TRUE ELSE QUIET = @FALSE IF INDEX(OPTIONS,'K',1) THEN KILL = @TRUE ELSE KILL = @FALSE OUTPUT = 'XML' IF INDEX(OPTIONS,'D',1) THEN OUTPUT = 'DTD' IF INDEX(OPTIONS,'G',1) THEN OUTPUT = 'XSD' IF INDEX(OPTIONS,'X',1) THEN OUTPUT = 'XSL' IF OUTPUT NE 'XML' THEN QUIET = @TRUE IF @TTY EQ 'phantom' THEN QUIET = @TRUE * Check if we have got dictionary items IF DICTS EQ '' THEN CRT 'Dictionary Items are required for XML' STOP END * * Display graph if terminal and select list is active TOTCNT = SYSTEM(11) * Next line for Universe IF TOTCNT THEN TOTCNT = @SELECTED * CNTR = 0 OLD.PCT = 0 SHOW = @FALSE IF TOTCNT THEN SHOW = @TRUE IF QUIET THEN SHOW = @FALSE * * Open, check, and initialise the transfer file IF [[TYPE19FILE]] NE 'CRT' THEN OPEN [[TYPE19FILE]] TO TRANSFER.FILE ELSE CRT 'Cannot open file ':[[TYPE19FILE]]:BELL STOP END * I THINK the next line will work in Unidata IF FILEINFO(TRANSFER.FILE,3) NE '4' THEN CRT [[TYPE19FILE]]:' is not type 1 or 19 file (Directory)':BELL STOP END DELETE TRANSFER.FILE, [[TYPE19ITEM]]:'.':OUTPUT IF OUTPUT = 'XSL' THEN DELETE TRANSFER.FILE, [[TYPE19ITEM]]:'.XML' END ELSE SHOW = @FALSE; QUIET = @TRUE * * Open the source file and its dictionary OPEN FNAME TO IFILE ELSE CRT 'Cannot open file ':FNAME:BELL STOP END OPEN 'DICT',FNAME TO DFILE ELSE CRT 'Cannot open the dictionary of file ':FNAME:BELL STOP END * * Make sure the name of the file is good XML XMLNAME = FNAME CONVERT ' ':CHAR(9) TO '' IN XMLNAME FRAG = XMLNAME; GOSUB CHANGE.CHARS; XMLNAME = FRAG * * Build up the dictionary data FIELD.LIST = CONVERT(' ',@AM,DICTS) XXCNT = DCOUNT(FIELD.LIST,@AM) * * Pass through the dictionary list, expanding any phrases * and setting out XML attributes, multivalues, and associated (or grouped) * U2 attributes. PHRASES = '' ATTS = '' TAGS = '' GRPS = '' GGCNT = 0 GROUPS = '' GRP.TITLE = '' FOR XX = 1 TO XXCNT ID = FIELD.LIST<XX> READ DREC FROM DFILE,ID THEN IF OCONV(DREC[1,2],'MCU') EQ 'PH' THEN LOCATE ID IN PHRASES SETTING POSN THEN CRT 'Circular reference - ': CRT ID:' is a phrase that has been used before.' STOP END PHRASES<-1> = ID NEWBIT = CONVERT(' ',@AM,DREC<2>) YYCNT = DCOUNT(NEWBIT,@AM) FIELD.LIST<XX> = NEWBIT XX = XX - 1 XXCNT = XXCNT + YYCNT - 1 END ELSE BEGIN CASE CASE DREC<1>[1,1] = 'A' OR DREC<6> = 'S' ATTS<-1> = XX * NOTE - I can't remember how Unidata handles groups CASE DREC<6> = 'M' AND DREC<7> NE '' GNAME = DREC<7> * Only allow two words maximum as a group title * The first word will be a sort of wrapper for the second, if there is one GNAME = TRIM(GNAME) TEST = INDEX(GNAME,' ',2) IF TEST THEN GNAME = GNAME[1,TEST-1] LOCATE GNAME IN GROUPS SETTING POSN THEN GRPS<POSN,-1> = XX END ELSE GGCNT = GGCNT + 1 GROUPS<GGCNT> = GNAME FRAG = GNAME; GOSUB CHANGE.CHARS GRP.TITLE<GGCNT> = FRAG GRPS<GGCNT> = XX END * Multivalues are set out as elements, and require tags CASE DREC<6> = 'M' TAGS<-1> = XX CASE 1 CRT ID:' is an invalid dictionary field' STOP END CASE END END NEXT XX * * Dimension and initialise the dictionary stuff DIM DICT.RECS(XXCNT); MAT DICT.RECS = '' DIM DICT.CONV(XXCNT); MAT DICT.CONV = '' DIM DICT.TYPE(XXCNT); MAT DICT.TYPE = '' DIM DICT.TITL(XXCNT); MAT DICT.TITL = '' * * Process the dictionary data FOR XX = 1 TO XXCNT ID = FIELD.LIST<XX> READ DREC FROM DFILE, ID THEN DTYPE = DREC<1>[1,1] IF DTYPE EQ 'V' THEN DTYPE = 'I' * Convert A-type to D-type - our software can have conversion on 8 or 7 IF DTYPE = 'A' THEN TEMP = 'D':@AM:DREC<2>:@AM:DREC<8>:@AM:DREC<3> TEMP<5> = DREC<10>:DREC<9> TEMP<6> = 'S' IF DREC<7> NE '' THEN TEMP<3> = DREC<7> DREC = TEMP DTYPE = 'D' END * Check the dictionary is compiled IF DTYPE EQ 'I' AND DREC<ITATT> = '' THEN EXECUTE 'COMPILE.DICT ':FNAME:' ':ID CAPTURING JUNK READ DREC FROM DFILE, ID ELSE DREC = '' IF DREC<ITATT> EQ '' THEN CRT 'Cannot compile dictionary ':ID STOP END END IF DTYPE EQ 'D' OR DTYPE EQ 'I' THEN BAD = @FALSE DICT.RECS(XX) = DREC DICT.CONV(XX) = DREC<3> TITL = ID FRAG = TITL; GOSUB CHANGE.CHARS; TITL = FRAG DICT.TITL(XX) = TITL DICT.TYPE(XX) = DTYPE END END NEXT XX IF BAD THEN CRT BELL:'No Dictionary items chosen':BELL STOP END * * See what the maximum number in a group is and dimension group workspace GMAX = 1 FOR GG = 1 TO GGCNT GNUM = DCOUNT(GRPS<GG>,@VM) IF GNUM GT GMAX THEN GMAX = GNUM NEXT GG DIM GDAT(GMAX) * * Now generate the output file BEGIN CASE CASE OUTPUT = 'DTD'; GOSUB OUTPUT.DTD CASE OUTPUT = 'XSD'; GOSUB OUTPUT.SCHEMA CASE OUTPUT = 'XSL' GOSUB OUTPUT.XSL IF [[TYPE19FILE]] NE 'CRT' THEN CLOSESEQ DEST ON ERROR CRT 'CLOSESEQ ERROR':BELL FIRST = @TRUE GOSUB OUTPUT.XML END CASE 1 GOSUB OUTPUT.XML END CASE IF [[TYPE19FILE]] NE 'CRT' THEN * CLOSESEQ DEST ON ERROR CRT 'CLOSESEQ ERROR':BELL CLOSESEQ DEST END STOP * * ********************************************************************* * SUBROUTINES ********************************************************************* PACK.ITEM: ********** REC = @RECORD LINE = '' XMLID = @ID FRAG = XMLID; GOSUB CHANGE.CHARS; XMLID = FRAG LINE = '<item id="':XMLID:'"' YYCNT = DCOUNT(ATTS,@AM) FOR YY = 1 TO YYCNT XX = ATTS<YY> IF DICT.TYPE(XX) EQ 'D' THEN IF DICT.RECS(XX)<2> EQ '0' THEN BIT = @ID * Just hope it is single valued END ELSE BIT = REC<DICT.RECS(XX)<2>> END ELSE BIT = ITYPE(DICT.RECS(XX)) END IF DICT.CONV(XX) NE '' THEN BIT = OCONV(BIT,DICT.CONV(XX)) IF KILL AND BIT EQ '' ELSE FRAG = BIT; GOSUB CHANGE.CHARS; BIT = FRAG LINE := ' ':DICT.TITL(XX):'="':BIT:'"' END NEXT YY LINE := '>' GOSUB WRITE.LINE; IF BAD THEN RETURN * YYCNT = DCOUNT(TAGS,@AM) FOR YY = 1 TO YYCNT XX = TAGS<YY> IF DICT.TYPE(XX) EQ 'D' THEN IF DICT.RECS(XX)<2> EQ '0' THEN BIT = @ID END ELSE BIT = REC<DICT.RECS(XX)<2>> END ELSE BIT = ITYPE(DICT.RECS(XX)) END BIT = RAISE(BIT) ZZCNT = DCOUNT(BIT,@AM) FOR ZZ = 1 TO ZZCNT * Note how subvalues are ignored - my decision, you may disagree ZIT = BIT<ZZ,1> IF DICT.CONV(XX) NE '' THEN ZIT = OCONV(ZIT,DICT.CONV(XX)) FRAG = ZIT; GOSUB CHANGE.CHARS; ZIT = FRAG ZIT = '<':DICT.TITL(XX):'>':ZIT:'</':DICT.TITL(XX):'>' LINE = T1:ZIT GOSUB WRITE.LINE; IF BAD THEN RETURN NEXT ZZ NEXT YY * * Process the grouped data FOR GG = 1 TO GGCNT MAT GDAT = '' IICNT = 0 HHCNT = DCOUNT(GRPS<GG>,@VM) FOR HH = 1 TO HHCNT XX = GRPS<GG,HH> IF DICT.TYPE(XX) EQ 'D' THEN IF DICT.RECS(XX)<2> EQ '0' THEN BIT = @ID END ELSE BIT = REC<DICT.RECS(XX)<2>> END ELSE BIT = ITYPE(DICT.RECS(XX)) END GDAT(HH) = RAISE(BIT) INUM = DCOUNT(GDAT(HH),@AM) IF INUM GT IICNT THEN IICNT = INUM NEXT HH WRAPPER = '' TITLE = GRP.TITLE<GG> WIT = '' IF INDEX(TITLE,' ',1) THEN WRAPPER = FIELD(TITLE,' ',1) TITLE = FIELD(TITLE,' ',2) WIT = T1 END * Cater for the special case where there is only one in the group * when we have an enclosing wrapper rather than a repeating title IF HHCNT EQ 1 AND WRAPPER EQ '' THEN WRAPPER = TITLE TITLE = '' END SAVETITLE = TITLE SAVEWRAPPER = WRAPPER FOR II = 1 TO IICNT TITLE = SAVETITLE FOR HH = 1 TO HHCNT XX = GRPS<GG,HH> * Again, subvalues are ignored ZIT = GDAT(HH)<II,1> IF DICT.CONV(XX) NE '' THEN ZIT = OCONV(ZIT,DICT.CONV(XX)) IF ZIT NE '' THEN IF WRAPPER NE '' THEN LINE = T1:'<':WRAPPER:'>' GOSUB WRITE.LINE; IF BAD THEN RETURN WRAPPER = '' END IF TITLE NE '' THEN LINE = WIT:T1:'<':TITLE:'>'; TITLE = '' GOSUB WRITE.LINE; IF BAD THEN RETURN END FRAG = ZIT; GOSUB CHANGE.CHARS; ZIT = FRAG ZIT = '<':DICT.TITL(XX):'>':ZIT:'</':DICT.TITL(XX):'>' LINE = WIT:T2:ZIT GOSUB WRITE.LINE; IF BAD THEN RETURN END NEXT HH IF TITLE EQ '' AND SAVETITLE NE '' THEN LINE = WIT:T1:'</':SAVETITLE:'>' GOSUB WRITE.LINE; IF BAD THEN RETURN END NEXT II IF WRAPPER EQ '' AND SAVEWRAPPER NE '' THEN LINE = T1:'</':SAVEWRAPPER:'>' GOSUB WRITE.LINE; IF BAD THEN RETURN END NEXT GG LINE = '</item>' GOSUB WRITE.LINE RETURN * OUTPUT.XML: *********** IF NOT(QUIET) THEN CRT @(-1):COMD; CRT; CRT IF OUTPUT = 'XSL' THEN LINE = '<?':VERSION:'?>' OUTPUT = 'XML' GOSUB WRITE.LINE; IF BAD THEN STOP LINE = '<?xml-stylesheet type="text/xsl" href="' LINE := [[TYPE19ITEM]]:'.XSL"?>' END ELSE LINE = '<?':VERSION:' standalone="yes"?>' END GOSUB WRITE.LINE; IF BAD THEN STOP LINE = T1:'<!-- XML from ':@PATH:' at ':TIMEDATE() LINE := ' by ':@LOGNAME:' - Original line as below -->' GOSUB WRITE.LINE; IF BAD THEN STOP LINE = T1:'<!-- ':@SENTENCE:' -->' GOSUB WRITE.LINE; IF BAD THEN STOP LINE = '<file id="':XMLNAME:'">' GOSUB WRITE.LINE; IF BAD THEN STOP IF NOT(TOTCNT) THEN SELECT IFILE EOF = @FALSE LOOP READNEXT @ID ELSE EOF = @TRUE UNTIL EOF *LOOP WHILE READNEXT @ID DO CNTR += 1 IF SHOW THEN NEW.PCT = INT((CNTR*100)[[/TOTCNT]]) IF NEW.PCT NE OLD.PCT THEN percent = NEW.PCT caption = 'PREPARING FILE "':[[TYPE19ITEM]]:'"' GOSUB GRAPH END OLD.PCT = NEW.PCT END ELSE IF NOT(QUIET) THEN IF NOT(REM(CNTR,100)) THEN CRT @(0):CNTR: END END READ @RECORD FROM IFILE, @ID THEN GOSUB PACK.ITEM IF BAD THEN STOP REPEAT LINE = '</file>'; GOSUB WRITE.LINE; IF BAD THEN STOP IF NOT(SHOW OR QUIET) THEN CRT @(-1):CNTR: RETURN * OUTPUT.DTD: *********** LINES = '' LINES<-1> = '<?':VERSION:' standalone="yes"?>' LINES<-1> = '<!--' LINES<-1> = T1:'This is the DTD for the command' LINES<-1> = T1:@SENTENCE LINES<-1> = '-->' LINES<-1> = '<!ELEMENT file (item)>' LINES<-1> = '<!ATTLIST file id CDATA #REQUIRED>' LINES<-1> = '<!ELEMENT item' BIT = ' (' * Show tags YYCNT = DCOUNT(TAGS,@AM) FOR YY = 1 TO YYCNT XX = TAGS<YY> LINES := BIT:DICT.TITL(XX):'*' BIT = ', ' NEXT YY * Show Groups YYCNT = DCOUNT(GROUPS,@AM) FOR YY = 1 TO YYCNT LINES := BIT:FIELD(GROUPS<YY>,' ',1):'*' BIT = ', ' NEXT YY IF BIT = ', ' THEN LINES := ')' LINES := '>' * Show id LINES<-1> = '<!ATTLIST item id':T1:'CDATA #REQUIRED' YYCNT = DCOUNT(ATTS,@AM) IF YYCNT THEN * Loop doing each ATT FOR YY = 1 TO YYCNT XX = ATTS<YY> LINES<-1> = SPACE(15):DICT.TITL(XX):T1:'CDATA #' IF KILL THEN LINES := 'IMPLIED' ELSE LINES := 'REQUIRED' IF YY EQ YYCNT THEN LINES := '>' NEXT YY END ELSE LINES := '>' END * Loop doing each TAG YYCNT = DCOUNT(TAGS,@AM) FOR YY = 1 TO YYCNT XX = TAGS<YY> LINES<-1> = '<!ELEMENT ':DICT.TITL(XX):' (#PCDATA)>' NEXT YY * Loop doing each group item GGCNT = DCOUNT(GRPS,@AM) FOR GG = 1 TO GGCNT GNAME = GROUPS<GG> IF INDEX(GNAME,' ',1) THEN LINES<-1> = '<!ELEMENT ':FIELD(GNAME,' ',1):' (' LINES := FIELD(GNAME,' ',2):'*)>' GNAME = FIELD(GNAME,' ',2) END HHCNT = DCOUNT(GRPS<GG>,@VM) LINES<-1> = '<!ELEMENT ':GNAME:' ' BIT = '(' FOR HH = 1 TO HHCNT XX = GRPS<GG,HH> LINES := BIT:DICT.TITL(XX):'*' BIT = ', ' NEXT HH LINES := ')>' FOR HH = 1 TO HHCNT XX = GRPS<GG,HH> LINES<-1> = '<!ELEMENT ':DICT.TITL(XX):' (#PCDATA)>' NEXT HH NEXT GG GOSUB WRITE.LINES RETURN * OUTPUT.SCHEMA: ************** LINES = '' LINES<-1> = '<?':VERSION:' standalone="yes"?>' LINES<-1> = @AM * Documentation LINES<-1> = '<xsd:schema ' LINES := 'xmlns:xsd="http://www.w3.org/2000/10/XMLSchema">' LINES<-1> = '<xsd:annotation>' LINES<-1> = T1:'<xsd:documentation>' LINES<-1> = T2:'This is the SCHEMA for the command' LINES<-1> = T2:@SENTENCE LINES<-1> = T1:'</xsd:documentation>' LINES<-1> = '</xsd:annotation>' LINES<-1> = @AM * file LINES<-1> = '<xsd:element name="file" type="[[FileType]]"/>' LINES<-1> = '<xsd:complexType name="[[FileType]]"' LINES<-1> = T1:'<xsd:sequence>' LINES<-1> = T2:'<xsd:element name="item" type="[[ItemType]]"/>' LINES<-1> = T1:'</xsd:sequence>' LINES<-1> = T1:'<xsd:attribute name="id" use="required"' LINES := ' type="xsd:string"/>' LINES<-1> = '</xsd:complexType>' LINES<-1> = @AM * item LINES<-1> = '<xsd:complexType name="[[ItemType]]"' * Show tags and groups IF TAGS NE '' OR GROUPS NE '' THEN LINES<-1> = T1:'<xsd:sequence>' END * Show tags YYCNT = DCOUNT(TAGS,@AM) FOR YY = 1 TO YYCNT XX = TAGS<YY> LINES<-1> = T2:'<xsd:element name="' LINES := DICT.TITL(XX):'" type="xsd:string"/>' NEXT YY * Show groups referring to them as complex types YYCNT = DCOUNT(GROUPS,@AM) FOR YY = 1 TO YYCNT GNAME = FIELD(GROUPS<YY>,' ',1) LINES<-1> = T2:'<xsd:element name="':GNAME:'" ' LINES := 'type="':GNAME:'Type"/>' NEXT YY IF TAGS NE '' OR GROUPS NE '' THEN LINES<-1> = T1:'</xsd:sequence>' END * id attribute LINES<-1> = T1:'<xsd:attribute name="id" use="required"' LINES := ' type="xsd:string"/>' * Show attributes YYCNT = DCOUNT(ATTS,@AM) FOR YY = 1 TO YYCNT XX = ATTS<YY> LINES<-1> = T1:'<xsd:attribute name="':DICT.TITL(XX):'"' IF NOT(KILL) THEN LINES := ' use="required"' LINES := ' type="xsd:string"/>' NEXT YY LINES<-1> = '</xsd:complexType>' LINES<-1> = @AM * Show any second level groups as complex types also YYCNT = DCOUNT(GROUPS,@AM) FOR YY = 1 TO YYCNT GNAME = FIELD(GROUPS<YY>,' ',2) IF GNAME NE '' THEN LINES<-1> = '<xsd:complexType name="' LINES := FIELD(GROUPS<YY>,' ',1):'Type">' LINES<-1> = T1:'<xsd:sequence>' LINES<-1> = T2:'<xsd:element name="':GNAME:'" ' LINES := 'type="':GNAME:'Type"/>' LINES<-1> = T1:'</xsd:sequence>' LINES<-1> = '</xsd:complexType>' LINES<-1> = @AM END NEXT YY * Loop doing each group item GGCNT = DCOUNT(GRPS,@AM) FOR GG = 1 TO GGCNT GNAME = GROUPS<GG> IF INDEX(GNAME,' ',1) THEN GNAME = FIELD(GNAME,' ',2) LINES<-1> = '<xsd:complexType name="':GNAME:'Type">' HHCNT = DCOUNT(GRPS<GG>,@VM) FOR HH = 1 TO HHCNT XX = GRPS<GG,HH> LINES<-1> = T1:'<xsd:element name="':DICT.TITL(XX) LINES := '" type="xsd:string"/>' NEXT HH LINES<-1> = '</xsd:complexType>' LINES<-1> = @AM NEXT GG LINES<-1> = '</xsd:schema>' GOSUB WRITE.LINES RETURN * OUTPUT.XSL: *********** * Generic header LINES = '' LINES<-1> = '<?':VERSION:' standalone="yes"?>' LINES<-1> = '<xsl:stylesheet ' LINES := 'xmlns:xsl="http://www.w3.org/TR/WD-xsl">' LINES<-1> = @AM LINES<-1> = '<xsl:template match="/">' LINES<-1> = '<html>' LINES<-1> = T1:'<head>' LINES<-1> = T2:'<style>body,h1,h2,h3 ' LINES := '{ font-family: Tahoma,Arial,Helvetica; } ' LINES := 'thead { text-align: left; } ' LINES := 'tr { margin-top: 2px; } ' LINES := 'thead { background-color: Black; color: White; }</style>' LINES<-1> = T2:'<title>File listing</title>' LINES<-1> = T1:'</head>' LINES<-1> = T1:'<body>' LINES<-1> = T2:'<xsl:apply-templates select="*" />' LINES<-1> = T1:'</body>' LINES<-1> = '</html>' LINES<-1> = '</xsl:template>' LINES<-1> = @AM; GOSUB WRITE.LINES LINES<-1> = '<xsl:template match="file">' LINES<-1> = T1:'<h1>File name:' LINES := '<xsl:value-of select="@id" />' LINES := '</h1>' LINES<-1> = T1:'<xsl:apply-templates select="*" />' LINES<-1> = '</xsl:template>' LINES<-1> = @AM; GOSUB WRITE.LINES * item with id and attributes LINES<-1> = '<xsl:template match="item">' LINES<-1> = T1:'<h2>Item ID:' LINES := '<xsl:value-of select="@id" />' LINES := '</h2>' LINES<-1> = T1:'<div style="margin-left: 20px;">' * Loop doing each ATT YYCNT = DCOUNT(ATTS,@AM) FOR YY = 1 TO YYCNT XX = ATTS<YY> LINE = T1:'<h3>':DICT.TITL(XX):' = "' LINE:= '<xsl:value-of select="@':DICT.TITL(XX):'" />' LINE:= '"</h3>' LINES<-1> = LINE NEXT YY * Loop doing each TAG YYCNT = DCOUNT(TAGS,@AM) FOR YY = 1 TO YYCNT XX = TAGS<YY> LINES<-1> = T1:'<table>' LINES<-1> = T2:'<thead>' LINES<-1> = T3:'<th>':DICT.TITL(XX):'</th>' LINES<-1> = T2:'</thead>' LINES<-1> = T2:'<tbody>' LINES<-1> = T3:'<xsl:apply-templates select="':DICT.TITL(XX):'"/>' LINES<-1> = T2:'</tbody>' LINES<-1> = T1:'</table>' NEXT YY * * Loop doing each group (multi-level groups just have a reference) GGCNT = DCOUNT(GROUPS,@AM) FOR GG = 1 TO GGCNT GNAME = GROUPS<GG> GSUBNAME = FIELD(GNAME,' ',2) GNAME = FIELD(GNAME,' ',1) IF GSUBNAME NE '' THEN LINES<-1> = T1:'<xsl:apply-templates select="':GNAME:'"/>' END ELSE HHCNT = DCOUNT(GRPS<GG>,@VM) LINES<-1> = T1:'<h3>':GNAME:'</h3>' LINES<-1> = T1:'<table>' LINES<-1> = T2:'<thead>' FOR HH = 1 TO HHCNT XX = GRPS<GG,HH> LINES<-1> = T3:'<th>':DICT.TITL(XX):'</th>' NEXT HH LINES<-1> = T2:'</thead>' LINES<-1> = T2:'<tbody>' LINES<-1> = T3:'<xsl:apply-templates select="':GNAME:'"/>' LINES<-1> = T2:'</tbody>' LINES<-1> = T1:'</table>' END NEXT GG LINES<-1> = T1:'</div>' LINES<-1> = '</xsl:template>' LINES<-1> = @AM; GOSUB WRITE.LINES * Loop doing each TAG YYCNT = DCOUNT(TAGS,@AM) FOR YY = 1 TO YYCNT XX = TAGS<YY> LINES<-1> = '<xsl:template match="':DICT.TITL(XX):'">' LINES<-1> = T1:'<xsl:for-each match=".">' LINES<-1> = T2:'<tr><td>' LINES<-1> = T2:'<xsl:value-of select="."/>' LINES<-1> = T2:'</td></tr>' LINES<-1> = T1:'</xsl:for-each>' LINES<-1> = '</xsl:template>' LINES<-1> = @AM; GOSUB WRITE.LINES NEXT YY * Do each groups template GGCNT = DCOUNT(GROUPS,@AM) FOR GG = 1 TO GGCNT HHCNT = DCOUNT(GRPS<GG>,@VM) GNAME = GROUPS<GG> GSUBNAME = FIELD(GNAME,' ',2) GNAME = FIELD(GNAME,' ',1) LINES<-1> = '<xsl:template match="':GNAME:'">' IF GSUBNAME = '' THEN GOSUB DO.TABLE LINES<-1> = '</xsl:template>' LINES<-1> = @AM; GOSUB WRITE.LINES END ELSE LINES<-1> = T1:'<h3>':GNAME:'</h3>' LINES<-1> = T1:'<table>' LINES<-1> = T2:'<thead>' FOR HH = 1 TO HHCNT XX = GRPS<GG,HH> LINES<-1> = T3:'<th>':DICT.TITL(XX):'</th>' NEXT HH LINES<-1> = T2:'</thead>' LINES<-1> = T2:'<tbody>' IF GSUBNAME NE '' THEN LINES<-1> = T3:'<xsl:apply-templates select="*" />' END ELSE GOSUB DO.TABLE END LINES<-1> = T2:'</tbody>' LINES<-1> = T1:'</table>' LINES<-1> = '</xsl:template>' LINES<-1> = @AM; GOSUB WRITE.LINES LINES<-1> = '<xsl:template match="':GSUBNAME:'">' LINES<-1> = T1:'<tr>' FOR HH = 1 TO HHCNT XX = GRPS<GG,HH> LINES<-1> = T2:'<td><xsl:value-of select="' LINES := DICT.TITL(XX):'"/></td>' NEXT HH LINES<-1> = T1:'</tr>' LINES<-1> = '</xsl:template>' LINES<-1> = @AM; GOSUB WRITE.LINES END NEXT GG LINES<-1> = '</xsl:stylesheet>' GOSUB WRITE.LINES RETURN * DO.TABLE: ********* IF HHCNT = 1 THEN LINES<-1> = T1:'<xsl:for-each match=".">' LINES<-1> = T2:'<tr><td>' LINES<-1> = T2:'<xsl:value-of select="."/>' LINES<-1> = T2:'</td></tr>' LINES<-1> = T1:'</xsl:for-each>' END ELSE LINES<-1> = T1:'<tr>' FOR HH = 1 TO HHCNT XX = GRPS<GG,HH> LINES<-1> = T2:'<td><xsl:value-of select="' LINES := DICT.TITL(XX):'"/></td>' NEXT HH LINES<-1> = T1:'</tr>' END RETURN * WRITE.LINES: LLCNT = DCOUNT(LINES,@AM) FOR LL = 1 TO LLCNT LINE = LINES<LL> GOSUB WRITE.LINE IF BAD THEN STOP NEXT LL LINES = '' RETURN * WRITE.LINE: *********** IF FIRST THEN IF [[TYPE19FILE]] NE 'CRT' THEN WRITE LINE ON TRANSFER.FILE,[[TYPE19ITEM]]:'.':OUTPUT END ELSE CRT LINE END FIRST = @FALSE IF [[TYPE19FILE]] NE 'CRT' THEN OPENSEQ [[TYPE19FILE]],[[TYPE19ITEM]]:'.':OUTPUT TO DEST ELSE CRT 'Cannot OPENSEQ ':[[TYPE19ITEM]]:'.':OUTPUT BAD = @TRUE RETURN END END ELSE RETURN * Next line for Unidata? * RETURN END IF [[TYPE19FILE]] NE 'CRT' THEN WRITESEQ LINE ON DEST ELSE * Replace above line with next on Unidata? * WRITESEQ LINE APPEND ON DEST ELSE CRT 'Cannot WRITESEQ' BAD = @TRUE END END ELSE CRT LINE RETURN * GRAPH: ****** *SUBROUTINE GRAPH(percent,caption) * S[[/R]] - SKR - Graph of % completion of a task * CRT @(19,11):' |---|---|---|---|---|---|---|---|---|---| ':@(-4) CRT @(19,12):' 0 20 40 60 80 100':@(-4) CRT @(19,13):' ':caption:@(-4) bar.length = INT(percent*40/100) bar = STR(' ',bar.length) CRT @(20,10):@(-13):bar:@(-14):percent:' %':@(-4) RETURN * CHANGE.CHARS: ************* FRAG = CHANGE(FRAG,'&',AMPERSAND:'amp;') FRAG = CHANGE(FRAG,'<',AMPERSAND:'lt;') FRAG = CHANGE(FRAG,'>',AMPERSAND:'gt;') FRAG = CHANGE(FRAG,'"',AMPERSAND:'quot;') FRAG = CHANGE(FRAG,"'",AMPERSAND:'039;') RETURN