added initial DOM XML filter documentation. Much is missing yet ...
[idzebra-moved-to-github.git] / doc / recordmodel-alvisxslt.xml
1  <chapter id="record-model-alvisxslt">
2   <!-- $Id: recordmodel-alvisxslt.xml,v 1.16 2007-02-20 14:28:31 marc Exp $ -->
3   <title>ALVIS &xml; Record Model and Filter Module</title>
4
5      <note>
6       <para>
7         The functionality of this record model has been improved and
8         replaced by the DOM &xml; record model. See 
9         <xref linkend="record-model-domxml"/>.
10       </para>
11      </note>  
12
13   <para>
14    The record model described in this chapter applies to the fundamental,
15    structured &xml;
16    record type <literal>alvis</literal>, introduced in
17    <xref linkend="componentmodulesalvis"/>.
18   </para>
19
20   <para> This filter has been developed under the 
21    <ulink url="http://www.alvis.info/">ALVIS</ulink> project funded by
22    the European Community under the "Information Society Technologies"
23    Program (2002-2006).
24   </para>
25   
26   
27   <section id="record-model-alvisxslt-filter">
28    <title>ALVIS Record Filter</title>
29    <para>
30     The experimental, loadable  Alvis &xml;/&xslt; filter module
31    <literal>mod-alvis.so</literal> is packaged in the GNU/Debian package
32     <literal>libidzebra1.4-mod-alvis</literal>.
33     It is invoked by the <filename>zebra.cfg</filename> configuration statement
34     <screen>
35      recordtype.xml: alvis.db/filter_alvis_conf.xml
36     </screen>
37     In this example on all data files with suffix 
38     <filename>*.xml</filename>, where the
39     Alvis &xslt; filter configuration file is found in the
40     path <filename>db/filter_alvis_conf.xml</filename>.
41    </para>
42    <para>The Alvis &xslt; filter configuration file must be
43     valid &xml;. It might look like this (This example is
44     used for indexing and display of &oai; harvested records):
45     <screen>
46     &lt;?xml version="1.0" encoding="UTF-8"?&gt;
47       &lt;schemaInfo&gt;
48         &lt;schema name="identity" stylesheet="xsl/identity.xsl" /&gt;
49         &lt;schema name="index" identifier="http://indexdata.dk/zebra/xslt/1"
50             stylesheet="xsl/oai2index.xsl" /&gt;
51         &lt;schema name="dc" stylesheet="xsl/oai2dc.xsl" /&gt;
52         &lt;!-- use split level 2 when indexing whole &oai; Record lists --&gt;
53         &lt;split level="2"/&gt;
54       &lt;/schemaInfo&gt;
55     </screen> 
56    </para>
57    <para>
58     All named stylesheets defined inside
59     <literal>schema</literal> element tags 
60     are for presentation after search, including
61     the indexing stylesheet (which is a great debugging help). The
62     names defined in the <literal>name</literal> attributes must be
63     unique, these are the literal <literal>schema</literal> or 
64     <literal>element set</literal> names used in 
65       <ulink url="http://www.loc.gov/standards/sru/srw/">&srw;</ulink>,
66       <ulink url="&url.sru;">&sru;</ulink> and
67     &z3950; protocol queries.
68     The paths in the <literal>stylesheet</literal> attributes
69     are relative to zebras working directory, or absolute to file
70     system root.
71    </para>
72    <para>
73     The <literal>&lt;split level="2"/&gt;</literal> decides where the
74     &xml; Reader shall split the
75     collections of records into individual records, which then are
76     loaded into &dom;, and have the indexing &xslt; stylesheet applied.
77    </para>
78    <para>
79     There must be exactly one indexing &xslt; stylesheet, which is
80     defined by the magic attribute  
81     <literal>identifier="http://indexdata.dk/zebra/xslt/1"</literal>.
82    </para>
83
84    <section id="record-model-alvisxslt-internal">
85     <title>ALVIS Internal Record Representation</title>   
86     <para>When indexing, an &xml; Reader is invoked to split the input
87     files into suitable record &xml; pieces. Each record piece is then
88     transformed to an &xml; &dom; structure, which is essentially the
89     record model. Only &xslt; transformations can be applied during
90     index, search and retrieval. Consequently, output formats are
91     restricted to whatever &xslt; can deliver from the record &xml;
92     structure, be it other &xml; formats, HTML, or plain text. In case
93     you have <literal>libxslt1</literal> running with E&xslt; support,
94     you can use this functionality inside the Alvis
95     filter configuration &xslt; stylesheets.
96     </para>
97    </section>
98
99    <section id="record-model-alvisxslt-canonical">
100     <title>ALVIS Canonical Indexing Format</title>   
101     <para>The output of the indexing &xslt; stylesheets must contain
102     certain elements in the magic 
103      <literal>xmlns:z="http://indexdata.dk/zebra/xslt/1"</literal>
104     namespace. The output of the &xslt; indexing transformation is then
105     parsed using &dom; methods, and the contained instructions are
106     performed on the <emphasis>magic elements and their
107     subtrees</emphasis>.
108     </para>
109     <para>
110     For example, the output of the command
111      <screen>  
112       xsltproc xsl/oai2index.xsl one-record.xml
113      </screen> 
114      might look like this:
115      <screen>
116       &lt;?xml version="1.0" encoding="UTF-8"?&gt;
117       &lt;z:record xmlns:z="http://indexdata.dk/zebra/xslt/1" 
118            z:id="oai:JTRS:CP-3290---Volume-I" 
119            z:rank="47896"
120            z:type="update"&gt;
121        &lt;z:index name="oai_identifier" type="0"&gt;
122                 oai:JTRS:CP-3290---Volume-I&lt;/z:index&gt;
123        &lt;z:index name="oai_datestamp" type="0"&gt;2004-07-09&lt;/z:index&gt;
124        &lt;z:index name="oai_setspec" type="0"&gt;jtrs&lt;/z:index&gt;
125        &lt;z:index name="dc_all" type="w"&gt;
126           &lt;z:index name="dc_title" type="w"&gt;Proceedings of the 4th 
127                 International Conference and Exhibition:
128                 World Congress on Superconductivity - Volume I&lt;/z:index&gt;
129           &lt;z:index name="dc_creator" type="w"&gt;Kumar Krishen and *Calvin
130                 Burnham, Editors&lt;/z:index&gt;
131        &lt;/z:index&gt;
132      &lt;/z:record&gt;
133      </screen>
134     </para>
135     <para>This means the following: From the original &xml; file 
136      <literal>one-record.xml</literal> (or from the &xml; record &dom; of the
137      same form coming from a splitted input file), the indexing
138      stylesheet produces an indexing &xml; record, which is defined by
139      the <literal>record</literal> element in the magic namespace
140      <literal>xmlns:z="http://indexdata.dk/zebra/xslt/1"</literal>.
141      &zebra; uses the content of 
142      <literal>z:id="oai:JTRS:CP-3290---Volume-I"</literal> as internal
143      record ID, and - in case static ranking is set - the content of 
144      <literal>z:rank="47896"</literal> as static rank. Following the
145      discussion in <xref linkend="administration-ranking"/>
146      we see that this records is internally ordered
147      lexicographically according to the value of the string
148      <literal>oai:JTRS:CP-3290---Volume-I47896</literal>.
149      The type of action performed during indexing is defined by
150      <literal>z:type="update"&gt;</literal>, with recognized values
151      <literal>insert</literal>, <literal>update</literal>, and 
152      <literal>delete</literal>. 
153     </para>
154     <para>In this example, the following literal indexes are constructed:
155      <screen>
156        oai_identifier
157        oai_datestamp
158        oai_setspec
159        dc_all
160        dc_title
161        dc_creator
162      </screen>
163      where the indexing type is defined in the 
164      <literal>type</literal> attribute 
165      (any value from the standard configuration
166      file <filename>default.idx</filename> will do). Finally, any 
167      <literal>text()</literal> node content recursively contained
168      inside the <literal>index</literal> will be filtered through the
169      appropriate charmap for character normalization, and will be
170      inserted in the index.
171     </para>
172     <para>
173      Specific to this example, we see that the single word
174      <literal>oai:JTRS:CP-3290---Volume-I</literal> will be literal,
175      byte for byte without any form of character normalization,
176      inserted into the index named <literal>oai:identifier</literal>,
177      the text 
178      <literal>Kumar Krishen and *Calvin Burnham, Editors</literal>
179      will be inserted using the <literal>w</literal> character
180      normalization defined in <filename>default.idx</filename> into
181      the index <literal>dc:creator</literal> (that is, after character
182      normalization the index will keep the inidividual words 
183      <literal>kumar</literal>, <literal>krishen</literal>, 
184      <literal>and</literal>, <literal>calvin</literal>,
185      <literal>burnham</literal>, and <literal>editors</literal>), and
186      finally both the texts
187      <literal>Proceedings of the 4th International Conference and Exhibition:
188       World Congress on Superconductivity - Volume I</literal> 
189      and
190      <literal>Kumar Krishen and *Calvin Burnham, Editors</literal> 
191      will be inserted into the index <literal>dc:all</literal> using
192      the same character normalization map <literal>w</literal>. 
193     </para>
194     <para>
195      Finally, this example configuration can be queried using &pqf;
196      queries, either transported by &z3950;, (here using a yaz-client) 
197      <screen>
198       <![CDATA[
199       Z> open localhost:9999
200       Z> elem dc
201       Z> form xml
202       Z>
203       Z> f @attr 1=dc_creator Kumar
204       Z> scan @attr 1=dc_creator adam
205       Z>
206       Z> f @attr 1=dc_title @attr 4=2 "proceeding congress superconductivity"
207       Z> scan @attr 1=dc_title abc
208       ]]>
209      </screen>
210      or the proprietary
211      extentions <literal>x-pquery</literal> and
212      <literal>x-pScanClause</literal> to
213      &sru;, and &srw;
214      <screen>
215       <![CDATA[
216       http://localhost:9999/?version=1.1&operation=searchRetrieve&x-pquery=%40attr+1%3Ddc_creator+%40attr+4%3D6+%22the
217       http://localhost:9999/?version=1.1&operation=scan&x-pScanClause=@attr+1=dc_date+@attr+4=2+a
218       ]]>
219      </screen>
220      See <xref linkend="zebrasrv-sru"/> for more information on &sru;/&srw;
221      configuration, and <xref linkend="gfs-config"/> or the &yaz;
222      <ulink url="&url.yaz.cql;">&cql; section</ulink>
223      for the details or the &yaz; frontend server.
224     </para>
225     <para>
226      Notice that there are no <filename>*.abs</filename>,
227      <filename>*.est</filename>, <filename>*.map</filename>, or other &grs1;
228      filter configuration files involves in this process, and that the
229      literal index names are used during search and retrieval.
230     </para>
231    </section>
232   </section>
233
234
235   <section id="record-model-alvisxslt-conf">
236    <title>ALVIS Record Model Configuration</title>
237
238
239   <section id="record-model-alvisxslt-index">
240    <title>ALVIS Indexing Configuration</title>
241     <para>
242      As mentioned above, there can be only one indexing
243      stylesheet, and configuration of the indexing process is a synonym
244      of writing an &xslt; stylesheet which produces &xml; output containing the
245      magic elements discussed in  
246      <xref linkend="record-model-alvisxslt-internal"/>. 
247      Obviously, there are million of different ways to accomplish this
248      task, and some comments and code snippets are in order to lead
249      our paduans on the right track to the  good side of the force.
250     </para>
251     <para>
252      Stylesheets can be written in the <emphasis>pull</emphasis> or
253      the <emphasis>push</emphasis> style: <emphasis>pull</emphasis>
254      means that the output &xml; structure is taken as starting point of
255      the internal structure of the &xslt; stylesheet, and portions of
256      the input &xml; are <emphasis>pulled</emphasis> out and inserted
257      into the right spots of the output &xml; structure. On the other
258      side, <emphasis>push</emphasis> &xslt; stylesheets are recursavly
259      calling their template definitions, a process which is commanded
260      by the input &xml; structure, and avake to produce some output &xml;
261      whenever some special conditions in the input styelsheets are
262      met. The <emphasis>pull</emphasis> type is well-suited for input
263      &xml; with strong and well-defined structure and semantcs, like the
264      following &oai; indexing example, whereas the
265      <emphasis>push</emphasis> type might be the only possible way to
266      sort out deeply recursive input &xml; formats.
267     </para>
268     <para> 
269      A <emphasis>pull</emphasis> stylesheet example used to index
270      &oai; harvested records could use some of the following template
271      definitions:
272      <screen>
273       <![CDATA[
274       <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
275        xmlns:z="http://indexdata.dk/zebra/xslt/1"
276        xmlns:oai="http://www.openarchives.org/&oai;/2.0/" 
277        xmlns:oai_dc="http://www.openarchives.org/&oai;/2.0/oai_dc/" 
278        xmlns:dc="http://purl.org/dc/elements/1.1/"
279        version="1.0">
280
281        <xsl:output indent="yes" method="xml" version="1.0" encoding="UTF-8"/>
282
283         <!-- disable all default text node output -->
284         <xsl:template match="text()"/>
285
286          <!-- match on oai xml record root -->
287          <xsl:template match="/">    
288           <z:record z:id="{normalize-space(oai:record/oai:header/oai:identifier)}" 
289            z:type="update">
290            <!-- you might want to use z:rank="{some &xslt; function here}" --> 
291            <xsl:apply-templates/>
292           </z:record>
293          </xsl:template>
294
295          <!-- &oai; indexing templates -->
296          <xsl:template match="oai:record/oai:header/oai:identifier">
297           <z:index name="oai_identifier" type="0">
298            <xsl:value-of select="."/>
299           </z:index>    
300          </xsl:template>
301
302          <!-- etc, etc -->
303
304          <!-- DC specific indexing templates -->
305          <xsl:template match="oai:record/oai:metadata/oai_dc:dc/dc:title">
306           <z:index name="dc_title" type="w">
307            <xsl:value-of select="."/>
308           </z:index>
309          </xsl:template>
310
311          <!-- etc, etc -->
312  
313       </xsl:stylesheet>
314       ]]>
315      </screen>
316     </para>
317     <para>
318      Notice also,
319      that the names and types of the indexes can be defined in the
320      indexing &xslt; stylesheet <emphasis>dynamically according to
321      content in the original &xml; records</emphasis>, which has
322      opportunities for great power and wizardery as well as grande
323      disaster.  
324     </para>
325     <para>
326      The following excerpt of a <emphasis>push</emphasis> stylesheet
327      <emphasis>might</emphasis> 
328      be a good idea according to your strict control of the &xml;
329      input format (due to rigerours checking against well-defined and
330      tight RelaxNG or &xml; Schema's, for example):
331      <screen>
332       <![CDATA[
333       <xsl:template name="element-name-indexes">     
334        <z:index name="{name()}" type="w">
335         <xsl:value-of select="'1'"/>
336        </z:index>
337       </xsl:template>
338       ]]>
339      </screen>
340      This template creates indexes which have the name of the working 
341      node of any input  &xml; file, and assigns a '1' to the index.
342      The example query 
343      <literal>find @attr 1=xyz 1</literal> 
344      finds all files which contain at least one
345      <literal>xyz</literal> &xml; element. In case you can not control
346      which element names the input files contain, you might ask for
347      disaster and bad karma using this technique.
348     </para>
349     <para>
350      One variation over the theme <emphasis>dynamically created
351      indexes</emphasis> will definitely be unwise:
352      <screen>
353       <![CDATA[  
354       <!-- match on oai xml record root -->
355       <xsl:template match="/">    
356        <z:record z:type="update">
357       
358         <!-- create dynamic index name from input content --> 
359         <xsl:variable name="dynamic_content">
360          <xsl:value-of select="oai:record/oai:header/oai:identifier"/>
361         </xsl:variable>
362         
363         <!-- create zillions of indexes with unknown names -->
364         <z:index name="{$dynamic_content}" type="w">
365          <xsl:value-of select="oai:record/oai:metadata/oai_dc:dc"/>
366         </z:index>          
367        </z:record>
368        
369       </xsl:template>
370       ]]>
371      </screen>
372      Don't be tempted to cross
373      the line to the dark side of the force, paduan; this leads
374      to suffering and pain, and universal
375      disentigration of your project schedule.
376     </para>
377   </section>
378
379   <section id="record-model-alvisxslt-elementset">
380    <title>ALVIS Exchange Formats</title>
381    <para>
382      An exchange format can be anything which can be the outcome of an
383      &xslt; transformation, as far as the stylesheet is registered in
384      the main Alvis &xslt; filter configuration file, see
385      <xref linkend="record-model-alvisxslt-filter"/>.
386      In principle anything that can be expressed in  &xml;, HTML, and
387      TEXT can be the output of a <literal>schema</literal> or 
388     <literal>element set</literal> directive during search, as long as
389      the information comes from the 
390      <emphasis>original input record &xml; &dom; tree</emphasis>
391      (and not the transformed and <emphasis>indexed</emphasis> &xml;!!).
392     </para>
393     <para>
394      In addition, internal administrative information from the &zebra;
395      indexer can be accessed during record retrieval. The following
396      example is a summary of the possibilities:
397      <screen>
398       <![CDATA[  
399       <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
400        xmlns:z="http://indexdata.dk/zebra/xslt/1"
401        version="1.0">
402
403        <!-- register internal zebra parameters -->       
404        <xsl:param name="id" select="''"/>
405        <xsl:param name="filename" select="''"/>
406        <xsl:param name="score" select="''"/>
407        <xsl:param name="schema" select="''"/>
408            
409        <xsl:output indent="yes" method="xml" version="1.0" encoding="UTF-8"/>
410
411        <!-- use then for display of internal information -->
412        <xsl:template match="/">
413          <z:zebra>
414            <id><xsl:value-of select="$id"/></id>
415            <filename><xsl:value-of select="$filename"/></filename>
416            <score><xsl:value-of select="$score"/></score>
417            <schema><xsl:value-of select="$schema"/></schema>
418          </z:zebra>
419        </xsl:template>
420
421       </xsl:stylesheet>
422       ]]>
423      </screen>
424     </para>
425
426   </section>
427
428   <section id="record-model-alvisxslt-example">
429    <title>ALVIS Filter &oai; Indexing Example</title>
430    <para>
431      The sourcecode tarball contains a working Alvis filter example in
432      the directory <filename>examples/alvis-oai/</filename>, which
433      should get you started.  
434     </para>
435     <para>
436      More example data can be harvested from any &oai; complient server,
437      see details at the  &oai; 
438      <ulink url="http://www.openarchives.org/">
439       http://www.openarchives.org/</ulink> web site, and the community
440       links at 
441      <ulink url="http://www.openarchives.org/community/index.html">
442       http://www.openarchives.org/community/index.html</ulink>.
443      There is a  tutorial
444      found at
445      <ulink url="http://www.oaforum.org/tutorial/">
446       http://www.oaforum.org/tutorial/</ulink>.
447     </para>
448    </section>
449
450   </section>
451
452   
453  </chapter>
454
455
456 <!--
457
458 c)  Main "alvis" &xslt; filter config file:
459   cat db/filter_alvis_conf.xml 
460
461   <?xml version="1.0" encoding="UTF8"?>
462   <schemaInfo>
463     <schema name="alvis" stylesheet="db/alvis2alvis.xsl" />
464     <schema name="index" identifier="http://indexdata.dk/zebra/xslt/1"
465             stylesheet="db/alvis2index.xsl" />
466     <schema name="dc" stylesheet="db/alvis2dc.xsl" />
467     <schema name="dc-short" stylesheet="db/alvis2dc_short.xsl" />
468     <schema name="snippet" snippet="25" stylesheet="db/alvis2snippet.xsl" />
469     <schema name="help" stylesheet="db/alvis2help.xsl" />
470     <split level="1"/>
471   </schemaInfo>
472
473   the paths are relative to the directory where zebra.init is placed
474   and is started up.
475
476   The split level decides where the SAX parser shall split the
477   collections of records into individual records, which then are
478   loaded into &dom;, and have the indexing &xslt; stylesheet applied.
479
480   The indexing stylesheet is found by it's identifier.
481
482   All the other stylesheets are for presentation after search.
483
484 - in data/ a short sample of harvested carnivorous plants
485   ZEBRA_INDEX_DIRS=data/carnivor_20050118_2200_short-346.xml
486
487 - in root also one single data record - nice for testing the xslt
488   stylesheets,
489   
490   xsltproc db/alvis2index.xsl carni*.xml
491
492   and so on.
493
494 - in db/ a cql2pqf.txt yaz-client config file 
495   which is also used in the yaz-server <ulink url="&url.cql;">&cql;</ulink>-to-&pqf; process
496
497    see: http://www.indexdata.com/yaz/doc/tools.tkl#tools.cql.map
498
499 - in db/ an indexing &xslt; stylesheet. This is a PULL-type XSLT thing,
500   as it constructs the new &xml; structure by pulling data out of the
501   respective elements/attributes of the old structure.
502
503   Notice the special zebra namespace, and the special elements in this
504   namespace which indicate to the zebra indexer what to do.
505
506   <z:record id="67ht7" rank="675" type="update">
507   indicates that a new record with given id and static rank has to be updated. 
508
509   <z:index name="title" type="w">
510    encloses all the text/&xml; which shall be indexed in the index named
511    "title" and of index type "w" (see  file default.idx in your zebra
512    installation) 
513
514
515    </para>
516
517    <para>
518 -->
519
520
521
522
523  <!-- Keep this comment at the end of the file
524  Local variables:
525  mode: sgml
526  sgml-omittag:t
527  sgml-shorttag:t
528  sgml-minimize-attributes:nil
529  sgml-always-quote-attributes:t
530  sgml-indent-step:1
531  sgml-indent-data:t
532  sgml-parent-document: "zebra.xml"
533  sgml-local-catalogs: nil
534  sgml-namecase-general:t
535  End:
536  -->