lørdag, november 07, 2009

Solving the identifier arbitrariness problem

Lately, I have been thinking about subject identifier arbitrariness[1] problems. The problem is simple to define, but hard to solve; imagine you want to say something about the subject Orange in your ontology[2], and you give it the subject identifier http://example.com/ontology/orange. You, of course, know that you are talking about the color orange, but if your ontology is to be shared (broadcasted transmission[3]) with other systems, then the other systems (listeners[3]) may think you are talking about the telecommunication company Orange.

Here are some ways that people use to "solve" arbitrariness problems that I am aware of, some are better solutions than others, and some can be combined:

Identifier directories - Use already published subject identifiers from other ontologies, these can be found in identifier directories like subj3ct.com and others.

To my knowledge, there is no standardized[7] manner in the current interchange formats[5][6] to describe what identifier directories you are using (just a namespace reference will not do); this means that you need to inform your listeners of this in a seperate document, or as some kind of metadata[4].

Unfortunately, the description of the subjects are open for human interpretation, as it is usually written in plain language (and mostly in English), making it unsuitable for automated systems, or in other words; the listener has to still teach her system what the subjects are.

Adding identifier metadata
- Put metadata[4] into the subject identfier, for the color orange one could make an identifier that has the word color in it, like this http://example.com/color#orange, a company could be something like this http://example.com/company#orange .

In my opinion, this is probably the worst way of solving the problem, unless combined with some of the other solutions, some of my reasons are:
  • To my knowledge, there is no standardized[7] syntax to build these identifiers, so what the identifiers really mean is up for listeners interpretation
  • You still have not said what orange is, only that it is something that is related to color
  • You have created a new arbitrariness problem, now with color or company
  • Identifiers with lots of metadata can become long and unmanagable
  • The more metadata you put into a identifier the less interchangeability[8] you will have; unless you just add new identifiers every time you change something that affects your existing identifiers, which could bloat you ontology
Adding types - Adding types-instance relationships[9] to your ontology to infer the meaning of a subject, is probably the most common way of trying to solve the identifer arbitrariness problem; this way you could create a new subject for color with the identifier http://example.com/color and create a type-instance relationship to orange with the identifier http://example.com/orange. Unfortunately, even though you now have said that orange is of the type color, you still have not said what color is, thus you now have a identifier arbitrariness problem with the color subject.

Adding ontology metadata - Adding metadata[4] directly into a ontology is, in my opinion, not a best practice, you should rather make a second ontology for your metadata (a metamap). You could describe all your identifiers in the metamap, but since there is no standardized[7] manner of doing this, you must still document your metamap, which sadly somewhat defeats the purpose of the exercise.

Adding Descriptive Logic - Personally I think Descriptive Logic[10] is the way to solve the identifier arbitrariness problem as it will explain subjects in a structured manner, which will also support automated systems; in fact, Knowledge Representation[11] use Descriptive Logic. Unfortunately, to my knowledge, Descriptive Logic is not available for Topic Maps, although there have been some attempts with combining OWL[12] with TMDM[13] and TMCL[14].

Hopefully, a custom knowledge representation language will be part of the topic maps ISO standards in the future.

---

[1] The Antropology of a Language, Harriet Joseph Ottenheimer, Thomson - Wadsworth, 2006, page 179
[2] Ontology , Wikipedia
[3] The Antropology of a Language, Harriet Joseph Ottenheimer, Thomson - Wadsworth, 2006, page 178
[4] Metadata, Wikipedia
[5] XML Topic Maps (XTM) 1.0, TopicMaps.org
[6] Topic Maps - XML Syntax, TopicMaps.org
[7] Standardization, Wikipedia
[8] Interchangeability, Wikipedia
[9] Topic Maps - Data Model, isotopicmaps.org
[10] Description logic, Wikipedia
[11] Knowledge representation, Wikipedia
[12] OWL Web Ontology Language Overview, W3C
[13] Building Topic Maps in OWL-DL, Anne Cregan, Artificial Intelligence Group, University of New South Wales
[14] TMCL and OWL, Lars Marius Garshol, Bouvet

søndag, november 01, 2009

Meronymy DBMS part #2: TMQL Parser

Last year I wrote a blog article introducing my Topic Maps Database Management System called Meronymy DBMS. I coded a lot on it, but stopped in the pre-alpha stage as I was waiting for the TMQL ISO standard to be done. As bad luck would have it TMQL is still not finished, but when one of the ISO editors, Lars Marius Garshol, said that it might be helpful to the process if I started implementing his new TMQL Path Language, I said yes.




The above drawing shows the components that makes up the Meronymy DBMS, the parser component is marked by having a slightly fatter border around it.

The purpose of the TMQL parser is to to a syntactic analysis of the (TMQL) query, and split it into individual tokens. The output from the parser is a list of tokens that is later used as an input to the Operator Evaluator(see drawing), that builds a Operator Tree consisting of Logical Operators, I will write more about the Meronymy DBMS Operator Evaluator in a later article.

Writing a parser is complex, unless you use a framework of some type, for the Meronymy DBMS I use Quex to create my C++ lexical analyzer. Here are some of the reasons for choosing Quex:
  • Stream support
  • Full Unicode support
  • Very fast processing
  • Easy to use
  • Mode oriented
This weekend I finished all the rules for the TMQL Path Language parser, and I have now started to create a notation for the logical operator tree.

lørdag, oktober 10, 2009

Overwriting files in a Sharepoint feature

In my current Sharepoint project I wanted our frontend developer to easily update his files by deactivating and activating features, we created one feature for his master pages, one for his page layouts and one for his styles. We quickly discovered, however, that some of the files in his features did not get updated unless we manually deleted them before activated the feature. To prevent this manual excercise I added code that deletes the files when the feature deactivates. First I added some custom properties to the feature.xml file that just lists all files that should be deleted when the feature is deactivated:


<?xml version="1.0" encoding="utf-8"?>
<Feature Id="233f8aeb-b9ab-4eba-b5d9-2d154c6d9d34"
Title="Acme Web Stylesheets"
Description="Acme Web Stylesheets"
Version="1.0.0.0"
Hidden="FALSE"
Scope="Site"
DefaultResourceFile="core"
ReceiverAssembly="AcmeWebPublishingFeatures, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f447674da388ce6e"
ReceiverClass="AcmeWebPublishingFeatures.AcmeWebStyles"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ElementManifests>
<ElementManifest Location="elements.xml"/>
</ElementManifests>
<Properties>
<Property Key="DeleteFile_css1" Value="/Style Library/AcmeWeb/Styles/stylesheet.css" />
<Property Key="DeleteFile_css2" Value="/Style Library/AcmeWeb/Styles/stylesheet-ie.css" />
</Properties>
</Feature>


Then I added the following provisioning code to the deactivate feature reciever:


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;

namespace AcmeWebPublishingFeatures
{
class AcmeWebStyles : SPFeatureReceiver
{
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
}

/// <summary>
/// Delete feature files
/// </summary>
/// <param name="properties">Feature property bag</param>
/// <param name="web">Web that has the feature</param>
void DeleteFeatureFiles(SPFeatureReceiverProperties properties, SPWeb web)
{
using (web)
foreach (SPFeatureProperty p in properties.Feature.Properties)
{
if (p.Name.StartsWith("DeleteFile_"))
{
SPFile file = web.GetFile(p.Value);
if (file != null) file.Delete();
}
}
}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
DeleteFeatureFiles(properties, ((SPSite)(properties.Feature.Parent)).RootWeb);
}

public override void FeatureInstalled(SPFeatureReceiverProperties properties)
{
}

public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
}
}
}

Minimal Master Page for Sharepoint Publishing Sites

Here is my minimal master page for a Sharepoint Publishing Site, the master page is based on the master page presented by Andrew Connell in his book Professional SharePoint 2007 Web Content Management Development: Building Publishing Sites with Office SharePoint Server 2007.



1 <%@ Master language="C#" %>

2 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
3 <%@ Import Namespace="Microsoft.SharePoint" %>

4 <%@ Register Tagprefix="SPSWC" Namespace="Microsoft.SharePoint.Portal.WebControls" Assembly="Microsoft.SharePoint.Portal, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

5 <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

6 <%@ Register Tagprefix="WebPartPages" Namespace="Microsoft.SharePoint.WebPartPages" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

7 <%@ Register Tagprefix="PublishingWebControls" Namespace="Microsoft.SharePoint.Publishing.WebControls" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

8 <%@ Register Tagprefix="PublishingNavigation" Namespace="Microsoft.SharePoint.Publishing.Navigation" Assembly="Microsoft.SharePoint.Publishing, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>

9 <%@ Register TagPrefix="wssuc" TagName="Welcome" src="~/_controltemplates/Welcome.ascx" %>

10 <%@ Register TagPrefix="wssuc" TagName="DesignModeConsole" src="~/_controltemplates/DesignModeConsole.ascx" %>

11 <%@ Register TagPrefix="PublishingVariations" TagName="VariationsLabelMenu" src="~/_controltemplates/VariationsLabelMenu.ascx" %>

12 <%@ Register Tagprefix="PublishingConsole" TagName="Console" src="~/_controltemplates/PublishingConsole.ascx" %>

13 <%@ Register TagPrefix="PublishingSiteAction" TagName="SiteActionMenu" src="~/_controltemplates/PublishingActionMenu.ascx" %>

14
15 <html id="Html1" dir="<%$Resources:wss, multipages_direction_dir_value %>" runat="server" __expr-val-dir="ltr">

16 <WebPartPages:SPWebPartManager ID="SPWebPartManager1" runat="server"/>
17 <SharePoint:RobotsMetaTag ID="RobotsMetaTag1" runat="server"/>

18 <head id="Head1" runat="server">
19 <title id="onetidTitle"><asp:ContentPlaceHolder id="PlaceHolderPageTitle" runat="server"/></title>

20 <Sharepoint:CssLink ID="CssLink1" runat="server"/>
21 <SharePoint:ScriptLink ID="ScriptLink1" name="init.js" runat="server"/>

22 <asp:ContentPlaceHolder id="AdditionalHeaders" runat="server"/>
23 </head>
24 <body class="OWBody" onload="javascript:_spBodyOnLoadWrapper();">

25 <form id="Form1" runat="server" onsubmit="return _spFormOnSubmitWrapper();">
26 <wssuc:Welcome id="explitLogout" runat="server" />

27 <PublishingSiteAction:SiteActionMenu runat="server" />
28 <PublishingWebControls:AuthoringContainer id="authoringcontrols" runat="server">

29 <PublishingConsole:Console runat="server" />
30 </PublishingWebControls:AuthoringContainer>
31 <asp:ContentPlaceHolder ID="PlaceHolderMain" runat="server" />

32 <asp:Panel ID="DontRemoveMe" Visible="false" runat="server">
33 <%-- These ContentPlaceHolders are only necessary to ensure all out of the box MOSS 2007 pages render with this master page. If the system master page is set to any out of the box master pages, the only content placeholders required are those that are being overridden by your page layouts. --%>

34 <asp:ContentPlaceHolder ID="PlaceHolderSearchArea" runat="server" />
35 <asp:ContentPlaceHolder ID="PlaceHolderTitleBreadcrumb" runat="server" />

36 <asp:ContentPlaceHolder ID="PlaceHolderPageTitleInTitleArea" runat="server" />
37 <asp:ContentPlaceHolder ID="PlaceHolderLeftNavBar" runat="server" />

38 <asp:ContentPlaceHolder ID="PlaceHolderPageImage" runat="server" />
39 <asp:ContentPlaceHolder ID="PlaceHolderBodyLeftBorder" runat="server" />

40 <asp:ContentPlaceHolder ID="PlaceHolderNavSpacer" runat="server" />
41 <asp:ContentPlaceHolder ID="PlaceHolderTitleLeftBorder" runat="server" />

42 <asp:ContentPlaceHolder ID="PlaceHolderTitleAreaSeparator" runat="server" />
43 <asp:ContentPlaceHolder ID="PlaceHolderMiniConsole" runat="server" />

44 <asp:ContentPlaceHolder ID="PlaceHolderCalendarNavigator" runat="server" />
45 <asp:ContentPlaceHolder ID="PlaceHolderLeftActions" runat="server" />

46 <asp:ContentPlaceHolder ID="PlaceHolderPageDescription" runat="server" />
47 <asp:ContentPlaceHolder ID="PlaceHolderBodyAreaClass" runat="server" />

48 <asp:ContentPlaceHolder ID="PlaceHolderTitleAreaClass" runat="server" />
49 </asp:Panel>
50 </form>

51 </body>
52 </html>

lørdag, oktober 03, 2009

Using PROPFIND to query Sharepoint

It is possible to use a HTTP PROPFIND call to get all sorts of information about Sharepoint-, Office-, and other files on Web servers without actually using the Sharepoint API, a lot of information can be gathered from a remote client.Here I have made a simple example of how to achieve this:




/// <summary>
/// Returns the properties for a Sharepoint document or collection of documents
/// </summary>
/// <param name="Url">Url to the Sharepoint document or collection of Sharepoint documents</param>
/// <param name="domain">Domain is used if anonymous HTTP requests are forbidden to the Url</param>
/// <param name="username">User name is used if anonymous HTTP requests are forbidden to the Url</param>
/// <param name="password">Password is used if anonymmous HTTP requests are forbidden to the Url</param>
public bool CallSharepoint(string Url, string domain, string username, string password)
{
HttpWebRequest HTTPDoc = (HttpWebRequest)HttpWebRequest.Create(Url);
HTTPDoc.Method = "PROPFIND"; // Use the propfind method to retrieve the properties
HTTPDoc.ContentType = "text/xml";

NameValueCollection form = new NameValueCollection();
try
{
// Manually build a string that will contain the WebDav query
string body = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" +
"<a:propfind xmlns:f=\"urn:schemas-microsoft-com:office:office\" xmlns:c=\"xml:\" xmlns:a=\"DAV:\"

xmlns:e=\"urn:schemas-microsoft-com:publishing:\" xmlns:b=\"urn:schemas-microsoft-com:datatypes\">"
+
"<a:prop>" +
"<a:contentclassobject/>" +
"<a:HasChildren/>" +
"<a:contentclass/>" +
"<e:User/>" +
"<a:href/>" +
"<e:FriendlyVersionID/>" +
"<e:Domain/>" +
"<a:getlastmodified/>" +
"<a:getcontentlength/>" +
"<f:Author/>" +
"<e:owner/>" +
"<a:displayname/>" +
"<a:creationdate/>" +
"<f:Description/>" +
"<f:CustomField01/>" +
"<e:Comment/>" +
"<f:Title/>" +
"<a:searchrequest />" +
"</a:prop>" +
"</a:propfind>";

HTTPDoc.ContentLength = Encoding.ASCII.GetByteCount(body);

// No username means anonymous
if (username.Length > 0)
{
HTTPDoc.Credentials = new System.Net.NetworkCredential(username, password, domain);
}

// Send the HTTP request with the WebDav query
Stream requestStream = HTTPDoc.GetRequestStream(); // Used for a HTTP response container
requestStream.Write(Encoding.ASCII.GetBytes(body), 0, Encoding.ASCII.GetByteCount(body));
requestStream.Close(); // All done, close connection
// Get the response from the webserver
HttpWebResponse Response = (HttpWebResponse)HTTPDoc.GetResponse();
StreamReader respStream = new StreamReader(Response.GetResponseStream());
txtOutput.Text = respStream.ReadToEnd();

}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return false;
}

return true;
}


In the example code I have only tried to get certain data, see the namespace documentations in MSDN for more options.

mandag, mai 25, 2009

Imindi - Collective Mind Map

Imindi lets you create your own mind map and merge them with other related mind maps using semanic indexing technologies.

Currently in an invite beta stage only.

Article:
http://www.techcrunch.com/2009/05/25/connect-your-thoughts-to-the-mindex-with-imindi-private-beta-invites/

Presentation from last year:
http://www.techcrunch.com/2008/09/09/imindi-wants-to-get-inside-your-head/

Homepage:
http://www.imindi.com

torsdag, april 09, 2009

New version of TMInspector

These bugs have been fixed in this version of TMInspector:
  • XTM 1.0 & 2.0 DTD validation issues
  • XTM 1.0 & 2.0 reification of topic map constructs issues
In addition these new features have been added:
  • XTM 1.0 data types are now supported (optional); ex. 'export 1.0 mymap.xtm true'. Note that is is an extension of the standard, thus you will not be able to import the map into topic map engines that uses some kind of XTM schema validation
  • XTM 1.0 typed names are now supported (optional); ex. 'export 1.0 mymap.xtm false true'. Note that is is an extension of the standard but many topic map engine supports it
Click here to get the latest Windows(R) version of TMInspector executable.

If you use other operating systems than Windows(R) you can get TMInspector from the TM++ example suite, you will first need to compile TM++ since there are several changes to it, here is how to do it all:

svn co https://tmplusplus.svn.sourceforge.net/svnroot/tmplusplus/trunk tmplusplus
cd tmplusplus
./configure --prefix=/usr
make clean
make check

sudo make install
cd Examples/Cpp/TMInspector
./configure
--prefix=/usr
make clean
make
sudo make install
tminspector