Institut für Informationssysteme Dr. Robert Marti Claude Barthels David Sidler Informationssysteme für Ingenieure Herbstsemester 2016 Musterlösung 8 Lösung 8.1 1. XML Anwendungsbeispiel • Binär Z.B. Object Streams. Das Format ist kompakt, aber nicht für Menschen lesbar. Es bestehen zudem Inkompatibilitäten zwischen Formaten, z.B. Word Dokumente vs. Open Office Dokumente, oder serialisierte Java Objekte vs. serialisierte C++ Objekte. • Plain Text Einfache Handhabung und für Menschen lesbar. Wenn das Format sich ändert (zusätzliche Information hinzufügen) muss der Parser umgeschrieben werden. • XML Diese Variante erhöht die Kompatibilität mit anderen Systemen (andere Implementierung des eigenen Systems, neue Version des eigenen Systems, Traffic-Analysers etc). Erweiterung der Nachricht kein Problem (ältere Versionen lesen nur die Elemente, die sie kennen und ignorieren neue Elemente). Ausserdem gibt es für XML Libraries, die das Parsen und Kreieren von XML Dokumenten und deren Korrektheit (well-formedness) übernehmen. Nachteil: Grössere Nachrichten. Dieser Nachteil kann aber mit Komprimierung (z.B. ZIP) kompensiert werden. 2. Wenn ein Peer nach einer Datei sucht, so verfasst es ein request Dokument. In dieses schreibt es seine eigene id als Quelle und den Namen der gesuchten Datei. Falls nach einer ganz bestimmten Datei gesucht wird (die man schon kennt), könnte man auch (zusätzlich) einen Hashwert für die Datei einfügen. Dieses Anfragedokument schickt das Peer nun an seine Nachbarn. Hat ein Nachbar die gesuchte Datei nicht, so trägt er seine id im path Element des Dokumentes ein und schickt die Nachricht an seine Nachbarn weiter, falls deren id nicht schon im path steht. Wichtig ist, dass der Inhalt des path Elementes geordnet ist, also neue Einträge zum Beispiel immer unten angefügt werden, damit der Pfad später zurückverfolgt werden kann. <request> <source> <peer id="12" /> </source> <file> <name>Arcade Fire</name> ... </file> <path> <peer id="18" /> <peer id="81" /> <peer id="9" /> ... </path> </request> Besitzt ein Peer eine Datei, die einem eingehenden request entspricht, so kann es eine response Nachricht verfassen. Dafür kopiert es den Inhalt des source Elements in das destination Element und fügt sich selber als source ein. Die Information über die Datei bleibt gleich, hinzu kommt ein data Element, das die gesuchte Datei im Binärformat enthält. Der path Teil der Anfrage wird ebenfalls in die Antwort kopiert. Auf dem Rückweg der Antwort durch das P2P Netz kann jedes Peer nach dem Erhalt der Nachricht seine id als unterstes Element aus der Liste im path entfernen. Wir verwenden also für die Abwicklung von Frage/Antwort das path Element als Stack. <response> <source> <peer id="27" /> </source> <destination> <peer id="12" /> </destination> <file> <name>Arcade Fire</name> ... </file> <data>...01101000100101...</data> <path> <peer id="18" /> <peer id="81" /> <peer id="9" /> ... </path> </response> 3. <!DOCTYPE request [ <!ELEMENT request (source, file, path)> <!ELEMENT source (peer)> <!ELEMENT file (name, ...)> <!ELEMENT path (peer*)> <!ELEMENT peer EMPTY> <!ELEMENT name (CDATA)> <!ATTLIST peer id CDATA #REQUIRED> ]> <!DOCTYPE response [ <!ELEMENT response (source, destination, file, data, path)> <!ELEMENT source (peer)> <!ELEMENT destination (peer)> <!ELEMENT file (name, ...)> <!ELEMENT data (CDATA)> <!ELEMENT path (peer*)> <!ELEMENT peer EMPTY> <!ELEMENT name (CDATA)> <!ATTLIST peer id CDATA #REQUIRED> ]> 2 Lösung 8.2 XQuery 1. <countries> { for $c in /mondial/country return <country> <name>{string($c/name)}</name> <area>{string($c/@area)}</area> <population>{string($c/population)}</population> </country> } </countries> 2. <result> { for $c in //country, $o in //organization where $c/@capital = $o/@headq return <answer> <country>{string($c/name)}</country> <organization>{string($o/name)}</organization> </answer> } </result> 3. <result> { for $c in //country, $p in $c/province return <answer> <country>{string($c/name)}</country> <province>{string($p/name)}</province> </answer> } </result> 4. <result> { for $c in //country return <answer> <country>{string($c/name)}</country> { for $p in $c/province return <province>{string($p/name)}</province> } </answer> } </result> 3 Diese Anfrage liefert auch answer Elemente, wenn für ein Land keine Provinzen gespeichert sind. Wenn wir diese Länder ohne Provinzen herausfiltern wollen, so können wir das mit einem Zusatz von where $c/province vor dem return Statement erreichen. 5. <result> { for $c in //country return <country name="{$c/name}"> { for $city in $c//city return <city>{string($city/name)}</city> } </country> } </result> 6. <result> There are {for $m in /mondial return count($m//country)} countries in the database. { for $m in /mondial return sum( for $c in $m//country where $c//city/population > 1000000 return 1 ) } of them have a city with more than 1Mio inhabitants. <countries> { for $c in //country where $c//city/population > 1000000 return <country>{$c/name}</country> } </countries> </result> Bei dieser Anfrage wird die Auswertung der Städte mit mehr als 1Mio. Einwohnenr zweimal gemacht. Um dies zu vermeiden kann man mittels let ein Zwischenresultat definieren, ähnlich einer View in SQL. let $countrycount := for $m in /mondial return count($m//country) let $matches := for $c in //country where $c//city/population > 1000000 return <country>{$c/name}</country> 4 return <result> <totalcountries count="{$countrycount}" /> <matchingcountries count="{count($matches)}" /> <countries>{$matches}</countries> </result> 5