Creating lists (XML structure)
In the previous chapter, lists were created using markers. In this chapter a mechanism is used which means a bit more manual work, but is more flexible.
The speedata Publisher can create any type of list or index. Whether table of contents, article list or keyword index - all lists work on the same principle: the necessary data (e.g. page numbers, article numbers) are explicitly stored in a separate data structure, written to disk. The next time the Publisher is run, this data is read in and is available.
Step 1: Collecting the information
The two commands <Element>
and <Attribute>
are used to structure data that is read during processing.
This has already been described in the chapter elementattribute
.
These commands can be used to create new XML data set files.
The following structure could be useful for an article list:
<articlelist>
<article number="1" page="10"/>
<article number="2" page="12"/>
<article number="3" page="14"/>
</articlelist>
To create this structure in the layout rules, it must be composed of the commands <Element> and <Attributes> as follows
<Element name="articlelist">
<Element name="article">
<Attribute name="number" select="1"/>
<Attribute name="page" select="10"/>
</Element>
<Element name="article">
<Attribute name="number" select="2"/>
<Attribute name="page" select="12"/>
</Element>
<Element name="article">
<Attribute name="number" select="3"/>
<Attribute name="page" select="14"/>
</Element>
</Element>
Step 2: Saving and loading the information
With the command <SaveDataset>
this structure is saved to disk and with <LoadDataset>
it is loaded again.
If the file does not exist when loading, no error is reported, because it could be the first pass where the file naturally does not yet exist.
Step 3: Processing the information
Immediately after loading, XML processing is continued with the first element of the currently loaded structure. In the example above, the following command would be searched for in the layout ruleset
<Record element="articlelist">
...
</Record>
This means that the actual data processing is temporarily interrupted and continued with the new data set from <LoadDataset>
.
Example
This is the same example as in the previous section (directories-marker ). A simple data file is used as an example:
<data>
<chapter title="Foreword">
<text>...</text>
</chapter>
<chapter title="Introduction">
<text>...</text>
</chapter>
<chapter title="Conclusion">
<text>...</text>
</chapter>
</data>
Which is output with the following layout:
<Layout
xmlns="urn:speedata.de:2009/publisher/en"
xmlns:sd="urn:speedata:2009/publisher/functions/en">
<DefineFontfamily name="title" fontsize="18" leading="20">
<Regular fontface="sans"/>
</DefineFontfamily>
<!--1-->
<!--2-->
<Record element="data">
<ProcessNode select="chapter"/>
</Record>
<Record element="chapter">
<!--3-->
<PlaceObject>
<Textblock>
<Paragraph fontfamily="title">
<Value select="@title"/>
</Paragraph>
<Paragraph>
<Value select="text"/>
</Paragraph>
</Textblock>
</PlaceObject>
<ClearPage/>
</Record>
</Layout>
- The output of the actual table of contents is inserted here.
- The section ‘data’ is extended by loading and saving the XML data for the directory
- Here code is inserted that assembles the XML structure (see below)
Now a variable is defined (entries), which contains the information about the chapter beginnings.
The target structure should be as follows:
<tableofcontent>
<entry chaptername="Foreword" page="2"/>
<entry chaptername="Introduction" page="3"/>
<entry chaptername="Conclusion" page="4"/>
</tableofcontent>
In the chapter section (point 3 in the layout above) the code is inserted at the top to fill the variable entries with the contents:
<Record element="chapter">
<SetVariable variable="entries">
<Copy-of select="$entries"/>
<Element name="entry">
<Attribute name="chaptername" select="@title"/>
<Attribute name="page" select="sd:current-page()"/>
</Element>
</SetVariable>
<PlaceObject>
...
Thus, something new is added to a variable using <Copy-of>.
The structure must be loaded at the beginning and saved at the end of the run to ensure that it is always up-to-date.
If the file toc does not yet exist, the command is simply skipped.
The new section data now looks like this and is inserted at position 2 in the layout above (instead of the record existing there)
<Record element="data">
<LoadDataset name="toc"/>
<SetVariable variable="entries"/>
<ProcessNode select="chapter"/>
<SaveDataset name="toc" elementname="tableofcontents"
select="$entries"/>
</Record>
On the next run, the command <LoadDataset> takes effect and opens the previously saved XML file.
The layout ruleset searches for a section for the tableofcontents element, which is the root element of the saved file.
This has to be added to the layout rules (position 1 in the layout above):
<Record element="tableofcontents">
<PlaceObject>
<Table padding="5pt">
<ForAll select="entry">
<Tr>
<Td><Paragraph><Value select="@chaptername"/></Paragraph></Td>
<Td><Paragraph><Value select="@page"/></Paragraph></Td>
</Tr>
</ForAll>
</Table>
</PlaceObject>
<ClearPage/>
</Record>
A table is output with one line for each child element entry.
The subsequent page break shifts the subsequent text backwards.
This means that you have to run through the document three times before the table of contents is correct:
- In the first pass, the data structure is compiled.
- Afterwards the table of contents can be created, the page break shifts the content one page backwards, the data structure is updated accordingly.
- Only in the third pass is the table of contents correct.
If you know that the table of contents will only take up one page, you can insert the page break in the first pass. This saves you one pass.
