(Originally posted 2009-04-09.)
So here’s yet another way of parsing the WLM XML Service Definition. This time it’s on z/OS, using DFSORT. Relatively recent features in DFSORT have made it easier to do useful things with XML.
In this example I’ve made some attempt to make the output pretty – by creating a HTML table.
Below is the SYSIN you need to parse the <SchedulingEnvironment> elements. I’m assuming you know how to code a basic DFSORT invocation.
(To be able to run this example you need the PTFs for APAR UK90013 – WHEN=GROUP – and for UK90006/UK90007 – JFY and PARSE.)
OPTION COPY,VLSHRT INREC IFTHEN=(WHEN=INIT,BUILD=(1,4,3X,5)), IFTHEN=(WHEN=GROUP, BEGIN=(8,80,SS,EQ,C'<SchedulingEnvironment>'), END=(8,80,SS,EQ,C'</SchedulingEnvironment>'), PUSH=(5:ID=3)) OUTFIL INCLUDE=(5,1,CH,EQ,C'0'),REMOVECC, HEADER1=('<html>',/, '<body>',/, '<h1>Scheduling Environments</h1>',/, '<table border="1">',/, '<tr>',/, '<th>Name</th>',/, '<th>Description</th>',/, '<th>Resources Required</th>',/, '</tr>'), IFTHEN=(WHEN=(8,80,SS,EQ,C'<SchedulingEnvironment>'), BUILD=(1,4,C'<tr>')), IFTHEN=(WHEN=(14,6,CH,EQ,C'<Name>'), PARSE=(%00=(STARTAFT=C'<Name>',ENDBEFR=C'</Name>', FIXLEN=64)), BUILD=(1,4,%00,JFY=(SHIFT=LEFT,LEAD=C'<td>',TRAIL=C'</td>'))), IFTHEN=(WHEN=(8,80,SS,EQ,C'<Description>'), PARSE=(%01=(STARTAFT=C'<Description>',ENDBEFR=C'</Description>', FIXLEN=64)), BUILD=(1,4,%01,JFY=(SHIFT=LEFT,LEAD=C'<td>',TRAIL=C'</td>'))), IFTHEN=(WHEN=(8,80,SS,EQ,C'<ResourceNames>'), BUILD=(1,4,C'<td><ul>')), IFTHEN=(WHEN=(8,80,SS,EQ,C'<ResourceName>'), BUILD=(1,4,C'<li>')), IFTHEN=(WHEN=(18,6,CH,EQ,C'<Name>'), PARSE=(%02=(STARTAFT=C'<Name>',ENDBEFR=C'</Name>', FIXLEN=64)), BUILD=(1,4,%02)), IFTHEN=(WHEN=(8,80,SS,EQ,C'<RequiredState>'), PARSE=(%03=(STARTAFT=C'<RequiredState>', ENDBEFR=C'</RequiredState>', FIXLEN=64)), BUILD=(1,4,%03)), IFTHEN=(WHEN=(8,80,SS,EQ,C'</ResourceName>'), BUILD=(1,4,C'</li>')), IFTHEN=(WHEN=(8,80,SS,EQ,C'</ResourceNames>'), BUILD=(1,4,C'</ul></td>')), IFTHEN=(WHEN=(8,80,SS,EQ,C'</SchedulingEnvironment>'), BUILD=(1,4,C'</tr>')), TRAILER1=('</table>',/,'</body>',/,'</html>')
The best way to read this is as a sequence of two steps:
- INREC
- OUTFIL
There’s also a COPY as we’re not sorting, just preserving record order.
INREC
This statement uses WHEN=GROUP to label all records not between the <SchedulingEnvironment> and </SchedulingEnvironment> lines in the XML stream. The label is a sequence number:”PUSH=5:ID=3″ says “overlay position 5 (just after the RDW) with 3 bytes of sequence number, the sequence number incrementing for each group of records. (The “BUILD=1,4,3X,5” beforehand says “insert 3 blanks between the 4-byte RDW and the first byte of actual data”.)
So any line in the input file not in a <SchedulingEnvironment> element have no such tag. For the ones that have a tag we have sequence numbers “000”,”001″ etc. As we’ll see this is wide enough for 99 distinct scheduling environments – and can be adapted if you have more.
OUTFIL
This statement throws away records that aren’t part of a group (and so aren’t within a <SchedulingEnvironment> element), reformats the contents of each <SchedulingEnvironment> element and wraps header and trailer HTML around the result.
“INCLUDE=(5,1,CH,EQ,C’0′)” says “keep records that were tagged as part of a <SchedulingEnvironment> element in the INREC statement”.
“REMOVECC” prevents OUTFIL from writing ANSI carriage-control characters.
“HEADER1” and “TRAILER1” write “boilerplate” HTML.
The remainder – the IFTHEN “pipeline” – does the bulk of the work…
There are several IFTHEN “stages”. Note: If “HIT=NEXT” had been coded on any of them records matching the “WHEN=” clauses would be passed onto the next IFTHEN “stage”, In that sense it would be a true pipeline. In this case I didn’t code “HIT=NEXT” – as each matching “WHEN=” is the only one I want to operate on the matched record.
There are several distinct types of IFTHEN “stage”:
- Ones like
IFTHEN=(WHEN=(8,80,SS,EQ,C'<SchedulingEnvironment>'), BUILD=(1,4,C'<tr>')),
which is a substring search, with a literal replacement string. “Substring search” means “find the match ANYWHERE in the character range”.
- Ones like
IFTHEN=(WHEN=(14,6,CH,EQ,C'<Name>'), PARSE=(%00=(STARTAFT=C'<Name>',ENDBEFR=C'</Name>', FIXLEN=64)), BUILD=(1,4,%00,JFY=(SHIFT=LEFT,LEAD=C'<td>',TRAIL=C'</td>'))),
This one has a simple search – for a specific string in a particular position. But it also has a free-format parsing:
PARSE fills a variable (%00) with whatever is between “<Name>” and “</Name>”, now matter how wide or how narrow (subject to a limit of 64 characters – the FIXLEN value).This variable is used in the BUILD specification.
BUILD uses the new JFY (APAR UK00013) function to sandwich the contents of %00 between “<td>” and “</td>”, removing any trailing spaces.
- Ones like
IFTHEN=(WHEN=(8,80,SS,EQ,C'<RequiredState>'), PARSE=(%03=(STARTAFT=C'<RequiredState>', ENDBEFR=C'</RequiredState>', FIXLEN=64)), BUILD=(1,4,%03)),
which are a hybrid of the two.
Input Data
Disregarding the lines in the XML file that will ultimately be thrown away we have
<SchedulingEnvironment> <Name>DB2P</Name> <Description>Run for DB2P</Description> <ResourceNames> <ResourceName> <Name>DB2P</Name> <RequiredState>On</RequiredState> </ResourceName> </ResourceNames> </SchedulingEnvironment>
You’ll notice two different uses of the <Name> element. To distinguish between those the IFTHEN “stages” for the two use fixed offsets: e.g “WHEN=(18,6,CH,EQ,C'<Name>’)”.
Output HTML
For that one <SchedulingEnvironment> the code produces:
<html><body><h1>Scheduling Environments</h1><table border="1"><tr><th>Name</th><th>Description</th><th>Resources Required</th></tr><tr><td>DB2P</td><td>Run for DB2P</td>
<td><ul><li>DB2POn</li></ul></td></tr></table></body></html>
which ultimately formats as
Name | Description | Resources Required |
---|---|---|
DB2P | Run for DB2P |
|
though I’ve taken out the <html>, </html>, <body>, </body>, <h1> and </h1> tags – to make this blog entry format a little better.
So, admittedly this looks complex but if you pick through it should all make sense. If you’re lucky enough to have the PTFs on (and the latest is from July 2008) or are on z/OS Release 10 you can try this out and adapt the techniques for other parts of the WLM XML Service Definition or indeed other pieces of XML.
One other thing: In this example the <ResourceName> elements relate to a different part of the Service Definition, which looks like:
<Resources> <Resource> <Name>DB2P</Name> <Description>Subsystem DB2P</Description> </Resource> </Resources>
which I haven’t attempted to look up in the above code sample. To do it I think I’d be tempted to create 2 flat files – one from <SchedulingEnvironment> elements and one from <ResourceName> elements – and then use ICETOOL SPLICE to fold them in. And then emit HTML by reformatting the result.
But then this blog entry is quite long enough as it is. 🙂
One thought on “Workload Manager Policy in XML Format – Part IV”