This tutorial is based on the style-sheet play.dsl posted by an Anonymous author and posted by Jon Bosak. It is rather simplistic and not very well documented, but it should be understandable.
Paul Prescod has published another DSSSL tutorial which can be found at: http://itrc.uwaterloo.ca/~papresco/dsssl/tutorial.html. His tutorial is more detailed and does not assume Scheme knowledge.
The objective of the tutorial is to introduce you to the basics of DSSSL. We will build a DSSSL style-sheet for plays (based on the one posted by Jon Bosak (play.dsl).
You can download a copy of the examples from:
We already have a SGML file and its DTD. The first step is to generate an RTF file with all the text of the play, without any format:
; This dumps the text of the plays without any particular format (root (make simple-page-sequence (process-children)) )
The RTF file is just a sequence of characters. No margins, no paragraphs. It uses the Jade's defaults for the font family, font size, page size, etc.
(root
(make simple-page-sequence
; margins
left-margin: 1in
right-margin: 1in
top-margin: 1in
bottom-margin: 1in
(process-children))
)
We will work top-down, adding format as we encounter elements in the SGML file.
(element (PLAY TITLE) ;the play's title
(make paragraph
quadding: 'center
font-size: 18pt
line-spacing: 18pt
font-weight: 'bold
keep-with-next?: #t
(process-children)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Front matter
;
(element (FM)
(make paragraph
font-size: 8pt
line-spacing: 8pt
; left and right indentation
start-indent: 5cm
end-indent: 5cm
; space before
space-before: .5cm
; space after
space-after: .5cm
(process-children)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Adding constants
(define *titleFontSize* 18pt)
(define *fmFontSize* (/ *titleFontSize* 2))
(define *fmIndent* 3cm)
(define *fmSpaceBefore* .5cm)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; TITLE of the PLAY
(element (PLAY TITLE)
(make paragraph
quadding: 'center
font-size: *titleFontSize*
line-spacing: *titleFontSize*
font-weight: 'bold
keep-with-next?: #t
(process-children)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Front matter
;
(element (FM)
(make paragraph
font-size: *fmFontSize*
line-spacing: *fmFontSize*
; left and right indentation
start-indent: *fmIndent*
end-indent: *fmIndent*
; space before
space-before: *fmSpaceBefore*
; space after
space-after: *fmSpaceBefore*
(process-children)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PERSONAE
(element PERSONAE
(process-children))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PERSONA
(element PERSONA ;a person
(make paragraph
space-before: *personaSpaceBefore*
start-indent: *personaIndent*
(process-children)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; TITLE inside PERSONAE
(element (PERSONAE TITLE)
(make paragraph
font-size: *personaetitleFontSize*
line-spacing: *personaetitleFontSize*
font-weight: 'bold
keep-with-next?: #t
(process-children)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PGROUP
; We have to extract the description of the group (located
; at the end of the PGROUP, and displayed at _the beginning_
(define (*groupName*)
; First set x to GRPDESCR content
(let ((x
(data (select-elements (children (if (equal? (gi) "PGROUP")
(current-node)
(ancestor "PGROUP")))
'(GRPDESCR))))
)
; if x ends in "." drop the latter. then concatenate ":"
(string-append
(if (string=?
(substring x (- (string-length x) 1) (string-length x))
".")
(substring x 0 (- (string-length x) 1))
x)
":"
)
)
)
(element PGROUP
(make paragraph
start-indent: *personaIndent*
space-before: *textSpaceBefore*
font-weight: 'bold
(literal (*groupName*))
(process-children)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; PERSONA inside a PGROUP
(element (PGROUP PERSONA )
(make paragraph
space-before: *personaSpaceBefore*
start-indent: *pgroupIndent*
font-weight: #f
(process-children)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; GRPDESCR
; it has been extracted, so ignore
(element GRPDESCR
(empty-sosofo))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Scndescr
(define *sceneStyle* ;style for all scene descriptions
(style
quadding: 'center
font-size: (+ *textFontSize* 4pt)
line-spacing: *textFontSize*
font-weight: #f
font-posture: 'italic
start-indent: *sceneIndent*
end-indent: *sceneIndent*))
(element SCNDESCR
(make paragraph
use: *sceneStyle*
space-before: *sceneSpaceBefore*
(process-children)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; STAGEDIR
;
(element STAGEDIR
(make paragraph
font-posture: 'italic
; If it is inside a line or speech, don't put space-before, otherwise
; skip some space
space-before: (if (or (equal? (gi (parent)) "LINE")
(equal? (gi (parent)) "SPEECH"))
0pt
*textFontSize*)
; surround so not spoken accidentally
(literal "[")
(process-children)
(literal "]")))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SPEECH
(element SPEECH ;a set of lines by one or more speakers
(make table ;use a table to accommodate multiple speakers
space-before: (/ *textFontSize* 2)
may-violate-keep-after?: #t
(make table-column ;ensure speaker column is narrow
column-number: 1
width: *speakerWidth*)
(make table-cell ;collect all speakers
(make paragraph
(with-mode *speechSpeaker*
(process-matching-children "SPEAKER"))))
(make table-cell ;collect all lines and instructions
(process-children))))
(mode *speechSpeaker* ;collect all speakers into single column
(element SPEAKER ;separate with ampersands to indicate multiple
(if (= (child-number) 1)
(make sequence
font-posture: 'italic
(process-children))
(make sequence
font-posture: 'italic
(literal " & ")
(process-children))))
(default ;fail-safe - this should not trigger
(empty-sosofo)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; SPEAKER
; This has been taken care of in speechSpeaker mode, therefore ignore in
; normal mode
(element SPEAKER ;this should not trigger - only in mode
(empty-sosofo))
(element LINE ;all of the lines for a given set of speakers
(make paragraph
(process-children)))
DSSSL is a complex language. I had outlined very few of its characteristics. Don't expect be an expert after understanding this tutorial. At this point you should have a feeling of what it can accomplish. Furthermore, you should be ready to take the draft of the Standard and better understand it.
Good luck!
If you have comments regarding this tutorial, please feel free to drop me a line at dmg@csg.uwaterloo.ca