The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

TM::View - Topic Maps, Views and Listlets

SYNOPSIS

 use TM;
 use TM::View;

 my $map;
 # map is created/synced somehow

 # do not change the map afterwards or pass the constructor
 # a deep copy (e.g. using dclone from Storable).
 my $view=TM::View->new($map);  

 $view->sequence_add("tm://sometopic");  # added with default style info
 $view->sequence_add("tm://othertopic",0); # add at the beginning
 my $length=$view->sequence_length;
 my $whogoesthere=$view->who(0);        # which topic is shown first?

 # retrieve the style describing the topic's midlet by location
 my ($who,%style)=$view->style(1,0); 
 ($who,%style)=$view->style("tm://sometopic",0); # or by topic
 $style{bullet}=1;              #  modify it
 $style{emphasize}=0;
 $style{custom_attrib}="what you want!";
 $view->style("tm://sometopic",0,%style); # and write it back

 my $xml=$view->make_listlet;

DESCRIPTION

This package provides sequencing and styling mechanisms for Topic Map slide shows or other serialized presentations.

CONCEPTS

A view consists of an extract of a map together with rendering information which presents a linear sequence of topics and their interesting aspects. The main use of views is for using topicmaps as source for slides or similar linear presentation mechanisms.

A view contains information about which topics are shown in what sequence, and what of the available information related to a topic is presented and how. TM::View manages this information in data structures called styles.

Every topic in a map can have sundry attributes associated with it, e.g. basenames, occurrences and class/instance information. None of these have any implicit ordering. From a view perspective, these attributes belong to the topic and their display is controlled by the topic's style. A topic can also be involved in associations as member, role being played or type of the association. Associations are thus not directly associated with a single topic but instead are deemed to be interesting for every involved topic. A view thus includes information about a particular association multiple times in each involved topic's style.

In TM::View a style element consists of two components: an identifier of the topicmap object being controlled, and a reference to a hash of attribute/value pairs. The attributes describe the formatting of the object but do not include the object content. Besides certain attributes with predefined meanings (see topic_as_listlet below), there are no restrictions on the attributes.

TM::View uses the data structures and identification concepts described in TM(3), which separate the world into Midlets (without assertions) and Assertions (with midlets). (Everything in a map is a midlet. "Real" topics are only present as midlets, whereas implicit topics have a midlet and an assertion with the same identifier.) Midlets contain only topic id and reification information, whereas assertions carry everything else: topic attributes and associations.

A single style element controls the display of a single assertion. In practice that means that a basename has its style element, separate from an occurrence even if they both belong to the same topic.

The style elements for all displayable aspects of a single topic are collected in a list: this is called the styles of a topic. Position in this list controls display position, and this style list contains all information to create a slide or page about this topic. Note that the style of a topic is always complete and contains all the topic's aspects: Aspects that should not be displayed are flagged thus by a specific attribute (see topic_as_listlet).

Any midlet in a map can have such a style list (but of course not all midlets are worth displaying: for example, a topic that was implicitely defined by specifying a scope for some other attribute hardly contains interesting information).

Multiple topic styles describe a linear journey through the map, and this is represented in TM::View as the sequence. A view contains exactly one sequence, which lists the topics that are to be displayed (and their order). The sequence usually is only a subset of all available topics (or more precisely midlets).

RELATIONSHIP BETWEEN MAP AND VIEW

A TM::View object embeds a topicmap upon its creation, after which this map object must not be modified anymore. (To be precise, adding elements to the map might be mostly safe, but modification or removal of existing map content is definitely unsafe.) It is suggested that the programmer use dclone (see Storable(3)) or something similar to create a deep copy of the map object for the constructor, if modification of the map object is expected at a later stage.

As maps change over time, one-shot discardable views would be of little use for serious knowledge management: specifying a display sequence and extracting the appropriate information from a map is time-consuming. One would have to recreate the display sequence with a new view that applies to the new map, and manually copy over all transferrable attributes. Obviously this is tedious and inefficient, and TM::View provides automation for as much of this process as possible.

A TM::View object can be "applied" to a modified version of the respective map using the method reconcile.

reconcile resolves the differences between the old (embedded) and updated map and migrates the view information into the context of the updated map. This is done minimizing the loss of style information: the styles for unmodified elements are copied over, styles applying to removed elements are removed and new elements are added where appropriate (e.g. a new occurrence is added to the styles of the topic it applies to, with default display attributes). Modified (and renamed) topics and associations are identified and their styles are transported over, but style information for modified assertions is lost (the assertion will show up as new). Topics and assertions affected by these changes are flagged and upon completion, the map embedded in the old view is discarded and the new map is snapshotted in.

INTERFACE

The methods provided by TM::View fall into three categories: managing the overall sequence of topics, managing the styles (of assertions) of a particular topic and creating output.

The methods commonly use two different identifiers: a topic identifier and an assertion identifier, both of which are internal identifiers as described in TM(3). The tid applies to the sequence, whereas the aid applies to the aspects related to a particular topic. The sequence-related methods obviously do not require aid parameters.

Most methods allow to specify topics by either tid or position in the sequence. Similar mechanisms apply to selecting assertions by their aid or by position in the sequence of styles.

Constructor

 $view=TM::View->new($tmobj);

The constructor requires a TM map object as sole argument, which is the map the view applies to. The map object is attached to the view and must not be modified afterwards. It is highly suggested to use dclone (see Storable(3)) or similar to create a deep copy of the map for the view:

 $safeview=TM::View->new(dclone($tmobj));

Methods

map:
 $tmobj=$view->map;

This method returns the map object associated with the view. The map object can be used for retrieval purposes but must not be modified.

sequence_add:

$length=$view->sequence_add(tid [,position]);

This method adds the topic tid to the view. If no position argument is given (or if it is invalid), the topic is added at the end of the sequence. The position argument is a number, with zero being the start of the sequence. The sequence can not have holes.

The style information for the topic is a built-in default, which can be modified using the style method.

The new length of the sequence is returned on success, or undef if the topic is already sequenced or non-existent.

sequence_remove:

$length=$view->sequence_remove(tid or index);

 $length=$view->sequence_remove("tm://sometopic");
 $length=$view->sequence_remove(12);

This method removes a topic from the sequence. The topic can be identified either by its topic id or by its position in the sequence.

The method returns the new length of the sequence or undef on an unsequenced or nonexistent topic.

sequence_length:
 $howmany=$view->sequence_length;

The method returns the number of currently sequenced topics.

clear:
 $view->clear;

This method clears the list of sequenced topics and returns nothing.

sequence_move:

$newpos=$view->sequence_move(tid or index,delta);

 $newpos=$view->sequence_move(10,-1); # up one
 $newpos=$view->sequence_move('tm://sometopic',2); # down two slots

This method moves a sequenced topic to a different slot in the sequence. The topic can be identified by its id or its position. The movement is controlled by the delta argument which indicates how many slots the topic is to move.

The method returns the effective new position or undef on bad arguments.

where:

($topicindex,$aidindex)=$view->where(tid or index [,aid or index]);

 print "happy!" if ($view->where("tm://joy")); # is sequenced
 ($shakespeare,$bnidx)=$view->where("tm://frailty","tm://woman");

This method looks up a topic (or one of its attached assertions) in the sequence and returns the position in the sequence (and within this topic's information) or undef if no match was identified.

If no aid argument is given, the topic is looked up and aidindex=0 is returned. With an aid, first the topic is looked up and then the given aid is looked up in the style list for this topic. If either lookup fails, undef is returned.

who:

$tid=$view->who(topic index [,assertion index]);

This method performs the inverse of who: given an index into the sequence, it returns the tid of the topic in that slot. With the optional assertion index, the aid of the assertion in that place (within the styles of the topic) is returned.

If either index is invalid, undef is returned.

style_length

$nr_aspects=$view->style_length(tid or index);

Returns the number of assertions that the style of this topic contains. The topic is identified by its tid or index in the sequence, and if the argument is invalid, undef is returned.

style:

($id,%stylehash)=$view->style(tid or index,aid or index [,%newstyle]);

This method gets (and optionally sets) a style. The sequence is searched for a topic matching the first argument, and within the list of styles for this topic, the requested assertion is looked up. If either lookup fails, undef is returned.

On success, the aid of the found assertion and a copy of the display attributes hash is returned. If the optional newstyle argument is given, then the display attributes hash is replaced with a copy of newstyle. Note that when setting newstyle the previous display attributes are returned.

The contents of the stylehash are unrestricted, but certain attributes have specific meanings for TM::View's output methods which are discussed below, with topic_as_listlet.

The style at index 0 is a dummy style which contains no display attributes (except the _is_changed flag) and only identifies the topic in question. The dummy style cannot be modified.

style_move:

$newpos=$view->style_move(tid or index,aid or index,delta);

Identifies the style for the given assertion in the context of the given topic and moves it by delta slots. The dummy style at index 0 cannot be moved, nor can any other assertion be moved into slot 0.

On success, the new position is returned. If either topic or assertion lookup fails, or if the delta argument results in an invalid position, undef is returned.

reconcile:

$mapdiff=$view->reconcile(map object);

The reconcile method transfers style information from the current, snapshotted map over to the (newer) map given as argument. On completion, the new map replaces the old map. The new map must not be modified after the reconcile operation, and it is highly suggested to pass a deep copy (e.g. using dclone from Storable(3)) of the map object.

The method returns the output of TM::diff() for convenience.

Reconcile identifies unchanged or renamed-but-identical topics and migrates their style settings over. For changed topics or changed aspects of topics, all precisely identifyable information is migrated: identical occurrence data, associations whose membership has not changed and so on.

Where this identification is not possible (because the topic/aspect is gone/was added in the new map), reconcile will flag the change. Every sequenced topic whose aspects were modified receives the attribute _is_changed with a true value. This attribute is also set for aspects of a topic that have changed. This attribute can be cleared using the method clear_changed.

After reconcile has completed, the view is consistent with the argument map.

clear_changed:

$view->clear_changed([tid or index]);

This method removes the _is_changed flag wholesale from all topics in the sequence if no argument is given. Alternatively, it can clear the flag from a specific sequenced topic only. Returns nothing.

topic_as_listlet:

$xml=$view->topic_as_listlet(tid or index, [xml::writer obj,io::string obj]);

This method produces a Listlet for a particular topic. Without the optional arguments, the method creates and uses a temporary XML::Writer object for creating the output; With writer and ios arguments given, these will be used instead.

A Listlet is a very simple XML representation of a topic's slide/page as described by the topic's style. Basic listlets conform to the following DTD:

    <!ELEMENT listlet (PCDATA? listlet*)>
    <!ATTLIST listlet   title  CDATA #IMPLIED
                        url    URL #IMPLIED>

Every listlet has a header with the slide title, and recursively embedded further listlets for the topic's displayed aspects. The textual content is either in the title attribute or in the text data. For listlets dealing with addressable resources, a url attribute can be present as well.

The title attribute of a listlet is chosen using find_nicename (see below) to provide context-sensitive titles.

However, topic_as_listlet does not limit the user to said (minimal) DTD: any scalar-valued style attribute whose name does not start with an underscore will be transformed into an XML attribute of the same name in the listlet output. (This obviously imposes XML attribute naming restrictions to style attributes.)

Attributes with a leading underscore in their name are considered internal and are not printed at all: such attributes may be useful if one needs to store hashes or arrays in a style but still uses topic_as_listlet.

Certain style attributes have special meaning for topic_as_listlet and are not printed directly as well:

_on:

Controls whether this aspect is shown or not.

_type_on:

Controls whether a typed occurrence should be shown with an enclosing listlet that displays the occurrence's type. With this option, the AsTMa fragment

 reference
 bn: reference text:

 in(reference): some book

is rendered as

 <listlet title="reference text:">
    <listlet>some book</listlet>
 </listlet>

Without the attribute, only

 <listlet>some book</listlet>

would be output.

_player_order

Controls the display ordering of players for this particular display of an association. This is an array reference, the values correspond to the TM-native ordering of players as present in the assertion and the position describes the intended display position.

_player_order and _player_style are present wherever an association can be shown (= in the styles of all involved topics). Each of these displays has separate _player_style and _player_order attributes. _player_order must be kept consistent (ie. list all players exactly once).

_player_styles

This controls the display of individual players within an association. This is an array reference, with position corresponding to the TM-native ordering of players in the assertion. Each array cell is a hashref with style attributes applicable to this particular player.

Within these individual player styles, two attributes are special:

_on

controls whether this player is shown.

_role_on

controls whether the role the player is playing should be shown parenthesized after the player.

For every player a (possibly empty) _player_styles element must always be present.

make_listlet:

$xml=$view->make_listlet([metadata hash]);

This method runs topic_as_listlet on all sequenced topics, and optionally adds a metadata node to the toplevel listlet:

 <!ELEMENT metadata    title author*>
 <!ELEMENT title       PCDATA>
 <!ELEMENT author      PCDATA email? affiliation?>
 <!ELEMENT email       PCDATA>
 <!ELEMENT affiliation PCDATA>
 <!ATTLIST affiliation url URL>

The metadata argument is optional, and the hash keys directly correspond to the attributes of the resulting metadata node - with a possible exception for authorship:

If the author value is scalar, then email, affiliation and url are expected to be scalar, too, and a single author node is created. If author is an array-ref, then all other attributes (except title) are expected to be array-refs as well and matching array values will be used to construct multiple author nodes.

make_listlet returns the listlet xml or undef if the arguments are inconsistent.

find_nicename:

($source,$displayname)=$view->find_nicename(tid or index [,$ownstyles,$context]);

This method adds some context-sensitivity to choosing names for the display of a topic. If only the tid/index argument is given, then the first basename of this topic with source=0 is returned. If the ownstyles restriction is set, then the first displayed basename of this topic and its style list index is returned. If the restriction is not set, but context is given, then the basename that is scoped with the context is returned, or the first unscoped basename.

In any case, if nothing matching was found, the tid without baseuri is returned.

As an example, consider this AsTMa map fragment: vienna (city) bn: Vindobona bn@austria: Wien bn@oepest: A-1xxx in: Wien ist anders.

find_nicename("tm://vienna") will return any of the three basenames, depending on how the TM backend orders assertions. find_nicename("tm://vienna",0,"tm://murkin") will return (0,"Vindobona") because there is no basename with the requested scope. find_nicename("tm://vienna",0,"tm://oepest") will return (0,"A-1xxx").

This comes especially handy for associations, where the best name often depends on the perspective; for this find_nicename works best when given some help like in the following map fragment:

 (is-part-of)
 whole: a_thing
 part: some_other_thing

 is-part-of
 bn@whole: has components:
 bn@part: is a component of:

SEE ALSO

TM(3)

AUTHOR

Alexander Zangerl, <alphazulu@cpan.org>

COPYRIGHT AND LICENSE

Copyright 2007, 2008 Alexander Zangerl

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.