[Previous] [Contents] [Next]


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).

[Previous] [Contents] [Next]