Cross References
For the last of these examples I'd like to return to an XML-to-RTF conversion.
So far I've only been using elements, although in the last example I did use the position of the element in the document tree to extract extra information. This extra information comes close to being attribute information.
In this example I'd like to go one step further and really use information contained in attributes. Let's look at the XML document first, Listing 19.16.
Figure 19.10 The generated table of contents.
|
Listing 19.16 XML Cookbook File 5 (Cross References)
|
1: <?xml version="1.0"> 2: <!ELEMENT doc (TITLE | SECTION)*> 3: <!ELEMENT SECTION (TITLE | PARA)*> 4: <!ELEMENT TITLE (#PCDATA)> 5: <!ELEMENT PARA (#PCDATA | NOTE | XREF)*> 6: <!ELEMENT NOTE (#PCDATA)> 7: <!ATTLIST NOTE ID ID #IMPLIED> 8: 9: <!ELEMENT XREF EMPTY> 10: <!ATTLIST XREF REF CDATA #IMPLIED> 11: ]> 12: <doc> 13: <TITLE>Test Document</TITLE> 14: <SECTION><TITLE>Starting</TITLE> 15: <PARA>This paragraph simply contains some text 16: (<NOTE ID="N1">Note 1 </NOTE> 17: this is an embedded note) that we will use to wrap the 18: note we're going to cross-reference.</PARA></SECTION> 19: <SECTION><TITLE>Going On</TITLE> 20: <PARA>In this second paragraph, we'll include a cross-reference 21: <XREF REF="N1"> to the previous note.</PARA> 22: </SECTION> 23: </DOC>
| There aren't any real surprises in the XML code, but note how in the DTD I have added an ID attribute to the NOTE element and created a new XREF element that has a REF attribute. In the document itself, the NOTE element has an ID attribute value of N1 and this is the same value given to the REF attribute of the XREF element. In the DSSSL style sheet I use this to extract the text contained inside the NOTE. The DSSSL style sheet is shown in Listing 19.17. |
|
Listing 19.17 DSSSL Cookbook File 5 (Cross References)
|
1: <!DOCTYPE style-sheet 2 PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN"> 3: <!DOCTYPE style-sheet 4: PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN"> 5: 6: (define debug 7: (external-procedure "UNREGISTERED::James Clark//Procedure::debug")) 8: 9: (element doc 10: (make simple-page-sequence 11: page-width: 15cm 12: page-height: 20cm 13: left-margin: .5cm 14: right-margin: .5cm 15: top-margin: 2cm 16: bottom-margin: 2cm 17: header-margin: 1cm 18: footer-margin: 1cm 19: center-footer: (make sequence 20: (literal "Page " ) 21: (page-number-sosofo)) 22: left-header: (with-mode head (make sequence 23: font-size: 10pt 24: line-spacing: 14pt 25: font-posture: 'italic 26: (process-first-descendant "TITLE"))))) 27: 28: (element PARA (make paragraph font-size: 14pt space-after: 5pt)) 29: 30: (element (DOC TITLE) (make paragraph font-size: 18pt 31: space-before: 6pt space-after: 10pt)) 32: (element (SECTION TITLE) (make paragraph font-size: 14pt 33: space-before: 6pt space-after: 10pt)) 34: 35: (mode head 36: (element TITLE 37: (make paragraph font-size: 10pt space-before: 6pt 38: space-after: 10pt))) 39: 40: (element NOTE 41: (make sequence 42: font-posture: 'italic 43: font-size: 12pt 44: (process-children))) 45: 46: (element XREF 47: (make sequence 48: (literal "(see ") 49: (with-mode #f (process-children-trim))) 50: (process-element-with-id 51: (attribute-string "REF")) 52: (literal ")")))
| To get the XREF element to show the string 'Note 1', which it extracts from the NOTE element with the matching ID attribute value, I use the following specification: |
(element XREF
(make sequence
(literal "(see ")
(with-mode #f (process-children-trim)))
(process-element-with-id
(attribute-string "REF"))
(literal ")")))
I'm using a mode, or rather explicitly not using a mode, so I set with-mode to false (#f). I then process the element with the id (process-element-id) that matches the value in the string in the REF attribute (attribute-string "REF"). Notice that I use process-children-trim instead of just process-children; this trims off any extra spaces, tabs, or carriage returns around the string I'm extracting.
There are two more things I snuck in at the last moment, a page header and a footer.
The footer is extremely easy because a simple-page-sequence already has three footer characteristics. All I have to do is choose the one I want and attach another ready-made flow object, a page-number-sosofo:
center-footer: (make sequence
(literal "Page " )
(page-number-sosofo))
I thought I'd be a little more adventurous with the page header, so I created a mode to format the document's title element:
(mode head
(element TITLE
(make paragraph font-size: 10pt space-before: 6pt
space-after: 10pt)))
The mode itself is nothing special-it's just enough to give some basic formatting to the text. The real work is done in specifying the appropriate header characteristic, which is where I call the mode:
left-header: (with-mode head (make sequence
font-size: 10pt
line-spacing: 14pt
font-posture: 'italic
(process-first-descendant "TITLE")))
We're done. This is an XML-to-RTF conversion, so we can skip looking at the RTF code and just look at the layout when it's loaded into Microsoft Word (believe me, the header and footer are there even if you can't see them), shown in Figure 19.11.
Figure 19.11 RTF cookbook file 5 displayed (Cross References).