|
Struct
|
NOTE: this document describes traditional ISIS and early OpenIsis proposals.
For updated information please refer to
Malete structures
structuring ISIS records using subfields or subrecords
| structures |
The means by which an Isis record can be structured into "data elements"
("A defined unit of information", Z39.2 a.k.a. ISO2709)
fall in one of two broad categories (citing Z39.2):
- subfields
"A data element considered as a component of a field."
In *ML (SGML,HTML,XML...), subfields correspond to a node's attributes.
In MIME, subfields correspond to attributes of a MIME header value.
- subrecords
"A group of fields within a record that may be treated as a logical entity.
(When a record describes more than one entity,
the descriptions of individual entities may be treated as subrecords.)"
In *ML, subrecords correspond to a node's childs.
In MIME, subrecords correspond to multipart body parts.
| subfields |
Since a field value can actually be anything,
including XML text or a serialized (textual or binary) Isis record,
it can be arbitrarily structured according to a regular expression
or some other grammar (machine parseable or not).
The term subfield, however, is used for a range of characters in the value
which is identified by rather simple means:
- fixed
if all (or all but the last) subfields have a fixed length
and are neither optional nor repeatable,
then each subfield can be found at a fixed position.
- delimited with optional identifier
this is the proper Z39.2 notion of a subfield.
If a special delimiter character is found in the field,
it breaks the field into subfields.
Z39.2, and thus MARC, use the character 31 as delimiter
(hex 1F, CTRL-_, ASCII "unit separator" US).
Traditional Isis uses the caret '^'.
OpenIsis permits any character, including the horizontal TAB and semicolon.
More precisely, OpenIsis reverts Z39.2's notion that
"every subfield is INTRODUCED by a delimiter, unless it isn't"
to the principle that for every data element, it is specified
how it's end is detected, including by fixed length or varying delimiters.
The initial n characters of a subfield are used to identify the subfield.
Z39.2 permits any (small) fixed value for n, including 0, i.e. not identified.
The MARC family of standards uses n=1.
OpenIsis allows for any value, including variable length identifiers,
which are themselves delimited by some character like a '=' (see below).
Z39.2 states that if identifiers are used, each must be preceeded
by a delimiter, and every data element, including the first,
must be identified that way. However, an initial range of m characters
(i.e. preceeding the first delimiter) in every field may serve as "indicator",
which is not regarded a "data element". Again, m is a small fixed number;
MARC uses m=2. Traditional Isis has no special support for indicators.
OpenIsis allows to access whatever is before the first delimiter.
Different subfielding methods can be mixed or nested.
Typical cases are:
- mixed fixed/delimited
After some initial fixed subfields, following subffields are delimited.
This can be used to describe MARC's fixed indicators.
- nested delimited/fixed
A delimited subfield has itself a fixed substructure.
Actually the leading identifier in a subfield can be regarded
as fixed part in a mixed substructure.
- nested unidentified delimited
A delimited subfield has itself a delimited structure.
This can be used to model variable length identifiers.
In other words, identifiers are themselves nothing but subfields
used as keys on some level of nesting.
On the other hand, any subfield could serve as a key for it's parent.
This is used e.g. to select a field by a subfield indicating a language
(see below for keyed subrecords).
If you look at the
plaintext representation of an Isis record,
actually the whole record is a newline delimited value,
the whole database is a blankline (double newline) delimited value
and each field has it's tag as initial tab-delimited subfield.
In the future, OpenIsis will add support for a wide variety of
subfielding techniques such as defined by regular expressions,
MIME headers or produced in typical "character/comma separated values" files
(opionally using quotes).
Since splitting subfields is mostly and can always be done on the
application level (i.e. a database server rarely needs to care),
"support" essentially boils down to the definition of appropriate meta data.
| subrecords |
A subrecord consists of a typically continuous range of fields within a record,
started by some field to introduce the subrecord.
Some variants, however, like keyed subfields,
can be freely scattered and don't need a "header" field.
There are basically four ways to denote the boundaries of structures:
- embraced
where a special field is used to denote the structures end.
This resembles SGML-style notations,
where each opening tag is matched by a closing tag.
This is relatively easy and recommended for every day use.
- marked
where the fields of the child structure are marked as such.
This is sort of the opposite approach of embracing.
Marking comes in several powerful flavours,
see below for a more detailled discussion.
- counted
where the number of fields (not childs) belonging to the
structure is given in (any leading digits of) the initial field.
This allows for safe embedding regardless of the
structure's contents and is thus used in contexts where
full generality is needed like when embedding result records
within a server's response.
A variant of this is negative counting, where the TAG of the initial
field is the negative number of fields including the initial one.
- implicit
where the number of childs is fixed.
An example of this is the parse tree of a query,
where the structure "AND" has exactly two childs
(which in turn might be structures).
This is used mostly for internal structures like parsed
queries or formats, which are not meant to be exchanged.
The field introducing a subrecord might have any subfields
just like other fields, similar to the attributes that might
be assigned to a tag in SGML applications like HTML.
However, the first subfield (unidentified initial characters)
of a field opening an embraced or counted subrecord is reserved as indicator:
- a plus sign '+' as first character
indicates explicity opening a subrecord
- a minus sign '-' as first character
indicates an empty subrecord (containing no childs)
- an empty value
indicates explicity closing a subrecord
(similar to the closing blank line used in several protocols)
- an initial numeric value
(of decimal digits) gives the number of fields to follow.
- an initial character @A-Z
gives the number of childs to follow (@=0,A=1,B=2...) (rarely used)
Auxiliary information about the child,
like an embedded records row number and type,
are stored in subfields of the parent.
| conventions |
While the intented usage of subrecords might be specified in
more detail in the
table metadata
, the schema can also be used standalone (without referring to metadata),
if some conventions on tag ranges are followed.
The extend of subrecords by length or braces can be safely
determined if you just know that you want the given field
to be regarded as subrecord.
For subrecords of fixed number of childs (meant for internal use),
it is necessary to recognize whether a following field is itself a structure.
If they are used at all, the tag range -1..-99 should be reserved for this
purpose.
In this context, typically one of two modes is used:
- the MIME processing mode for processing list-style content,
assumes that negative tags denote structures,
while positive contain plain data.
- in XML processing mode, everything but the 0 tag (text node) is a structure.
If a parent has a subfield ^0,
that should contain the childs identity as dbname or mfn or dbname.mfn.
If the parents indicator is delimited by a tab instead of a ^,
the next tab-delimited subfield is interpreted that way (where applicable).
| marked structures |
There is a wide variety of techniques for marking fields as "childs"
of other fields. Marking techniques work especially well for a single
level of substructuring; for nested structures, some restrictions apply.
We give some commonly used examples:
- quoting
is done by prefixing every child field value with a special string,
which is not used as prefix outside the child fields.
However, at least for a single level of quoting, it does not impose
a problem if the child fields themselves started with the same prefix:
Still, the original value is retrieved by stripping the (first) prefix.
This even works for multiple levels, as long as the record was properly
constructed, i.e. the quoting prefix is not used outside childs.
Examples are the output of the diff command (which is driving the
RCS/CVS revision control system very reliably) and the '>' quoting
used in e-mail replies.
- tagging
Instead of the field value, of course also the field tag can be used
as child mark. In some situations it might be possible to choose
appropriate reserved tags for the childs.
In other situations, where some given child tag must be kept,
it can be stored as prefix in the field value according to the canonical
Serialized
plain text format.
- keying
If the mark used is dependent on an attribute of the parent field,
the childs can be determined even if non-continuous.
With some more cooperation of the childs, the mark might be an
attribute (subfield) instead of a prefix (indicator).
That way, childs and parents are linked together rather logically
than "physically" by a common key just like in relational databases.
This easily extends to multiple levels using segmented keys
(consisting of several attributes/subfields).
While this scheme only works with well behaved childs and may waste
some space by replicating keys, it is simple and robust and gives
convenient access to the childs without inspecting the structure.
| childs vs. attributes |
Every information that can be represented using an attribute,
can also be represented using a child.
From that point of view, attributes are a redundant "language" construct
and one might deem a model using only childs as the simpler one.
We call such an attributeless model "canonical verbose" representation.
It's a little bit similar to the "everything is an object"
approach of pure OO languages like Smalltalk.
But then, having a richer language isn't always such a bad thing,
if you know how to use it appropriately.
(This "if" is the core of almost any serious criticism of rich languages,
but for now, let's assume we know what we're doing).
Appropriate use basically boils down to choosing the language construct
that was just made for your situation, i.e. not the most general one,
but quite to the opposite the most specific (restricted) one.
That way you will not only have the most efficient representation,
but also express additional information about what's going on.
In short, a "canonical compact" modelling can be based upon the principle
"Use attributes wherever possible".
Some logical property of a logical structure can be represented by
means of attributes, if
- it is simple,
i.e. one single string value.
- or at least flat,
i.e. itself a structure that can be represented based on attributes
that do not interfere with the parents attributes.
In the latter case, the property will show up as several
logically interrelated attributes of the parent.
However, such a flat group of attributes might be a candidate
for a child under some circumstances.
- it is not repeatable.
Although OpenIsis supports repeated subfields as used by some MARCs,
XML/SGML attributes can not be repeated.
(Technically, they can, but there neither is defined semantics for
repeated attributes nor is access supported by parsers or the DOM).
Moreover, traditional CDS/ISIS implementations do not support
repeated subfields, so it's probably a good idea to not use them
without a pretty good reason.
Basically, when you think C, one field's attributes take everything
that goes into a simple struct, without using arrays or pointers.
The detailled modelling should also take into account the intended usage.
For example, one might devise some attribute candidates to childs, if
- they are likely to be accessed or modified together
but independent of other properties
- they are candidates to be inherited or overridden as a group in a
PatchWork
- the parent would otherwise become very large
| variant structures |
The C language construct of a "union" is frequently used in bibliographic
databases. The typical form resembles the PASCAL "variant record",
using an initial field as indicator for the usage of the given field.
Sometimes, however, the more liberal C practice is used,
where the intented interpretation is specified somewhere in the record, somehow.
A similar construct is used in ALGOL-derived OO languages like C++ or Java,
where the indicator (of what object is this ?) is out-of-band data
(i.e. cannot be modified or inspected like any other data).
In Isis records, fields always have a tag
(and subfields commonly have an identifier) indicating the kind of data.
Therefore, there is little need to introduce another level of switches.
A canonically decomposed model
- would not reuse fields or subfields with different structure
- would not contain rules like
"if subfield a has value b then subfield c must be present"
However, on the other hand, full decomposition might be tedious and
even hide relationships. Moreover, from a given point of view,
tags and identifiers are just ordinary subfields on some level.
In general, if the same tag is used for variants of a field,
the risk of misinterpretation of data should be minimized by
not reusing the same subfields with different structure.
After all, defining another indicator and ignoring an unexpected subfield
or moaning on the lack of an expected one is cheaper and more robust and clear
than verifying an expected structure based on other subfield values.
| examples |
A typical HTML table definition starting with
<table width="100%" cellpadding="0" cellspacing="0"
marginwidth="0" marginheight="0" topmargin="0" leftmargin="0" border="0">
<tr>
<td valign="top" width="160">
this is the textbody <br/> of the td node
</td>
</tr>
...
will be compacted to, say,
100 +^w100%^p0^s0^m0^h0^t0^l0^b0
101 +
102 +^vtop^w160
0 this is the textbody
103 -
0 of the td node
102
101
...
For a detailed description of the transformation, see
the XML-ISIS doku
A six field result record might be embedded within a response like
908 6 cds.47
24 Hydrological achievements and social problems
...
Assuming we gave tag -20 to "OR" (and 0 to a literal),
the query "plant OR water" might be parsed to
-20 B
0 plant
0 water
"frog AND (plant OR water)" might look like, if -21 is assigned to "AND"
-21 B
0 frog
-20 B
0 plant
0 water
For implicit tags, the number of childs is redundant
(fixed per tag in a given use) and will typically be omitted.
$Id: Struct.txt,v 1.10 2004/06/10 12:52:29 kripke Exp $
|
|