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>
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"/>.
14 The record model described in this chapter applies to the fundamental,
16 record type <literal>alvis</literal>, introduced in
17 <xref linkend="componentmodulesalvis"/>.
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"
27 <section id="record-model-alvisxslt-filter">
28 <title>ALVIS Record Filter</title>
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
35 recordtype.xml: alvis.db/filter_alvis_conf.xml
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>.
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):
46 <?xml version="1.0" encoding="UTF-8"?>
48 <schema name="identity" stylesheet="xsl/identity.xsl" />
49 <schema name="index" identifier="http://indexdata.dk/zebra/xslt/1"
50 stylesheet="xsl/oai2index.xsl" />
51 <schema name="dc" stylesheet="xsl/oai2dc.xsl" />
52 <!-- use split level 2 when indexing whole &oai; Record lists -->
53 <split level="2"/>
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
73 The <literal><split level="2"/></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.
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>.
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.
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
110 For example, the output of the command
112 xsltproc xsl/oai2index.xsl one-record.xml
114 might look like this:
116 <?xml version="1.0" encoding="UTF-8"?>
117 <z:record xmlns:z="http://indexdata.dk/zebra/xslt/1"
118 z:id="oai:JTRS:CP-3290---Volume-I"
121 <z:index name="oai_identifier" type="0">
122 oai:JTRS:CP-3290---Volume-I</z:index>
123 <z:index name="oai_datestamp" type="0">2004-07-09</z:index>
124 <z:index name="oai_setspec" type="0">jtrs</z:index>
125 <z:index name="dc_all" type="w">
126 <z:index name="dc_title" type="w">Proceedings of the 4th
127 International Conference and Exhibition:
128 World Congress on Superconductivity - Volume I</z:index>
129 <z:index name="dc_creator" type="w">Kumar Krishen and *Calvin
130 Burnham, Editors</z:index>
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"></literal>, with recognized values
151 <literal>insert</literal>, <literal>update</literal>, and
152 <literal>delete</literal>.
154 <para>In this example, the following literal indexes are constructed:
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.
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>,
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>
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>.
195 Finally, this example configuration can be queried using &pqf;
196 queries, either transported by &z3950;, (here using a yaz-client)
199 Z> open localhost:9999
203 Z> f @attr 1=dc_creator Kumar
204 Z> scan @attr 1=dc_creator adam
206 Z> f @attr 1=dc_title @attr 4=2 "proceeding congress superconductivity"
207 Z> scan @attr 1=dc_title abc
211 extentions <literal>x-pquery</literal> and
212 <literal>x-pScanClause</literal> to
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
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.
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.
235 <section id="record-model-alvisxslt-conf">
236 <title>ALVIS Record Model Configuration</title>
239 <section id="record-model-alvisxslt-index">
240 <title>ALVIS Indexing Configuration</title>
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.
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.
269 A <emphasis>pull</emphasis> stylesheet example used to index
270 &oai; harvested records could use some of the following template
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/"
281 <xsl:output indent="yes" method="xml" version="1.0" encoding="UTF-8"/>
283 <!-- disable all default text node output -->
284 <xsl:template match="text()"/>
286 <!-- match on oai xml record root -->
287 <xsl:template match="/">
288 <z:record z:id="{normalize-space(oai:record/oai:header/oai:identifier)}"
290 <!-- you might want to use z:rank="{some &xslt; function here}" -->
291 <xsl:apply-templates/>
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="."/>
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="."/>
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
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):
333 <xsl:template name="element-name-indexes">
334 <z:index name="{name()}" type="w">
335 <xsl:value-of select="'1'"/>
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.
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.
350 One variation over the theme <emphasis>dynamically created
351 indexes</emphasis> will definitely be unwise:
354 <!-- match on oai xml record root -->
355 <xsl:template match="/">
356 <z:record z:type="update">
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"/>
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"/>
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.
379 <section id="record-model-alvisxslt-elementset">
380 <title>ALVIS Exchange Formats</title>
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;!!).
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:
399 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
400 xmlns:z="http://indexdata.dk/zebra/xslt/1"
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="''"/>
409 <xsl:output indent="yes" method="xml" version="1.0" encoding="UTF-8"/>
411 <!-- use then for display of internal information -->
412 <xsl:template match="/">
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>
428 <section id="record-model-alvisxslt-example">
429 <title>ALVIS Filter &oai; Indexing Example</title>
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.
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
441 <ulink url="http://www.openarchives.org/community/index.html">
442 http://www.openarchives.org/community/index.html</ulink>.
445 <ulink url="http://www.oaforum.org/tutorial/">
446 http://www.oaforum.org/tutorial/</ulink>.
458 c) Main "alvis" &xslt; filter config file:
459 cat db/filter_alvis_conf.xml
461 <?xml version="1.0" encoding="UTF8"?>
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" />
473 the paths are relative to the directory where zebra.init is placed
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.
480 The indexing stylesheet is found by it's identifier.
482 All the other stylesheets are for presentation after search.
484 - in data/ a short sample of harvested carnivorous plants
485 ZEBRA_INDEX_DIRS=data/carnivor_20050118_2200_short-346.xml
487 - in root also one single data record - nice for testing the xslt
490 xsltproc db/alvis2index.xsl carni*.xml
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
497 see: http://www.indexdata.com/yaz/doc/tools.tkl#tools.cql.map
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.
503 Notice the special zebra namespace, and the special elements in this
504 namespace which indicate to the zebra indexer what to do.
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.
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
523 <!-- Keep this comment at the end of the file
528 sgml-minimize-attributes:nil
529 sgml-always-quote-attributes:t
532 sgml-parent-document: "zebra.xml"
533 sgml-local-catalogs: nil
534 sgml-namecase-general:t