<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>xscDevBlog - LastSharp &#38; Co.</title>
	<atom:link href="http://dev.xscheme.de/feed/" rel="self" type="application/rss+xml" />
	<link>http://dev.xscheme.de</link>
	<description>Der xscheme-DevelopmentBlog</description>
	<lastBuildDate>Sun, 23 May 2010 11:40:10 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>[Release] LastSharp 0.4.5 Incarnation 2</title>
		<link>http://dev.xscheme.de/2010/05/release-lastsharp-0-4-5-incarnation-2/</link>
		<comments>http://dev.xscheme.de/2010/05/release-lastsharp-0-4-5-incarnation-2/#comments</comments>
		<pubDate>Sun, 23 May 2010 11:40:10 +0000</pubDate>
		<dc:creator>WordPress</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=1008</guid>
		<description><![CDATA[Nachdem ich jetzt das wahre Problem gefunden habe, das LastSharp davon abhielt, weiterhin Lieder herunterzuladen, stelle ich hiermit eine neue Version zur Verfügung:
Download: http://files.xscheme.de/LastSharp/LastSharp0.4.5-incarnation2.zip
Der Zusatz &#8220;Incarnation 2&#8243; rührt von der Tatsache her, dass ich aktuell an einer komplett neuen Version arbeite, die mit dieser nicht mehr viel gemein hat. Und da es auch zuvor schonmal [...]]]></description>
			<content:encoded><![CDATA[<p>Nachdem ich jetzt das wahre Problem gefunden habe, das LastSharp davon abhielt, weiterhin Lieder herunterzuladen, stelle ich hiermit eine neue Version zur Verfügung:</p>
<p><strong>Download: </strong><a href="http://files.xscheme.de/LastSharp/LastSharp0.4.5-incarnation2.zip">http://files.xscheme.de/LastSharp/LastSharp0.4.5-incarnation2.zip</a></p>
<p>Der Zusatz &#8220;Incarnation 2&#8243; rührt von der Tatsache her, dass ich aktuell an einer komplett neuen Version arbeite, die mit dieser nicht mehr viel gemein hat. Und da es auch zuvor schonmal so einen Neuanfang gegeben hat, ist die passende Zahl eben die &#8220;2&#8243;.</p>
<p>Scrobbling sollte nun auch wieder funktionieren, außerdem gibt es eine Möglichkeit, sich nun auch bei noch nicht endgültigen Releases über Updates informieren zu lassen (unter &#8220;Erweiterte Einstellungen&#8221; das Häckchen bei &#8220;Nur stabile Versionen melden&#8221; entfernen).</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2010/05/release-lastsharp-0-4-5-incarnation-2/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>LastSharp 0.4.4 patched</title>
		<link>http://dev.xscheme.de/2010/05/lastsharp-0-4-4-patched/</link>
		<comments>http://dev.xscheme.de/2010/05/lastsharp-0-4-4-patched/#comments</comments>
		<pubDate>Fri, 21 May 2010 22:17:12 +0000</pubDate>
		<dc:creator>xsc</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/2010/05/lastsharp-0-4-4-patched/</guid>
		<description><![CDATA[Siehe der folgende Eintrag im Forum:
http://devboard.xscheme.de/read.php?1,706
]]></description>
			<content:encoded><![CDATA[<p>Siehe der folgende Eintrag im Forum:</p>
<p><a href="http://devboard.xscheme.de/read.php?1,706">http://devboard.xscheme.de/read.php?1,706</a></p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2010/05/lastsharp-0-4-4-patched/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Release] SharpConnect 1.0.0</title>
		<link>http://dev.xscheme.de/2010/03/release-sharpconnect-1-0-0/</link>
		<comments>http://dev.xscheme.de/2010/03/release-sharpconnect-1-0-0/#comments</comments>
		<pubDate>Sun, 21 Mar 2010 18:41:49 +0000</pubDate>
		<dc:creator>WordPress</dc:creator>
				<category><![CDATA[Projekte]]></category>
		<category><![CDATA[Theorie]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=1001</guid>
		<description><![CDATA[Die erste Version von SharpConnect (einer Bibliothek zum Zugriff auf Web-APIs, z.B. dem von Last.FM) steht nun der Öffentlichkeit zur Verfügung. Und zwar auf der neu eingerichteten Wiki-Seite:
http://wiki.xscheme.de/index.php?p=sharpconnect
]]></description>
			<content:encoded><![CDATA[<p>Die erste Version von SharpConnect (einer Bibliothek zum Zugriff auf Web-APIs, z.B. dem von Last.FM) steht nun der Öffentlichkeit zur Verfügung. Und zwar auf der neu eingerichteten Wiki-Seite:</p>
<p><a href="http://wiki.xscheme.de/index.php?p=sharpconnect">http://wiki.xscheme.de/index.php?p=sharpconnect</a></p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2010/03/release-sharpconnect-1-0-0/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>[Proof of Concept] SharpConnect</title>
		<link>http://dev.xscheme.de/2010/03/proof-of-concept-sharpconnect/</link>
		<comments>http://dev.xscheme.de/2010/03/proof-of-concept-sharpconnect/#comments</comments>
		<pubDate>Wed, 03 Mar 2010 00:22:40 +0000</pubDate>
		<dc:creator>WordPress</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Projekte]]></category>
		<category><![CDATA[Theorie]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=989</guid>
		<description><![CDATA[Nachdem ich in den letzten Tagen an einem Konzept getüftelt habe, wie man verschiedene webbasierte APIs einfach zugänglich machen könnte, möchte ich nun eine beispielhafte Implementierung vorführen: SharpConnect. (Download DLL) Und das Ziel meiner Wahl ist natürlich Last.FM, was auch sonst. Wohlgemerkt gehe ich hier nicht auf die Umsetzung ein, nur auf die Verwendung.
Es stellt [...]]]></description>
			<content:encoded><![CDATA[<p>Nachdem ich in den letzten Tagen an einem <a href="http://dev.xscheme.de/2010/03/concept-generischer-api-zugriff/">Konzept</a> getüftelt habe, wie man verschiedene webbasierte APIs einfach zugänglich machen könnte, möchte ich nun eine beispielhafte Implementierung vorführen: <strong>SharpConnect</strong>. (<a href="http://dev.xscheme.de/sources/LastConnect.dll">Download DLL</a>) Und das Ziel meiner Wahl ist natürlich Last.FM, was auch sonst. Wohlgemerkt gehe ich hier nicht auf die Umsetzung ein, nur auf die Verwendung.</p>
<p>Es stellt sich zuerst die Frage: <strong>Was wollen wir?</strong> Ich für meinen Teil würde z.B. gerne wissen, wo und wann Kasabian demnächst Konzerte geben (Nicht, dass die Chance bestünde, das München auf der Liste wäre, aber dennoch&#8230;), und somit böte sich der API-Aufruf <a href="http://www.lastfm.de/api/show/?service=117">artist.getEvents</a> zur näheren Betrachtung an: <strong>Welche Parameter hat er, wie muss er ausgeführt werden und wie sieht die Antwort aus?</strong></p>
<p>Wir sehen, dass es zwei Parameter gibt (&#8220;artist&#8221; und &#8220;api_key&#8221;, beide benötigt) und dass die Antwort ein XML-Dokument ist, dass die Wurzel &#8220;lfm&#8221; hat, anschließend den Knoten &#8220;events&#8221; und viele Kindknoten &#8220;event&#8221;, die die einzelnen Konzerte enthalten. Diese wiederum besitzen Werte für die auftretenden Künstler, den Ort, die Zeit, Ticketverkäufe, etc&#8230; Das Beispiel von der API-Seite:</p>
<pre class="brush:xml">&lt;events artist="Cher" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" total="4"&gt;
&lt;event&gt;
    &lt;id&gt;599858&lt;/id&gt;
  &lt;title&gt;Cher&lt;/title&gt;
  &lt;artists&gt;
    &lt;artist&gt;Cher&lt;/artist&gt;
    &lt;headliner&gt;Cher&lt;/headliner&gt;
  &lt;/artists&gt;
  &lt;venue&gt;
    &lt;name&gt;The Colosseum at Caesars Palace&lt;/name&gt;
    &lt;location&gt;
      &lt;city&gt;Las Vegas&lt;/city&gt;
      &lt;country&gt;United States&lt;/country&gt;
      &lt;street&gt;&lt;/street&gt;
      &lt;postalcode&gt;&lt;/postalcode&gt;
      &lt;geo:point&gt;
         &lt;geo:lat&gt;36.2265501474709&lt;/geo:lat&gt;
         &lt;geo:long&gt;-115.0048828125&lt;/geo:long&gt;
      &lt;/geo:point&gt;
      &lt;timezone&gt;PST&lt;/timezone&gt;
     &lt;/location&gt;
    &lt;url&gt;http://www.last.fm/venue/8841108&lt;/url&gt;
  &lt;/venue&gt;
  &lt;startDate&gt;Sat, 16 Aug 2008&lt;/startDate&gt;
  &lt;startTime&gt;19:30&lt;/startTime&gt;
  &lt;description&gt;&lt;/description&gt;
  &lt;image size="small"&gt;...&lt;/image&gt;
  &lt;image size="medium"&gt;...&lt;/image&gt;
  &lt;image size="large"&gt;...&lt;/image&gt;
  &lt;attendance&gt;42&lt;/attendance&gt;
  &lt;reviews&gt;0&lt;/reviews&gt;
  &lt;tag&gt;lastfm:event=669027&lt;/tag&gt;
  &lt;url&gt;http://www.last.fm/event/599858&lt;/url&gt;
  &lt;website&gt;http://...&lt;/website&gt;
  &lt;tickets&gt;
    &lt;ticket supplier="..."&gt;http://...&lt;/ticket&gt;
    ...
  &lt;/tickets&gt;
&lt;/event&gt;
...
&lt;/events&gt;
</pre>
<p><span id="more-989"></span>SharpConnect stellt die folgenden Klassen zur Verfügung:</p>
<ul>
<li><strong>SharpConnect.Apitizer.Apitizer</strong> bzw. <strong>SharpConnect.Xml.XmlApitizer</strong> zur Verwaltung von Methoden</li>
<li><strong>SharpConnect.Apitizer.Method</strong> zur Darstellung von Methoden</li>
<li><strong>SharpConnect.Apitizer.Parameters</strong> zur Darstellung von Parametern</li>
<li><strong>SharpConnect.Apitizer.Accessor</strong> als Zugriffsklasse für Antworten</li>
<li><strong>SharpConnect.Apitizer.Rule</strong> bzw. <strong>SharpConnect.Xml.XmlRule</strong> zur Darstellung von Accessor-Regeln</li>
<li><strong>SharpConnect.Apitizer.Codec</strong> bzw. <strong>SharpConnect.Xml.XmlCodec</strong> zur Umwandlung von Anfragen und Antworten.</li>
</ul>
<p>Mehr brauchen wir eigentlich nicht, und auch, wenn das keine wirklich kurze Liste ist, die Verwendung der einzelnen Klassen ist nicht besonders kritisch. Beginnen wir mit dem schwersten, dem <strong>Codec</strong>.</p>
<p>Wenn wir diesen auf Basis von XmlCodec aufbauen, haben wir die Hälfte schon geschafft:  die Antworten (<em>Response</em>) werden automatisch in einen Accessor für XML umgewandelt und können anschließend anhand der Regeln, die wir noch definieren werden, durchlaufen werden. Was wir noch machen müssen, ist, die Daten, die gesendet werden sollen (<em>Request</em>), vorzubereiten. LastFM erwartet die einzelnen Parameter als Query-String von Name-Wert-Paaren, also z.B.:</p>
<pre class='brush:plain'>method=artist.getEvents&amp;artist=Cher&amp;api_key=b25b959554ed76058ac220b7b2e0a026</pre>
<p>Der API-Key wird immer angehängt, bei Anfragen, die Daten verändern, sogar noch eine Session und ein API-Secret, diese lassen wir jedoch hier unter den Tisch fallen. Man muss es ja nicht gleich übertreiben. Unser Last.FM Codec könnte also folgendermaßen aussehen:</p>
<pre class="brush:c-sharp"> public class LastFMCodec : XmlCodec
 {
   private string apiKey;

   public LastFMCodec(string key)
     : base("lfm", null)
   {
     this.apiKey = key;
   }

   public override Request Encode(Method m, Parameters p)
   {
     string method = m.Name;
     string query = "method=" + method + "&amp;";
     query += p.QueryString("&amp;", "=");
     query += "api_key=" + this.apiKey + "&amp;";
     if (m.IsPOST) return new Request("", query);
     else return new Request(query, "");
   }
 }
</pre>
<p>Das wars auch schon. Das meiste wird ohnehin von SharpConnect erledigt, sodass wir uns nun auf den <strong>Apitizer</strong> konzentrieren können. Auch hier ist die Klasse XmlApitizer eine wunderbare Grundlage, die nicht viele Ergänzungen benötigt:</p>
<pre class="brush:c-sharp"> public class LastFMApitizer : XmlApitizer
 {
   public LastFMApitizer(string key, WebProxy p)
     : base("http://ws.audioscrobbler.com/2.0/", new LastFMCodec(key), p)
   {
      AddMethods(this);
   }

   private static void AddMethods(XmlApitizer api) {
     // Methods here!
   }
 }
</pre>
<p>Wir haben nun also einen Apitizer erstellt, der alle Anfragen an &#8220;http://ws.audioscrobbler.com/2.0/&#8221; sendet und den soeben definierten Codec verwendet. Nun müssen wir dem Apitizer nur noch sagen, was er eigentlich kann.</p>
<p>Eine Methode wird definiert durch</p>
<ul>
<li>einen Namen,</li>
<li>eine Liste von Parameter-Namen,</li>
<li>eine Liste von boolschen Werten, die angibt, welche Parameter benötigt werden, sowie</li>
<li>einen Wert der angibt, ob die Anfrage über HTTP-POST läuft oder nicht.</li>
</ul>
<p>In unserem Fall sieht dies nun folgendermaßen aus (Der API-Key wird im Encoder automatisch hinzugefügt!):</p>
<pre class="brush:c-sharp"> Method artistGetEvents = new Method(
   "artist.getEvents",
   new String[] { "artist" },
   new bool[] { true },
   false
 );</pre>
<p>Was machen wir nun mit der Antwort dieses Aufrufs? Die Antwort: wir verwenden die Klasse <strong>XmlRule</strong>, um Zuordnungen zwischen Attributnamen und Knoten des Antwortdokuments herzustellen. Das Mittel der Wahl ist hierbei XPath.</p>
<pre class="brush:c-sharp;"> XmlRule Image = new XmlRule();
 Image.Set("URL", "self::node()");
 Image.Set("Size", "@size");

 XmlRule Event = new XmlRule();
 Event.Set("Name", "title");
 Event.Set("ID", "id");
 Event.Set("Artists", "artists/artist");
 Event.Set("Headliner", "artists/headliner");
 Event.Set("Date", "startDate");
 Event.Set("Time", "startTime");
 Event.Set("Description", "description");
 Event.Set("Images", "image", Image);             // !!!
 Event.Set("Attendance", "attendance");
 Event.Set("ReviewCount", "reviews");
 Event.Set("UniqueTag", "tag");
 Event.Set("Website", "website");

 XmlRule rule = new XmlRule();
 rule.Set("Count", "/lfm/events/@total");
 rule.Set("Events", "/lfm/events/event", Event); // !!!</pre>
<p>Zuerst wird eine Bild-Regel definiert: das Attribut &#8220;URL&#8221; liefert den Wert des Knotens, &#8220;Size&#8221; den Wert des &#8220;size&#8221;-Attributs. Die beiden blauen Zeilen zeigen die Verwendung von bestehenden Regeln als Unterobjekte: die Regel &#8220;Image&#8221; ist auf alle Knoten anwendbar, die über das Attribut &#8220;Images&#8221; gefunden werden, d.h. jeder Knoten aus &#8220;Images&#8221; erlaubt wieder Zugriff auf &#8220;URL&#8221; und &#8220;Size&#8221;. Gleiches für &#8220;Events&#8221;: alle Knoten, die über den XPath-Ausdruck &#8220;/lfm/events/event&#8221; gefunden werden, haben Attribute &#8220;Name&#8221;, &#8220;ID&#8221;, &#8220;Artists&#8221;, &#8230;</p>
<p>Wir müssen nur noch dem Decoder sagen, dass er diese Regel verwenden soll, wenn er eine Antwort auf eine &#8220;artist.getEvents&#8221;-Anfrage erhält. Dies geschieht durch gleichzeitiges Registrieren der Methode im Apitizer und Codec mittels &#8220;Apitizer.Method&#8221; (Wir befinden uns wieder in der statischen Funktion &#8220;AddMethods&#8221; von oben):</p>
<pre class="brush:c-sharp;">api.Method(artistGetEvents, rule);
</pre>
<p>Und nun sind wir fertig.</p>
<h2>Beispiel gefällig?</h2>
<p>Das folgende Beispiel funktioniert mit meiner aktuellen Implementierung von SharpConnect. Neu im Vergleich zum eben besprochenen ist nur die Klasse &#8220;LastFMValue&#8221;, die den Accessor für XML-Dokumente darstellt:</p>
<pre class="brush:c-sharp;"> LastFMApitizer lfm = new LastFMApitizer("b25b959554ed76058ac220b7b2e0a026", "", null);

 LastFMValue resp = lfm.Execute("artist.getEvents", new Parameters(
   "artist", "Kasabian"
 ));
 if (resp != null)
 {
   Console.Write(resp.ToString()); // oder z.B. Console.Write(resp.All("Events")[2].Value("Date"));
 }
 Console.ReadLine();
</pre>
<p>Die Ausgabe sieht so oder  ähnlich aus (auf all diese Attribute und Array-Elemente könnte man mittels &#8220;resp.Get(attribut)&#8221;  und &#8220;resp.All(attribut)&#8221; zugreifen, vgl. den Concept-Artikel):</p>
<pre>  Status : ok
  Count : 14
  Events[0] :
    Status : ok
    Name : Kasabian
    ID : 1408186
    URL : http://www.last.fm/event/1408186+Kasabian+at+Tivoli+Oudegracht+on+27+May+2010
    Artists : Kasabian
    Headliner : Kasabian
    Date : Thu, 27 May 2010 12:08:01
    Description : ...
    Images[0] :
      URL : http://userserve-ak.last.fm/serve/34/284053.jpg
      Size : small
    Images[1] :
      URL : http://userserve-ak.last.fm/serve/64/284053.jpg
      Size : medium
    Images[2] :
      URL : http://userserve-ak.last.fm/serve/126/284053.jpg
      Size : large
    Images[3] :
      URL : http://userserve-ak.last.fm/serve/252/284053.jpg
      Size : extralarge
    Attendance : 87
    ReviewCount : 0
    UniqueTag : lastfm:event=1408186
    Website : http://www.tivoli.nl/agenda/informatie/datum/do-27-mei-2010/titel/KASABIAN
  Events[1] :
    Status : ok
    Name : Pinkpop 2010
    ID : 932823
    URL : http://www.last.fm/event/932823+Pinkpop+2010
    Artists[0] : Green Day
    Artists[1] : Pixies
    Artists[2] : Kasabian
    Artists[3] : The Prodigy
    Artists[4] : Rammstein
    Artists[5] : John Mayer
    Artists[6] : Editors
    Artists[7] : Mika
    Artists[8] : Wolfmother
    Artists[9] : Kate Nash
    Artists[10] : Mando Diao
    Artists[11] : Paolo Nutini
    Artists[12] : P!nk
    Artists[13] : Florence + The Machine
    Artists[14] : Skunk Anansie
    Artists[15] : Gogol Bordello
    Artists[16] : Biffy Clyro
    Artists[17] : Yeasayer
    Artists[18] : The Temper Trap
    Artists[19] : Danko Jones
    Artists[20] : Gossip
    Artists[21] : 2 Many DJ's
    Artists[22] : Moke
    Artists[23] : Kitty, Daisy &amp; Lewis
    Artists[24] : Caro Emerald
    Artists[25] : Triggerfinger
    Artists[26] : Destine
    Artists[27] : DeWolff
    Artists[28] : Sungrazer
    Headliner : Green Day
    Date : Fri, 28 May 2010 21:24:01
    Description : ...
    Images[0] :
      URL : http://userserve-ak.last.fm/serve/34/42600061.jpg
      Size : small
    Images[1] :
      URL : http://userserve-ak.last.fm/serve/64/42600061.jpg
      Size : medium
    Images[2] :
      URL : http://userserve-ak.last.fm/serve/126/42600061.jpg
      Size : large
    Images[3] :
      URL : http://userserve-ak.last.fm/serve/252/42600061.jpg
      Size : extralarge
    Attendance : 560
    ReviewCount : 1
    UniqueTag : lastfm:event=932823
    Website : http://www.pinkpop.nl
  Events[2] :
    Status : ok
    Name : Kasabian
  ...
</pre>
<p>Ich arbeite im Moment an einer vollständigen Abbildung des Last.FM-APIs, auch wenn ich nicht weiß, ob ich das nicht lieber jedem selbst überlassen sollte. In den Worten von Morpheus:</p>
<p><strong>I can only show you the door, you have to  walk through it!</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2010/03/proof-of-concept-sharpconnect/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>[Concept] Generischer API-Zugriff</title>
		<link>http://dev.xscheme.de/2010/03/concept-generischer-api-zugriff/</link>
		<comments>http://dev.xscheme.de/2010/03/concept-generischer-api-zugriff/#comments</comments>
		<pubDate>Tue, 02 Mar 2010 00:16:59 +0000</pubDate>
		<dc:creator>WordPress</dc:creator>
				<category><![CDATA[Theorie]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=983</guid>
		<description><![CDATA[Eines der größten Hindernisse beim Zugriff auf die Cloud, also die riesigen Datenmengen, die im Internet schweben, sowie die darauf basierenden Dienste, ist die Tatsache, dass die vielen verfügbaren APIs oftmals grundsätzlich verschieden sind. Dementsprechend ist es schwer, die eigene Arbeit, das eigene Wissen auf unterschiedliche Dienste/WebServices/APIs anzuwenden oder zu recyclen. Man beginnt meist wieder [...]]]></description>
			<content:encoded><![CDATA[<p>Eines der größten Hindernisse beim Zugriff auf die Cloud, also die riesigen Datenmengen, die im Internet schweben, sowie die darauf basierenden Dienste, ist die Tatsache, dass die vielen verfügbaren APIs oftmals grundsätzlich verschieden sind. Dementsprechend ist es schwer, die eigene Arbeit, das eigene Wissen auf unterschiedliche Dienste/WebServices/APIs anzuwenden oder zu recyclen. Man beginnt meist wieder bei Null &#8211; und sei es bloß, die bereits fertige Implementierung eines anderen zu verstehen.</p>
<p>Mein Problem begann beim Last.FM-Webservice: wie kann ich dessen Funktion möglichst einfach zugänglich machen, ohne Flexibilität zu verlieren? Ich wollte nicht auf eine bereits bestehende Lösung zurückgreifen, da dort womöglich viel mehr angeboten als letztendlich benötigt wird; genauso sollte keine neue, nur für Last.FM nutzbare Implementierung geschaffen werden, sei sie auch noch so einfach zu verwenden &#8211; irgendwann müsste dann doch wieder von vorne begonnen werden&#8230; Eine neue Abstraktionsschicht musste her, eine vereinfachte, für den Otto-Normal-Programmierer sinnvolle Minimal-Version von <a href="http://de.wikipedia.org/wiki/Web_Services_Description_Language">WSDL</a> quasi. Etwas, das leicht zu erlernen und zu verwenden ist, ohne unnötigen Ballast.</p>
<h2><span id="more-983"></span><strong>Methoden</strong></h2>
<p>Im Prinzip kann man jede Funktion eines WebServices als <strong>Methode</strong> beschreiben. Diese hat:</p>
<ul>
<li>einen Namen,</li>
<li>eine Reihe von Parametern,</li>
<li>Informationen zu diesen Parametern (Typ? Optionaler Parameter?),</li>
<li>sowie ein Zugriffsprotokoll</li>
<li>und ein Antwortformat.</li>
</ul>
<p>Je genauer man Methoden beschreibt, desto sicherer kann man sich sein, dass ein Aufruf, der alle Anforderungen erfüllt, auch wirklich erfolgreich ist. Nur: die Daten, die so fällig werden, nehmen schnell an Größe und Komplexität zu, sodass man eigentlich nicht umhin kann, das Messer anzusetzen und so viel wie möglich wegzuschneiden:</p>
<ul>
<li>Zugriffsprotokoll:<br />
So ziemlich alle wichtigen WebServices sind über HTTP ansprechbar. Es ist nicht verwerflich, sich hierauf zu begrenzen.</li>
<li>Parametertypen:<br />
Letztlich erfolgt an irgendeiner Stelle immer eine Umwandlung in Strings, vor allem bei textbasierten Protokollen wie HTTP. Ersparen wir uns also die statische Typisierung, die ohnehin schwer zu implementieren ist.</li>
<li>Antwortformat:<br />
Auch hier könnte man sagen, dass man an XML ohnehin nicht vorbeikommt, allerdings ist in diesem Bereich Flexibilität wichtig: neue Formate wie JSON sind auf dem Vormarsch, vor allem für einfachere Anwendungen. Einigen wir uns darauf: <strong>Die Methode muss nicht wissen, wie ihre Antwort aussieht!</strong></li>
</ul>
<p>Übrig bleibt das in folgender Schreibweise zusammengefasste bisschen Information:</p>
<pre>Methode   M  = (Name, HTTP-Methode, [Parameter P1, Parameter P2, ...])
Parameter Px = (Name, required?)</pre>
<p>Als Beispiel sei der Aufruf <a href="http://www.lastfm.de/api/show?service=267">artist.getInfo</a> des Last.FM-APIs notiert:</p>
<pre>Methode M1   = (artist.getInfo, GET, (artist, false), (mbid, false), (username, false), (lang, false))</pre>
<p>Diese Methode ist bewusst gewählt: die Spezifikation besagt, dass sie <em>entweder</em> mit einem Künstlernamen (artist) <em>oder</em> einer Musicbrainz-ID aufgerufen werden kann. Dies haben wir hier nicht abgebildet, können wir aber gut und gerne dem Nutzer überlassen oder eben nachholen, indem wir zwei verschiedene Methoden definieren:</p>
<pre>Methode M1   = (artist.getInfo, GET, (artist, true), (username, false), (lang, false))
Methode M2   = (artist.getInfo, GET, (mbid, true), (username, false), (lang, false))</pre>
<p>Wir können jede Operation, die ein WebService bietet, so aufschreiben &#8211; und viel wichtiger: wir können dies in jeder objektorientierten Sprache sehr einfach implementieren. Ein paar Konventionen zur Schreibweise sind jedoch noch nötig:</p>
<ul>
<li>Methodenaufruf:
<pre>Aufruf A = M(P1 -&gt; V1, P2 -&gt; V2, ...)</pre>
<p>Der Parameter P1 wird mit V1 belegt, usw&#8230; z.B. für artist.getInfo (s.o.):</p>
<pre>Aufruf A1 = M1(artist -&gt; Kasabian, username -&gt; xschemer, lang -&gt; de)</pre>
<p>Die Reihenfolge der Parameter ist unerheblich.</li>
<li>Methodenaufruf ohne Parameterzuordnung:
<pre>Aufruf A = M(V1, V2, V3, ...)</pre>
<p>V entspricht dem ersten in der Definition angegebenen Parameter, usw&#8230; Semantisch identisch zum obigen Beispiel:</p>
<pre>Aufruf M1(Kasabian, xschemer, de)</pre>
</li>
</ul>
<p>Die Definition eines APIs haben wir erledigt, den Methodenaufruf spezifiziert. Aber was machen wir nun damit?</p>
<h2>Request, Response &amp; Codec</h2>
<p>Ein WebService kann mit einer Methode erst etwas anfangen, wenn sie in dem Format aufgerufen wird, dass er versteht. Für Last.FM muss z.B. immer ein &#8220;method&#8221;-Parameter übergeben werden, der den Namen enthält, zusätzlich noch der API-Key, evtl. eine Session und eine Signatur.</p>
<p>Damit wir einen Aufruf in das richtige Format bringen können, brauchen wir einen sog. Codec, also einen <em>Umwandler</em>. Er nimmt einen Methodenaufruf und produziert daraus die URL, an die eine Anfrage geschickt wird, sowie die Daten, die gesendet werden. Ebenso verarbeitet er die Antwort des Servers zu einem standardisierten Objekt (Accessor), das weiter unten beschrieben ist. Im Prinzip handelt es sich also nur um zwei separate Funktionen, konkretisiert:</p>
<pre>Request  Rq = (URL, Daten)
Response Rp = (Request, Daten)
Codec    C  = (Encoder, Decoder)
Encoder  E  = Funktion: Aufruf -&gt; Request
Decoder  D  = Funktion: Response -&gt; Accessor</pre>
<p>Wenn wir hier aufhören, haben wir folgenden Datenfluss:</p>
<pre>User -&gt; Codec -&gt; Encoder -&gt; WebService -&gt; Decoder -&gt; Codec -&gt; User</pre>
<p>Was uns immer noch fehlt ist eine Überprüfung, ob zumindest alle benötigten Parameter vorhanden sind. Zwar könnte man diese in den Encoder packen, doch das sollte nicht dessen Aufgabe sein, schließlich müsste er dafür alle Methoden kennen, was schlicht und einfach keinen Sinn macht.</p>
<h2>Apitizer &#8211; Wächter der Methoden</h2>
<p>Diese Verwaltung wird also in ein neues Objekt verlagert, den <strong>Apitizer</strong>. Er übernimmt die folgenden Aufgaben:</p>
<ul>
<li>Speicherung aller verfügbaren Methoden,</li>
<li>Verwaltung genau <span style="text-decoration: underline;">eines</span> Codecs,</li>
<li>Auswahl der passenden Methode zu einem Name-Parameterliste-Paar,</li>
<li>sowie Überprüfung von Parameterlisten auf Vollständigkeit.</li>
</ul>
<p>Jede Kommunikation eines Users mit dem API sollte über den Apitizer laufen, nicht direkt über Encoder und Decoder! Das folgende Bild soll das nochmals verdeutlichen:</p>
<p><a href="http://dev.xscheme.de/wp-content/uploads/2010/03/Apitizer.png"><img class="aligncenter size-full wp-image-984" style="margin: 0.5em; border: solid 1px #ddd; padding: 0.5em;" title="Apitizer" src="http://dev.xscheme.de/wp-content/uploads/2010/03/Apitizer.png" alt="" width="644" height="444" /></a></p>
<p>Was man hier auch sieht, ist die Möglichkeit, des Encoders/Decoders auf externe Daten zurückzugreifen, z.B. den API-Key bei Last.FM. Aber nun erstmal zum wohl wichtigsten Teil dieses Konzepts, den Accessor.</p>
<h2>Accessor</h2>
<p>Wenn wir eine Antwort bekommen, interessieren uns bestimmte Teile davon. Allerdings existieren unterschiedliche Formate, unterschiedliche Strukturen. Es gilt also, diese auf ein einfaches Konzept zurückzuführen.</p>
<p>Betrachten wir die grundsätzlichen Arten von Daten, die es gibt:</p>
<ul>
<li>einzelne Werte,</li>
<li>Mengen von Werten,</li>
<li>Zusammengesetzte Strukturen,</li>
<li>sowie Mengen von zusammengesetzten Strukturen.</li>
</ul>
<p>Definieren wir diese folgendermaßen:</p>
<pre>Wert    V  = String | List | Struct
List    L  = (Wert, Wert, ...)
Struct  S  = (Mapping, Mapping, ...)
Mapping Mp = String -&gt; Wert</pre>
<p>In Worten: ein Wert ist entweder ein String, eine Liste oder eine Struktur; eine Liste ist eine Menge von Werten und eine Struktur ist eine Menge von Zuordnungen von Strings zu Werten. Letzteres entspricht den Attributen eines Objekts. (z.B. kann die Struktur &#8220;Rechteck&#8221; eine Zuordnung &#8220;Höhe&#8221; -&gt; &#8220;10&#8243; besitzen)</p>
<p>Ein Accessor bildet nun beliebige Daten mithilfe von <em>Regeln</em> auf die eben besprochenen Einheiten ab:</p>
<pre>Regel          Rl = (AccessMapping1, AccessMapping2, ...)
AccessMapping  AM = (Attributname, Transformation, Regel)
Transformation T  = Funktion: Daten -&gt; Daten[]
Accessor       Ac = (Daten, Regel)</pre>
<p>Der Accessor muss in der Lage sein, die folgenden Operationen auszuführen:</p>
<ul>
<li>das passende Mapping zu einem Attributnamen finden,</li>
<li>den aktuellen Daten-Wert als String ausgeben,</li>
<li>einen Accessor erstellen, der einem Attribut entspricht,</li>
<li>eine Menge von Accessors erstellen, die einer Menge von Attribut-Werten entspricht.</li>
</ul>
<p>Und wieder wird definiert (das ist keine besondere Beschreibungssprache, nur Pseudo-Code):</p>
<pre>Accessor.map(attribut)  -&gt; AccessMapping
Accessor.value()        -&gt; (String) Accessor.Daten
Accessor.get(attribut)  -&gt; Accessor.all().firstElement
Accessor.all(attribut)  -&gt;
    m = Accessor.map(attribut);
    d = m.Transformation(Accessor.Daten);
    Array for all d[n]: new Accessor(d[n], m.Regel)</pre>
<p>Es wird Zeit für ein Beispiel. Und da XML mein Hauptanliegen ist, sollte ich es wohl auch verwenden.</p>
<h2>Beispiel: XML Accessor</h2>
<p>Auf XML-Daten kann mithilfe von XPath zugegriffen werden und dies kann man wunderbar nutzen. Nehmen wir das folgende Dokument:</p>
<pre>&lt;fruitbasket&gt;
  &lt;count&gt;2&lt;/count&gt;
  &lt;fruit&gt;
    &lt;name&gt;Apple&lt;/name&gt;
    &lt;color&gt;red&lt;/color&gt;
  &lt;/fruit&gt;
  &lt;fruit&gt;
    &lt;name&gt;Orange&lt;/name&gt;
    &lt;color&gt;orange&lt;/color&gt;
  &lt;/fruit&gt;
&lt;/fruitbasket&gt;</pre>
<p>Wir können nun Regeln definieren, wobei wir davon ausgehen, dass Transformationen eindeutig durch einen XPath-Ausdruck bestimmt sind und auf dem Wurzelknoten des übergebenen Dokuments arbeiten, z.B. lässt sich auf die Anzahl der Früchte ausgehend vom Wurzelnoten &#8220;fruitbasket&#8221; mittels &#8220;count&#8221; zugreifen:</p>
<pre>Regel Fruitbasket = (
  ("Count", xpath: "count", None),
  ("Fruits", xpath: "fruit", Fruit)
)

Regel Fruit = (
  ("Name", xpath: "name", None),
  ("Color", xpath: "color", None)
)</pre>
<p>Diese Regeln müssen irgendwo im Decoder definiert sein, ebenso eine Zuordnung Methodenname -&gt; Regel, damit der Decoder weiß, für welche Methode er welche Regel verwenden soll. Ein Accessor, der das oben beschriebene Dokument (abgekürzt als FRUITDOC) repräsentiert wäre also:</p>
<pre>Accessor MyBasket = (FRUITDOC, Fruitbasket)</pre>
<p>Wenn man nun die Methode &#8220;all&#8221; für das Attribut &#8220;Fruits&#8221; aufruft, wird der Accessor feststellen, dass dies dem AccessMapping (&#8220;Fruits&#8221;, xpath: &#8220;fruit&#8221;, Fruit) entspricht. Er wendet also die Transformation auf das Dokument an (findet also alle Knoten, die dem XPath-Ausdruck &#8220;fruit&#8221; entsprechen) und erstellt mithilfe der gegebenen Regel Fruit neue Accessors. Das Ergebnis wäre also:</p>
<pre>MyBasket.all("Fruits") = [
  Accessor("&lt;fruit&gt;&lt;name&gt;Apple&lt;/name&gt;...", Fruit),
  Accessor("&lt;fruit&gt;&lt;name&gt;Orange&lt;/name&gt;...", Fruit)
]</pre>
<p>Führen wir nun &#8220;get&#8221; für das Attribut &#8220;Color&#8221; des ersten Ergebnisses (nennen wir es E1) aus, erhalten wir das AccessMapping (&#8220;Color&#8221;, xpath: &#8220;color&#8221;, None). Eine Auswertung des XPath-Ausdrucks liefert hier genau einen Knoten, aus dem der neue Accessor V1 erstellt wird:</p>
<pre>V1 = E1.get("Color") = Accessor("&lt;color&gt;red&lt;/color&gt;", None)</pre>
<p>Und hier können wir den Wert auslesen:</p>
<pre>V1.value() = "red"</pre>
<p>Das gleiche Ergebnis würde übrigens der folgende Ausdruck liefern:</p>
<pre>MyBasket.get("Fruits").get("Color").value()</pre>
<p>Soviel zu Accessors.</p>
<h2>Warum? Warum? Warum?!</h2>
<p>Wie anfangs (und das ist lange her) erwähnt, arbeite ich an meiner Version des Last.FM-APIs auf Basis dieses Konzepts. Dieses wiederum wird die Basis für neue Versionen von LastSharp und LeSharp sein, wobei ich v.a. für ersteres Programm grundlegende Änderungen angedacht habe. (Multiuser-Support mit mehreren Downloads, Anhören und Downloaden gleichzeitig, &#8230;)</p>
<p>Es hat also schon alles seinen Sinn. Danke fürs Zuhören.</p>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 2863px; width: 1px; height: 1px; overflow: hidden;">
<pre>Attributname : String, Transformation, Unterregel</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2010/03/concept-generischer-api-zugriff/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>nginx = Wow!</title>
		<link>http://dev.xscheme.de/2010/02/nginx-wow/</link>
		<comments>http://dev.xscheme.de/2010/02/nginx-wow/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 15:11:17 +0000</pubDate>
		<dc:creator>xsc</dc:creator>
				<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=976</guid>
		<description><![CDATA[Nachdem ich ja diese Woche mit meinem Blog den Hoster gewechselt habe, stand ich vor einem kleinen Problem: der vServer, den ich mir angemietet habe, schien zeitweise extrem instabil, hing manchmal fest und tat gar nichts mehr.
Eine kleine Analyse brachte das Problem zutage: der installierte Apache 2 Server fraß die Resourcen auf, anscheinend beim Versuch, [...]]]></description>
			<content:encoded><![CDATA[<p>Nachdem ich ja diese Woche mit meinem Blog den Hoster gewechselt habe, stand ich vor einem kleinen Problem: der vServer, den ich mir angemietet habe, schien zeitweise extrem instabil, hing manchmal fest und tat gar nichts mehr.</p>
<p>Eine kleine Analyse brachte das Problem zutage: der installierte <strong>Apache 2</strong> Server fraß die Resourcen auf, anscheinend beim Versuch, sich mit der MySQL-Datenbank (die ich zwecks einfacher Weiterbetreibung dieses Blogs behalten habe) zu verbinden. Und egal, wo ich an der Konfiguration herumgeschraubt habe, es hat nichts gebracht.</p>
<p>Also bin ich einen anderen Weg gegangen: ein neuer Webserver musste her. Und hierbei fiel mein Auge auf <strong>nginx (Engine X)</strong>. (<a href="http://nginx.org/">Homepage</a>) Eine kurze <a href="http://www.howtoforge.com/installing-nginx-with-php5-and-mysql-support-on-debian-lenny">Installation</a> und eine unglaublich einfach zu erledigende Konfiguration später, lief er dann auch schon. Und siehe da: keine Abstürze, keine langen Wartezeiten. Einfach Wow!</p>
<p><del datetime="2010-02-04T08:52:46+00:00">Jetzt muss ich nur noch <a href="http://cakephp.org/">cakePHP</a> zum Laufen bekommen, dann wäre die Welt perfekt&#8230;</del> Läuft.</p>
<p><span id="more-976"></span>Oh, noch nebenbei die Konfiguration für diesen Wordpress-Blog, falls jemand auf der Suche nach den Rewrite-Rules sein sollte (nginx unterstützt keine .htaccess Dateien):</p>
<pre>server {
	listen 80;
	server_name dev.xscheme.de;

	location / {
		root [...];
		index index.php;
		if (!-e $request_filename) {
			rewrite ^ /index.php last;
		}
	}
	...
}
</pre>
<p>Wo genau ich das gefunden habe, weiß ich jetzt auch nicht mehr&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2010/02/nginx-wow/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Umzug vollbracht</title>
		<link>http://dev.xscheme.de/2010/01/umzug-vollbracht/</link>
		<comments>http://dev.xscheme.de/2010/01/umzug-vollbracht/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 01:07:21 +0000</pubDate>
		<dc:creator>xsc</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/2010/01/umzug-vollbracht/</guid>
		<description><![CDATA[So, seit eben liegt diese Seite bei meinem neuen Hoster, der synergetic AG. Hat jetzt dann doch eine Woche gedauert, weil ich vergessen hatte, ein Formular an die DeNIC zu schicken. Shame on me&#8230;
Aber jetzt sollte wieder alles funktionieren. Wenn nicht, bitte bescheid sagen!
Update: Um das Forum kümmere ich mich morgen.
]]></description>
			<content:encoded><![CDATA[<p>So, seit eben liegt diese Seite bei meinem neuen Hoster, der <a href="http://www.synserver.de/">synergetic AG</a>. Hat jetzt dann doch eine Woche gedauert, weil ich vergessen hatte, ein Formular an die DeNIC zu schicken. Shame on me&#8230;</p>
<p>Aber jetzt sollte wieder alles funktionieren. Wenn nicht, bitte bescheid sagen!</p>
<p><strong>Update</strong>: Um das Forum kümmere ich mich morgen.</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2010/01/umzug-vollbracht/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[Release] LeSharp 1.2.2</title>
		<link>http://dev.xscheme.de/2009/11/release-lesharp-1-2-2/</link>
		<comments>http://dev.xscheme.de/2009/11/release-lesharp-1-2-2/#comments</comments>
		<pubDate>Thu, 05 Nov 2009 19:51:58 +0000</pubDate>
		<dc:creator>WordPress</dc:creator>
				<category><![CDATA[LeSharp / Lea]]></category>
		<category><![CDATA[release]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/2009/11/971/</guid>
		<description><![CDATA[Heute habe ich (weil ich einfach vor Ewigkeiten vergessen habe, das zu machen) eine ausgebesserte Version von LeSharp online gestellt. Im Vorgänger hat Pico nicht mehr richtig funktioniert, aber die Tatsache, dass sich darüber niemand aufgeregt hat, nehme ich jetzt einfach mal positiv auf&#8230; Wenn weiter Probleme mit LeSharp bestehen, bitte melden!
Download:
https://sourceforge.net/projects/lastsharp/files/lesharp/LeSharp%201.2.2/LeSharp1.2.2.zip/download
]]></description>
			<content:encoded><![CDATA[<p>Heute habe ich (weil ich einfach vor Ewigkeiten vergessen habe, das zu machen) eine ausgebesserte Version von LeSharp online gestellt. Im Vorgänger hat Pico nicht mehr richtig funktioniert, aber die Tatsache, dass sich darüber niemand aufgeregt hat, nehme ich jetzt einfach mal positiv auf&#8230; Wenn weiter Probleme mit LeSharp bestehen, bitte melden!</p>
<p><strong>Download</strong>:<br />
<a href="https://sourceforge.net/projects/lastsharp/files/lesharp/LeSharp%201.2.2/LeSharp1.2.2.zip/download">https://sourceforge.net/projects/lastsharp/files/lesharp/LeSharp%201.2.2/LeSharp1.2.2.zip/download</a></p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2009/11/release-lesharp-1-2-2/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Aktuelle Situation: Stress.</title>
		<link>http://dev.xscheme.de/2009/10/aktuelle-situation-stress/</link>
		<comments>http://dev.xscheme.de/2009/10/aktuelle-situation-stress/#comments</comments>
		<pubDate>Thu, 01 Oct 2009 20:05:25 +0000</pubDate>
		<dc:creator>WordPress</dc:creator>
				<category><![CDATA[General]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=966</guid>
		<description><![CDATA[Ich möchte diesen Artikel nutzen, um kurz meine aktuelle Situation zu beschreiben und mich im Zuge dessen dafür zu entschuldigen, dass ich diese Seite und meine Projekte im Moment eher ruhen lasse.
Zum einen bin ich letzten Samstag umgezogen (der klassische Studentenweg: von Zuhause weg und in eine 2er-WG) und da jetzt dann doch ziemlich eingebunden. [...]]]></description>
			<content:encoded><![CDATA[<p>Ich möchte diesen Artikel nutzen, um kurz meine aktuelle Situation zu beschreiben und mich im Zuge dessen dafür zu entschuldigen, dass ich diese Seite und meine Projekte im Moment eher ruhen lasse.</p>
<p>Zum einen bin ich letzten Samstag umgezogen (der klassische Studentenweg: von Zuhause weg und in eine 2er-WG) und da jetzt dann doch ziemlich eingebunden. Ich hab noch nichtmal ein Bett&#8230; (Lieferzeit: 3 Wochen)</p>
<p>Seit September arbeite ich zudem als Werkstudent bei <a href="http://o2online.de/">Telefonica O<sub>2</sub> Germany</a>. Die 20h-Woche ist jetzt vielleicht nicht sooo auslastend, aber es summiert sich dann doch.</p>
<p>Zuguterletzt geht dann demnächst auch die Uni wieder los, was mein Pensum dann auf 50h die Woche erhöht. Aber mei, wir sind jung &#8211; wenn wir jetzt sowas nicht packen, wann dann?</p>
<p>Jedenfalls werde ich alle offenen Kommentare beantworten, sobald ich Zeit habe. Ebenso wird es dann neue Versionen der einzelnen Programme geben. Danke für&#8217;s Verständnis!</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2009/10/aktuelle-situation-stress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Scripe. Oder: Warum eine Scriptsprache auch nur eine Suppe ist.</title>
		<link>http://dev.xscheme.de/2009/09/scripe-eigene-scriptsprache-ganz-einfach/</link>
		<comments>http://dev.xscheme.de/2009/09/scripe-eigene-scriptsprache-ganz-einfach/#comments</comments>
		<pubDate>Wed, 02 Sep 2009 20:40:33 +0000</pubDate>
		<dc:creator>WordPress</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Projekte]]></category>
		<category><![CDATA[Software]]></category>

		<guid isPermaLink="false">http://dev.xscheme.de/?p=962</guid>
		<description><![CDATA[Es ist wohl aufgefallen, ich erwähne es trotzdem: Seit einiger Zeit arbeite ich an einem Prinzip, dass es jedem Interessierten ermöglichen soll, eine eigene Script- oder Programmiersprache zu entwerfen. Meine theoretischen Überlegungen, so langweilig sie auch manches Mal seien mögen, habe ich in einer Reihe von Artikeln festgehalten; damit ich diese Texte aber auch schreiben [...]]]></description>
			<content:encoded><![CDATA[<p>Es ist wohl aufgefallen, ich erwähne es trotzdem: Seit <a href="http://dev.xscheme.de/2009/07/eigene-programmiersprache-scriptsprach/">einiger Zeit</a> arbeite ich an einem Prinzip, dass es jedem Interessierten ermöglichen soll, eine eigene Script- oder Programmiersprache zu entwerfen. Meine theoretischen Überlegungen, so langweilig sie auch manches Mal seien mögen, habe ich in einer <a href="http://dev.xscheme.de/2009/08/wie-entwickle-ich-meine-eigene-scriptsprache-teil-1/">Reihe</a> <a href="http://dev.xscheme.de/2009/08/wie-entwickle-ich-meine-eigene-scriptsprache-teil-2/">von</a> <a href="http://dev.xscheme.de/2009/08/wie-entwickle-ich-meine-eigene-scriptsprache-teil-3/">Artikeln</a> festgehalten; damit ich diese Texte aber auch schreiben konnte, musste ich immer ein kleines Stückchen vorausdenken und einiges an implementierungstechnischer Vorarbeit leisten.</p>
<p>Und heute war ich dann soweit, dass ich eine gar nicht so üble Version vor mir hatte, die ich nun (nicht detailliert, eher angeberischerweise <img src='http://dev.xscheme.de/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  ) präsentieren will. Vorhang auf für <strong>Scripe</strong>!</p>
<p><span id="more-962"></span></p>
<p>(Der Name hat mehrere Hintergründe: zum einen wäre da der Schreibfehler, der schonmal beim Wort &#8220;Scripte&#8221; auftaucht, zum anderen findet sich ein Ursprung im englischen &#8220;to scribe&#8221;, was soviel wie &#8220;vorzeichnen&#8221; bedeutet. Zuguterletzt sagt einem das allwissende <a href="http://www.urbandictionary.com/define.php?term=scripe">Urban Dictionary</a>, das &#8220;scripe&#8221; das Äquivalent von &#8220;a load of rubbish&#8221;, also etwas nicht ganz hochwertigem ist. Das ist auch in Ordnung so: Scripe ist der Weg, den ich einschlagen würde, wenn ich eine Scriptsprache zu entwickeln hätte. Zwar sind Grundkonzepte, die sich auch im professionelleren Einsatz finden, vorhanden, aber Scripe erhebt in dieser Hinsicht keinerlei Anspruch auf Vollständigkeit oder übermäßige Effizienz. &#8220;Quick and Dirty&#8221; wäre dennoch übertrieben, dann doch eher &#8220;<strong>Quick and Not-So-Clean</strong>&#8220;&#8230;)</p>
<p>Die Suppe im Titel lässt das Prinzip erahnen: Suppen brauchen Gewürze, um zu schmecken, und hierbei ist es wichtig auf die Mischung zu achten. Ebenso wird jeder seine Suppe anders würzen, je nach Vorlieben oder Vorhaben. Eine Scriptsprache ist da nicht anders: hier eine Prise Variablenverwaltung, dort ein Löffel Arithmetik. Voilà.</p>
<p>Dieses Suppenprinzip findet man heutzutage überall, hauptsächlich in der Unix/Linux-Welt, wo man je nach Bedarf auf einfachste Art und Weise ein Paket nachladen kann und das Gesamtsystem somit bis ins letzte Eck modifizierbar bleibt. <strong>Auch Scripe verwendet solche Pakete, allerdings eben für die Features der Programmiersprache!</strong></p>
<p>Folgender C#-Code erzeugt einen Prozessor, der den <a href="http://en.wikipedia.org/wiki/Shunting_yard_algorithm">Shunting-Yard-Algorithmus</a> verwendet, um die Eingabe zu parsen. Anschließend erhält er vier Pakete: eines für arithmetische Operationen, eines für String-Operationen, eines für Ein- und Ausgabe, und eines für Variablendefinition und -verwaltung. Anschließend wird eine Eingabe-Auswertungs-Schleife gestartet.</p>
<pre>// Create processor
Processor p = new Processor(
    new ShuntingYardAlgorithm()
);

// Add packages
p.AddPackage(new Scripe.Evaluators.Arithmetic.ArithmeticPackage(true));
p.AddPackage(new Scripe.Evaluators.Strings.StringPackage("&amp;", "$"));
p.AddPackage(new Lapicon.Evaluators.InputOutput.InputOutputPackage());
p.AddPackage(new Lapicon.Evaluators.Variables.VariablePackage());

// Empty codebase
Codebase c = new Codebase(new Scripe.Env.Environment());

// Read-Eval-Print-Loop
string r = "";
while (true)
{
    try
    {
        Console.Write("Calc: ");
        if ((r = Console.ReadLine()) == "exit") break;
        c.Add(r);
        Console.WriteLine(" ==&gt; " + c.Execute(p).ReturnValue);
    }
    catch (Exception ex)
    {
        Console.WriteLine(" ERROR: " + ex.Message);
    }
}</pre>
<p>In nur 5 Zeilen haben wir hier (mithilfe der Scripe-internen und zweier für Lapicon geschriebenen Pakete) einen Prozessor geschaffen, der jede der folgenden Eingaben auswerten kann:</p>
<pre>1+(4-6)*(3-4^5)+e
def variable = 7*8
def variableDurchZwei = &lt;variable&gt;/2
echo "(7*8)/2 = " &amp; $(&lt;variableDurchZwei&gt;)</pre>
<p>Und nun stelle man sich eine Internetseite vor, die eine gewisse Anzahl solcher Pakete anbietet. <strong>Scriptsprachen entwickeln einfach gemacht</strong>.</p>
<p>Soviel also von mir. Wann Scripe letztlich ganz fertig ist (und ich mich wieder den anderen Projekten wie LastSharp widmen kann), kann ich nur schätzen. Ist ein Monat in Ordnung? <img src='http://dev.xscheme.de/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://dev.xscheme.de/2009/09/scripe-eigene-scriptsprache-ganz-einfach/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.332 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2010-09-03 16:46:41 -->
