A suggestion for TMQL
Rani Pinchuk <[email protected]> Mon, 12 Jan 2004 15:08:07 +0100
| Newsgroups | gmane.text.xml.xtm.tmql |
|---|---|
| Message-ID | <1073916487.1618.20.camel@mikush2> |
Dear all, Please find attached a very early draft of a suggestion for TMQL. It is presented as a "quasi-tutorial" because it is very far from being a solid vision. The language is based very much on ideas from AsTMa* and Tolog, and also from SQL and from the usual object oriented notation. I will appreciate any feedback. Thanks Rani -- Rani Pinchuk Software Engineer Space Applications Services Leuvensesteenweg, 325 B-1932 Zaventem Belgium Tel.: + 32 2 721 54 84 Fax.: + 32 2 721 54 44 http://www.spaceapplications.com
style.css
(text/css, 4.3 KB)
BODY {
background: white;
color: black;
font-family: arial,sans-serif;
margin: 0;
padding: 1ex;
}
TABLE {
border-collapse: collapse;
border-spacing: 0;
border-width: 0;
color: inherit;
}
IMG { border: 0; }
FORM { margin: 0; }
input { margin: 2px; }
A.fred {
text-decoration: none;
}
A:link, A:visited {
background: transparent;
color: #006699;
}
A[href="#POD_ERRORS"] {
background: transparent;
color: #FF0000;
}
TD {
margin: 0;
padding: 0;
}
DIV {
border-width: 0;
}
DT {
margin-top: 1em;
}
.credits TD {
padding: 0.5ex 2ex;
}
.huge {
font-size: 32pt;
}
.s {
background: #dddddd;
color: inherit;
}
.s TD, .r TD {
padding: 0.2ex 1ex;
vertical-align: baseline;
}
TH {
background: #bbbbbb;
color: inherit;
padding: 0.4ex 1ex;
text-align: left;
}
TH A:link, TH A:visited {
background: transparent;
color: black;
}
.box {
border: 1px solid #006699;
margin: 1ex 0;
padding: 0;
}
.distfiles TD {
padding: 0 2ex 0 0;
vertical-align: baseline;
}
.manifest TD {
padding: 0 1ex;
vertical-align: top;
}
.l1 {
font-weight: bold;
}
.l2 {
font-weight: normal;
}
.t1, .t2, .t3, .t4 {
background: #006699;
color: white;
}
.t4 {
padding: 0.2ex 0.4ex;
}
.t1, .t2, .t3 {
padding: 0.5ex 1ex;
}
/* IE does not support .box>.t1 Grrr */
.box .t1, .box .t2, .box .t3 {
margin: 0;
}
.t1 {
font-size: 1.4em;
font-weight: bold;
text-align: center;
}
.t2 {
font-size: 1.0em;
font-weight: bold;
text-align: left;
}
.t3 {
font-size: 1.0em;
font-weight: normal;
text-align: left;
}
/* width: 100%; border: 0.1px solid #FFFFFF; */ /* NN4 hack */
.datecell {
text-align: center;
width: 17em;
}
.cell {
padding: 0.2ex 1ex;
text-align: left;
}
.label {
background: #aaaaaa;
color: black;
font-weight: bold;
padding: 0.2ex 1ex;
text-align: right;
white-space: nowrap;
vertical-align: baseline;
}
.categories {
border-bottom: 3px double #006699;
margin-bottom: 1ex;
padding-bottom: 1ex;
}
.categories TABLE {
margin: auto;
}
.categories TD {
padding: 0.5ex 1ex;
vertical-align: baseline;
}
.path A {
background: transparent;
color: #006699;
font-weight: bold;
}
.pages {
background: #dddddd;
color: #006699;
padding: 0.2ex 0.4ex;
}
.path {
background: #dddddd;
border-bottom: 1px solid #006699;
color: #006699;
/* font-size: 1.4em;*/
margin: 1ex 0;
padding: 0.5ex 1ex;
}
.menubar TD {
background: #006699;
color: white;
}
.menubar {
background: #006699;
color: white;
margin: 1ex 0;
padding: 1px;
}
.menubar .links {
background: transparent;
color: white;
padding: 0.2ex;
text-align: left;
}
.menubar .searchbar {
background: black;
color: black;
margin: 0px;
padding: 2px;
text-align: right;
}
A.m:link, A.m:visited {
background: #006699;
color: white;
font: bold 10pt Arial,Helvetica,sans-serif;
text-decoration: none;
}
A.o:link, A.o:visited {
background: #006699;
color: #ccffcc;
font: bold 10pt Arial,Helvetica,sans-serif;
text-decoration: none;
}
A.o:hover {
background: transparent;
color: #ff6600;
text-decoration: underline;
}
A.m:hover {
background: transparent;
color: #ff6600;
text-decoration: underline;
}
table.dlsip {
background: #dddddd;
border: 0.4ex solid #dddddd;
}
PRE {
background: #eeeeee;
border: 1px solid #888888;
color: black;
padding: 1em;
white-space: pre;
}
H1 {
background: transparent;
color: #006699;
font-size: +3;
}
H2 {
background: transparent;
color: #006699;
font-size: +2;
}
H3 {
background: transparent;
color: #006699;
font-size: +1;
}
IMG {
vertical-align: top;
}
.toc A {
text-decoration: none;
}
.toc LI {
line-height: 1.2em;
list-style-type: none;
}
.faq DT {
font-size: 1.4em;
font-weight: bold;
}
.chmenu {
background: black;
color: red;
font: bold 1.1em Arial,Helvetica,sans-serif;
margin: 1ex auto;
padding: 0.5ex;
}
.chmenu TD {
padding: 0.2ex 1ex;
}
.chmenu A:link, .chmenu A:visited {
background: transparent;
color: white;
text-decoration: none;
}
.chmenu A:hover {
background: transparent;
color: #ff6600;
text-decoration: underline;
}
.column {
padding: 0.5ex 1ex;
vertical-align: top;
}
.datebar {
margin: auto;
width: 14em;
}
.date {
background: transparent;
color: #008000;
}
toma.html
(text/html, 20.3 KB)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Quasi-Tutorial for a Suggested TMQL</title> <link rel="stylesheet" href="style.css" type="text/css" /> <link rev="made" href="mailto:[email protected]" /> </head> <body> <p><a name="__index__"></a></p> <!-- INDEX BEGIN --> <ul> <li><a href="#quasitutorial_for_a_suggested_tmql">Quasi-Tutorial for a Suggested TMQL</a></li> <ul> <li><a href="#introduction">Introduction</a></li> <li><a href="#selection_by_topics">Selection by Topics</a></li> <ul> <li><a href="#topic_accessors">Topic Accessors</a></li> <li><a href="#simple_topic_selects">Simple Topic Selects</a></li> <li><a href="#the_returned_values">The Returned Values</a></li> </ul> <li><a href="#selection_by_associations">Selection by Associations</a></li> <li><a href="#learning_the_structure_of_the_topic_map">Learning the Structure of the Topic Map</a></li> <li><a href="#sorting_the_results">Sorting the Results</a></li> <li><a href="#author_&_copyright">Author & Copyright</a></li> </ul> </ul> <!-- INDEX END --> <hr /> <p> </p> <h1><a name="quasitutorial_for_a_suggested_tmql">Quasi-Tutorial for a Suggested TMQL</a></h1> <p> </p> <h2><a name="introduction">Introduction</a></h2> <p>Because the language that is shown below is very young, I chose to present it as a quasi-tutorial. It contains many examples but also some definition parts. However it is very far from being a language specification.</p> <p>I was hoping to uncover some difficulties in the language itself, but also to generate a somewhat readable document that exposes what I believe to be the strengths of the language.</p> <p>It is my hope that this document will bring much feedback (hopefully constructive :-), so the language can be developed to a more consistent and powerful language.</p> <p>The language below is strongly based on two other languages for dealing with topic maps, <strong>tolog</strong> (of Ontopia) and <strong>AsTMa*</strong> (of Robert Barta), and on SQL. I even used some examples from the presentation of <strong>tolog</strong> and the tutorials of <strong>AsTMa*</strong>. Actually I see this effort as an integration effort among the ideas I took from those languages.</p> <p>When doing this pre-designing of the language (if it might be called that way) I had in mind two targets:</p> <dl> <dt><strong><a name="item_power">Power</a></strong><br /> </dt> <dd> The language suppose to let the user to query most if not all the queries he/she might have in mind. </dd> <p></p> <dt><strong><a name="item_simplicity">Simplicity</a></strong><br /> </dt> <dd> In order for a new language to become popular, it must be easy to learn and use. </dd> <p></p></dl> <p>Usually, the above two targets contradict each other. However, they guided me in making the following decisions:</p> <ol> <li></li> Basing the syntax as much as possible on the well known SQL. This simplified the learning process of the language at least for those who know already SQL. SQL also deals with quite similar problems, so I found good match between its structure and the needs. <p></p> <li></li> No support for generating a presentation of the results in different formats. Like SQL, it seems that this language will be embedded within other more generic languages (Perl, Java, C etc). On the other hand the number of formats and presentations that might be needed is uncountable. Usually the host languages are already capable of providing with formating/presentation means. Therefore I thought that the loss of moving the formatting/presentation part out of the language to the host language makes sense. <p>In this context see also the Skin design pattern.</p> <p>In the context of embedding the language in other language, see the Phrasebook design pattern.</p> <p></p> <li></li> Treating topics as objects. As was said before, ``everything in a topic map is a topic''. And a topic is a structure that holds various data and references to data. Therefore it made sense to treat it as an object. This implied the usage of accessors - in order to access the elements of the object. I found that AsTMa= provides very clear symbols that actually play as accessors (such as the scope character @). The accessors found to be (in my humble opinion) a good thing, as they let us ``navigate'' within the topic object and also to other topic objects. Although the accessors might seem confusing at first, they provide huge power in reasonable complexity. <p></p></ol> <p>Finally, I am well aware that the description below does not include all the facilities that the language suppose to include. In many places I assume knowledge of SQL by the reader. For example, I did not include any built-in functions like the functions provided by SQL. I also did not include macros or function definitions. I guess that if the development of this language goes on, there should be a careful process of choosing what of those functions and other facilities should be adopted in the language.</p> <p> </p> <h2><a name="selection_by_topics">Selection by Topics</a></h2> <p>We start with the most simple case - selecting a certain topic from a certain topic map:</p> <pre> select $person from tm://my/topic/map where $person.id = 'Jonathan';</pre> <p>We can see that we select from a certain topic map that is defined by the <em>from</em> clause. Instead of doing that, we could choose to work from now on with that topic map:</p> <pre> use tm://my/topic/map; select $person where $person.id = 'Jonathan';</pre> <p>We treat topics as objects that have id, base name etc. Dollar followed by any alphanumeric character, underscore or hyphen is a variable that can hold a topic object.</p> <p> </p> <h3><a name="topic_accessors">Topic Accessors</a></h3> <p>We can access the topic elements as follows:</p> <dl> <dt><strong><a name="item_id">id</a></strong><br /> </dt> <dd> <em>.id</em> will give us the topic id: </dd> <dd> <pre> $person.id</pre> </dd> <p></p> <dt><strong><a name="item_base_name">base name</a></strong><br /> </dt> <dd> <em>.bn</em> will give us the topic base name: </dd> <dd> <pre> $person.bn</pre> </dd> <dd> <p>The @ character will let us alter the scope. So for example</p> </dd> <dd> <pre> $city.bn@en</pre> </dd> <dd> <p>will give us the base name of the city in the English scope.</p> </dd> <p></p> <dt><strong><a name="item_type">type</a></strong><br /> </dt> <dd> A topic type (is-a relationship) is a topic by itself. We use the <em>.type()</em> where inside the brackets we can place a number, or an asterisk. </dd> <dd> <p>The following refers to the type of $person topic:</p> </dd> <dd> <pre> $person.type(0)</pre> </dd> <dd> <p>We can refer to the type of the superclass of $person topic like this:</p> </dd> <dd> <pre> $person.type(1)</pre> </dd> <dd> <p>If we want to refer to the type of $person or the type of any superclass of it, we can write:</p> </dd> <dd> <pre> $person.type(*)</pre> </dd> <dd> <p>We can also use the .. operator as follows:</p> </dd> <dd> <pre> $person.type(0..1)</pre> </dd> <dd> <p>The above refers to the type of $person and to the type of its type.</p> </dd> <dd> <p>Note that because <em>.type()</em> returns a topic, we can use o it any of the other accessors. For example, the following is the base name of the type of $person: </p> </dd> <dd> <pre> $person.type(0).bn</pre> </dd> <p></p> <dt><strong><a name="item_occurrence">occurrence</a></strong><br /> </dt> <dd> Occurrence can be a reference or in-line. We can refer to occurrence by three accessors: <em>.oc</em>, <em>.ref</em> or <em>.in</em>. <em>.oc</em> refers to any occurrence no matter if it is a reference or in-line. <em>.ref</em> refers only to references and <em>.in</em> refers only to in-lines. </dd> <dd> <p>Each occurrence might have a scope and a type. We refer to the scope by using again the character @. We refer to the type by placing it inside brackets just after the accessor. If we want to refer both to the scope and to the type, we place always the brackets in the end.</p> </dd> <dd> <p>Example:</p> </dd> <dd> <pre> $person.in</pre> </dd> <dd> <pre> $person.ref@en(cv)</pre> </dd> <dd> <pre> $person.oc@en(birthdate)</pre> </dd> <dd> <p>Note that the occurrence accessors return the data itself (so the reference or the in-line). However, if another accessor is placed after those accessors it will refer to the topic of the type of the occurrence. So the following:</p> </dd> <dd> <pre> $person.in(cv).bn</pre> </dd> <dd> <p>might give us ``Curriculum Vitae'' which is the base name of the topic with id 'cv'.</p> </dd> <p></p> <dt><strong><a name="item_role">role</a></strong><br /> </dt> <dd> The accessors <em>.role()</em> implies that the element before them is an association. </dd> <dd> <pre> $a.role('location')</pre> </dd> <dd> <p>implies that $a is an association that has a role which its id is 'location'. By writing the above we refer to the topic that plays that role (so the topic that plays the role 'location').</p> </dd> <dd> <p>Thus,</p> </dd> <dd> <pre> $a.role('location').bn</pre> </dd> <dd> <p>refers to the base name of the topic which plays the 'location' role.</p> </dd> <dd> <p>In the same way,</p> </dd> <dd> <pre> $a.role(*)</pre> </dd> <dd> <p>implies that $a is an association that has whatever role and we refer to the topic that plays that whatever role.</p> </dd> <dd> <p>If we put a variable inside the brackets, we get the actual topic that describe the role. So</p> </dd> <dd> <pre> $a.role($b)</pre> </dd> <dd> <p>is very similar to last example, but $b will be populated with the topic object that describes that role. Later we will see how we use this structure in order to restrict the roles of an yet unknown association, or to find what are the roles of certain association.</p> </dd> <p></p></dl> <p> </p> <h3><a name="simple_topic_selects">Simple Topic Selects</a></h3> <ul> <li></li> Select a topic by its base name: <pre> select $city where $city.bn@fr = 'Anvers'</pre> <p></p> <li></li> Select a topic by its type base name <pre> select $language where $lanaguge.type(0).bn = 'Object Oriented Language';</pre> <pre> select $language where $language.type(0..1).bn = 'Computer Language';</pre> <pre> select $language where $language.type(*).bn = 'Computer Language';</pre> <p></p> <li></li> Select a topic by its occurrence <pre> select $language where $language.ref = '<a href="http://www.perl.com">http://www.perl.com</a>'</pre> <p></p> <li></li> Select a topic that has occurrence in English and that the French base name of the type of that occurrence is 'ville'. <p>Note that the moment we add an accessor after the <em>.oc</em>, <em>.ref</em> or or <em>.in</em>, we refer to the topic map of the type of the occurrence and not to the reference or the in-line data.</p> <pre> select $city where [email protected]@fr = 'ville'</pre> <p></p> <li></li> Select a topic by the base name of its occurrence type <pre> select $c where $c.oc.bn = 'City'</pre> <p></p> <li></li> Select a topic by its in-line occurrence. <pre> select $a where $a.in@en(city) =~ 'Antwerp';</pre> <p>Here we select the in-line data that match the simple string 'Antwerp'. In general, the language supports regular expressions style Perl5. It is done by using the operators =~ or !~ followed by the regular expression. The first non white character after the operator will be the delimiter of the regular expression. So the above could be written also like:</p> <pre> select $a where $a.in@en(city) =~ /Antwerp/;</pre> <p>or:</p> <pre> select $a where $a.in@en(city) =~ sAntwerps;</pre> <p></p></ul> <p> </p> <h3><a name="the_returned_values">The Returned Values</a></h3> <p>In the examples above, we list only the actual topic objects as the returned values. We can deal with those objects with whatever programming interface we use.</p> <p>However, we can also request only certain data out of the returned value, again using the accessors. Examples:</p> <ul> <li></li> Select the id of the topic: <pre> select $bla.id ...</pre> <p></p> <li></li> Select the base name of the topic: <pre> select $bla.bn ...</pre> <p></p> <li></li> Select the type of the topic (so select the superclass topic): <pre> select $bla.type(0) ...</pre> <p></p> <li></li> Select the base name of the type of the topic: <pre> select $bla.type(0).bn ...</pre> <p></p> <li></li> Select certain occurrence of the topic: <pre> select $person.ref@en(homepage) ...</pre> <p>It is not yet decided what happens if there is more then one occurrence that can be returned (in the example above - two or more homepages in English). One possibility is to return one of them. Other possibility is to return always an array, when occurrences is requested. Yet another possibility is to forbid to request an occurrence all together - and to demand that the occurrences will be retrieved via the topic object.</p> <p></p></ul> <p> </p> <h2><a name="selection_by_associations">Selection by Associations</a></h2> <p>When we select by an association, we know the actual association, and can refer to it by its id.</p> <p>Let us examine an example. Select a person that was born in a city that is called in Dutch 'Antwerpen':</p> <pre> select $person where born_in.person = $person and born_in.location.bn@nl = 'Antwerpen'</pre> <p>We can see that we use kind of accessors (role names) for an element that is not a variable. 'born_in' in the example above, is the id of an association. Any id of association followed by a dot and a role name refers to the topic that plays that role in that association.</p> <p>Because the structure <association_id>.<role_name> refers to a topic, we can use the usual accessors on that topic.</p> <p>We can also see that we use <em>and</em> between two parts of the <em>where</em> clause. We can use <em>and</em> and <em>or</em> and group them using brackets as it is done in SQL.</p> <p>Sometimes though we will need to refer to the same association more then once in the same <em>where</em> clause. We can do that by using the aliases clause. For example, the following query selects a part that is contained in other part that is contained in a spaceship.</p> <pre> select $part aliases contains contains1, contains contains2 where contains1.part = $part and contains1.whole = contains2.part and contains2.whole.id = 'spaceship';</pre> <p>We can also use the negation operator <em>not</em> or use the <em>!=</em> operator. In the following example we get all the employees that are not managers of the same company where they are employed:</p> <pre> select $person, $company where (managed_by.manager != $person and managed_by.company = $company) or (employed_by.company = $company and employed_by.employee = $person);</pre> <p>This can be written also as:</p> <pre> select $person, $company where not (managed_by.manager != $person and managed_by.company = $company) or (employed_by.company = $company and employed_by.employee = $person);</pre> <p>Note that not always we need to mention all the association roles in a query. Consider the following example which query who manages whatever company:</p> <pre> select $person where managed_by.manager = $person;</pre> <p>Sometimes we might want to know how two or more topics might be associated. We can do that by using the <em>.role()</em> accessor.</p> <p>The following query selects an association that connects two topics - one with base name 'Antwerpen' and the other with base name 'Jonathan' (will return the association topic 'born_in').</p> <p>Note that the usage of the accessor <em>.role()</em> implies that the element before it is an association. And remember also that when using <em>.role()</em> we look at the topic that <strong>plays</strong> that role.</p> <pre> select $a where $a.role(*).bn@nl = 'Antwerpen' and $a.role(*).bn = 'Jonathan';</pre> <p>As we saw above, we can check what are the roles we found by placing a variable in the brackets of <em>.role()</em>:</p> <pre> select $a, $r1, $r2 where $a.role($r1).bn@nl = 'Antwerpen' and $a.role($r2).bn = 'Jonathan';</pre> <p>In a similar way, we can restrict the roles we found:</p> <pre> select $a where $a.role($r).bn@nl = 'New York' and $a.role(*).bn = 'Roni' and $r != 'state';</pre> <p>We can also use scope over an association. We do that by using the <em>@...</em> accessor over the object that represents the association. For example, if Jonathan is now in Antwerpen, he might have the association located_in. Yet, that association will not be active under the 'history' scope, and only born_in association will be returned:</p> <pre> select $a where [email protected](*).bn@nl = 'Antwerpen' and [email protected](*).bn = 'Jonathan'</pre> <p>Note that we could write the above also like this:</p> <pre> select $a where [email protected](*).bn@nl = 'Antwerpen' and $a.role(*).bn = 'Jonathan'</pre> <p>The moment a topic object got a scope, it will be kept. The following on the other hand is an error:</p> <pre> select $a where [email protected](*).bn@nl = 'Antwerpen' and [email protected](*).bn = 'Jonathan' # an error !!</pre> <p>The last examples bring us to the domain of introspective queries that will be discussed next.</p> <p> </p> <h2><a name="learning_the_structure_of_the_topic_map">Learning the Structure of the Topic Map</a></h2> <p>Get all the topics:</p> <pre> select $a where exists $a;</pre> <p>We use the <em>exists</em> keyword that returns <em>true</em> if the expression that follows it exists in the topic map.</p> <p>Get all the associations:</p> <pre> select $a where exists $a.role(*);</pre> <p>Select all association types in this topic map:</p> <pre> select distinct $a.type(0) where exists $a.role(*);</pre> <p>Note that we use the <em>distinct</em> keyword. This keyword make sure that each row of the result set is unique.</p> <p>Select an association that has a role named 'location' or 'placed':</p> <pre> select $a where exists $a.role('location') or exists $a.role('placed')</pre> <p>Select all role types used in more than one association type:</p> <pre> select distinct $a where exists $a.role($r) and exists $b.role($r) and $a != $b;</pre> <p>Select all occurrence types: </p> <pre> select distinct $a where $b.oc.type(0) = $a;</pre> <p>In order to query about scopes we first examine the scope character @. Because a scope can be seen also as a topic, the string we place after the @ character is the id of the topic that represents the scope. However, we can also place a variable after the scope character. for example:</p> <pre> $city.bn@$language</pre> <p>However, we should be careful with precedence issues. For example, in</p> <pre> $a@$scope.role(*).bn@nl</pre> <p>it is not clear if</p> <pre> .role(*).bn@nl</pre> <p>is referring to $scope or to</p> <pre> $a@$scope</pre> <p>Actually, all the accessors refer to the immediate element from their left. So probably we want to write the above as:</p> <pre> ($a@$scope).role(*).bn@nl</pre> <p>Using a variable after the scope character, we can select all scopes:</p> <pre> select distinct $s where exists $t@$s or exists $t.oc@$s or exists $t.bn@$s;</pre> <p>We can also select the scope of certain occurrence. For example checking in which languages (so scopes, in that case) the CV of certain person is available.</p> <pre> select $s where $person.id = 'michael' and exists $person.oc@$s('cv');</pre> <p> </p> <h2><a name="sorting_the_results">Sorting the Results</a></h2> <p>The results from the query are returned as rows of topic objects or strings. We can sort the results by using the <em>order by</em> keyword. When we order by a topic object, its id will be taken for determining the order. So:</p> <pre> ... order by $t</pre> <p>and</p> <pre> ... order by $t.id</pre> <p>is actually the same.</p> <p>We can order by several variables, and we can reverse the order with the keyword 'desc':</p> <pre> ... order by $a, $b.bn@en decs, $c.type(0).bn;</pre> <p> </p> <h2><a name="author_&_copyright">Author & Copyright</a></h2> <p>Rani Pinchuk, <<a href="mailto:[email protected]">[email protected]</a>> </p> <p>Copyright (c) 2003 Space Applications Services </p> </body> </html>