Der einfachste REST-Webservice mit XQuery und exist-db (Erste Schritte mit XRX – 2 von X)
In einem früheren Beitrag hatte ich mich schon begeistert über die einfachen und eleganten REST-Services, die mit XRX möglich sind, geäußert. Hier nun der Beweis, der einfachste REST-Webservice wo gibt:
declare namespace request="http://exist-db.org/xquery/request"; <result> {concat('Hallo ', request:get-parameter('name', 'Welt'), '!')} </result>
Dieser Code kann einfach in einer XQuery-Datei innerhalb von exist-db gespeichert werden, in einer betterFORM-Installation etwa unterhalb des Hauptordners betterform, so dass sie sofort im betterFORM-Dashboard erscheint. Der Service kann dann z.B. mit http://localhost:8080/betterform/rest/db/betterform/service.xquery?name=Max aufgerufen werden, zurückgegeben wird das allseits beliebte »Hallo Max!«. Zugegeben: Das Beispiel macht nicht viel, aber an der Stelle des XPath-Ausdrucks kann natürlich jeder beliebig mächtige andere Ausdruck stehen.
Für die Parameterverarbeitung wird eine proprietäre Erweiterung von exist-db benutzt; in der Praxis empfiehlt sich deshalb, diese Funktion gegen eine selbst definierte in einer ausgelagerten Modul-Bibliothek zu ersetzen, um bei einem Plattformwechsel schnell die notwendigen Anpassungen vornehmen zu können.
XML Schema: complexType mit simpleContent
Verfasst von Stf unter Grundlagen, XML Schema, XML-Validierung am 4. Dezember 2011
Gelegentlich steht man vor dem Problem, in XML Schema ein Element mit einem oder mehreren Attributen und einem in irgendeiner Form beschränkten simpleContent (Text, Zahlen, URIs; aber keine Elemente) zu definieren. Die Syntax von XML Schema dazu ist wenig intuitiv:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="MyElement"> <xs:complexType> <xs:simpleContent> <xs:extension base="MySimpleElementType"> <xs:attribute name="MyAttribute" type="MySimpleAttributeType"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> <xs:simpleType name="MySimpleElementType"> <xs:restriction base="xs:string"> <xs:enumeration value="Value_A"/> <xs:enumeration value="Value_B"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="MySimpleAttributeType"> <xs:restriction base="xs:string"> <xs:enumeration value="AttributeContent_A"/> <xs:enumeration value="AttributeContent_B"/> </xs:restriction> </xs:simpleType> </xs:schema>
Es handelt sich um einen complexType (wegen des Attributes) mit simpleContent (hier xs:string mit aufgezählten gültigen Werten). Wenig intuitiv ist, dass ein simpleType mit einem Attribut erweitert wird und so faktisch ein complexContent wird, aber trotzdem innerhalb von simpleContent steht. Der Schlüssel ist sicher die Unterscheidung von Type und Content, denn der Inhalt des Elements ist ja immer noch einfach.
Das Schema und ein Instanzdokument habe ich in der Beispielsammlung abgelegt.
Erste Schritte mit XRX (1 von X)
XRX ist eine Technik für die Entwicklung und den Betrieb von Webanwendungen. Das Akronym steht nach einem sehr allgemeinen Verständnis für XML für die Datenspeicherung im Client, REST-Schnittstellen und XML auf dem Server. Im engeren Sinne wird XRX meist für XForms, REST, XQuery verwendet, wobei XQuery in der Regel auf eine XML-Datenbank zugreift.
Als XML-affiner Zeitgenosse war ich natürlich neugierig auf diese Technik. Meine Erfahrungen bei den ersten Schritten möchte ich hier notieren – schließlich ist aller Anfang schwer, aber nicht notwendigerweise für alle.
Ein erstes Resümee vorab
XRX ist recht komplex, und die Entwicklung wird (nach meinem jetzigen Kenntnisstand) nicht mit dem gewohnten Komfort unterstützt. Zuverlässige, d.h. kontext-sensitive Content Completition habe ich bisher noch nicht gefunden, und beim Debugging fühle ich mich schlecht unterstützt: mir fehlen Informationen zu den internen Abläufen (und Fehlern) des XForms-Prozessors. Und gleich noch eine Warnung: ohne einigermaßen belastbare Kenntnisse von XPath, Namespaces und ein bisschen Erfahrung mit XML Schema, XQuery und/oder XSLT wird der Einstieg eher schwer.
Auf der anderen Seite wird man von XRX mit eleganter, effizienter und plattformunabhängiger Anwendungsentwicklung belohnt (obwohl ich nicht über genug Erfahrung mit anderen Plattformen verfüge, um solche Einschätzungen zu treffen, wage ich mal dieses Statement). Ein REST-Webservice in drei Zeilen XQuery löst bei mir ebenso Begeisterung aus wie die »magische« (d.h. codefreie) Aktualisierung von Formularfeldern durch XForms oder der unmittelbare Zugriff auf die soeben altualisierten XML-Daten via REST. Da bin ich doch recht zuversichtlich, XRX demnächst auch produktiv einsetzen zu können.
Installation
Es gibt verschiedene vorkonfigurierte Bundles aus XForms-Prozessor und XML-Datenbank; ich habe mich aus Bequemlichkeit (die Entwickler arbeiten in Berlin, und ich kenne sie persönlich) für die betterFORM XML Suite mit eXist-db als XML-Datenbank entschieden. Für Windows gibt es eine Installer-Exe, für den Mac ein JAR. Unter Windows bemäkelte der Installer das 7er SDK, aber nach einem Neustart lief die Installation einfach durch. betterFORM hat auf seiner Seite eine detaillierte Anleitung.
Nach der Installation kann man sich im betterFORM Dashboard einen ersten Eindruck von XForms-Anwendungen verschaffen.
Tipp: Der »eXist Admin Client« (erreichbar über Download und Start von exist.jnlp rechts oben im betterFORM Dashboard) erlaubt einen ersten Einblick in die Datenbank. Besonders zum Anlegen und Löschen von Collections und Dateien leistet er gute Dienste.
OxygenXML
Zum Entwickeln braucht es natürlich eine IDE. OxygenXML bietet eine gute Integration von eXist-db, die Einrichtung ist in der F1-Hilfe und auf der OxygenXML-Seite zu eXist-db detailliert beschrieben. Ich habe dann ewig gebraucht, um die URL der REST-Schnittstelle zu finden und bin später über die Lösung gestolpert: beim Start des »eXist Admin Client« ist die korrekte URL voreingestellt und kann einfach nach OxygenXML kopiert werden. Mit den Standardparametern ist die URL xmldb:exist://localhost:8080/betterform/xmlrpc.
Tipp: Die Arbeit mit Dateien und an der Datenbank geht mit OxygenXML sehr leicht von der Hand. Man kann Dateien öffnen, bearbeiten und zurück in die Datenbank speichern, außerdem sind Dateioperationen wie Löschen, Umbenennen oder Importieren möglich. Unbedingt ausprobieren!
Zweite Hürde ist die Unterstützung durch Content Completition und Validierung. Während XQuery direkt unterstützt wird, ist für XForms etwas Handarbeit notwendig. Der einfachste Weg ist, die Processing Instruction <?xml-model href="http://www.oxygenxml.com/1999/xhtml/xhtml-xforms.nvdl" schematypens="http://purl.oclc.org/dsdl/nvdl/ns/structure/1.0"?> am Anfang eines XHTML-Dokumentes einzufügen. Außerdem können neue Dokumente über Datei/Neu mit dem Dokumenentyp (unter Framework templates/XHTML) »XHTML 1.0 RNG Based + XForms 1.1« angelegt werden. Die XForms-Unterstützung ist nicht perfekt, aber sehr praktisch.
»Hello World« und Tutorials
Das Hello-World-Beispiel aus dem XForms-Wikibook lief bei mir auf Anhieb. Die nächsten Schritte – Zugriff auf eXist-db, Anzeigen, Erstellen, Löschen, Laden und Speichern von Datensätzen – habe ich mir recht zügig mit dem guten »Orbeon Forms XForms Tutorial« erarbeitet. Danach helfen der XForms-Standard beim W3C, der »XForms Feature Explorer« (erreichbar über das betterFORM Dashboard) sowie die Online-Dokumentation von eXist-db weiter. Schließlich habe ich mir manche Einsicht und Anregung aus »A Beginners Guide XRX« von Dan McCreary und Joe Wicentowski geholt.
Im Rückblick war der Einstieg dann gar nicht so schwer. Größte und unerwartete Hürde für mich war das Erforschen und Verstehen des Model-View-Controller-Konzepts von XForms und der darauf aufbauenden Sprachkonstrukte. Und auch ein paar Pattern wollten erarbeitet sein. Dazu vielleicht später mehr.
XSLT-SB: asin(), acos(), atan(), atan2(), dynamische Typung
Verfasst von Stf unter Allgemeines, XSLT-SB am 27. Juni 2011
Mit dem Sprung auf Version 0.2.37 kann die XSLT-SB, genauer math.xsl, jetzt auch die Arkusfunktionen und dynamische Typung. In Ergänzung der knappen Release-Notes hier ein paar Anmerkungen dazu.
Arkusfunktionen
Die Gruppe der Arkusfunktion lässt sich einfach auf der Grundlage von atan() implementieren – wenn man den richtigen Ansatz gefunden hat. Meine ersten Versuche, asin() und atan() über Taylor-Reihen zu implementierten scheiterten daran, dass diese Reihen zu langsam konvergieren. Zusammen mit den in der Reihenbildung verwendeten rekursiven Funktionen (Fakultät und Potenz) war schnell das Limit der Rekursionstiefe erreicht: Saxon bricht die Verarbeitung mit Hinweis auf das Überschreiten der maximalen Rekursionstiefe ab.
Die Lösung brachte ein alternativer Algorithmus zur Berechnung von atan(), den ich bei WolframMathWorld fand (Gleichungen Nr. 44 bis 48). Mittels des Arkustangens lässt sich einfach der Arkussinus und Arkuskosinus berechnen, so dass diese Implementierung ein Kinderspiel war (siehe Wikipedia).
dynamische Typung
Zweites großes Thema der Überarbeitung von math.xsl war die dynamische Typung. Die mathematischen Operatoren und Funktionen in XPath geben ihr Ergebnis i.d.R. mit dem Typ der Argumente zurück. Zum Beispiel ist das Ergebnis von fn:round-half-to-even() mit einem Argument vom Typ xs:decimal vom Typ xs:decimal, während mit einem xs:double-Argument das Ergebnis vom Typ xs:double ist.
Die Implementierung dieses Verhaltens barg einige Schwierigkeiten, weil manche Funktionen als Ergebnis NaN, -INF oder INF zurückgeben können. Diese speziellen Werte sind zwar mit den Typen xs:float und xs:double darstellbar, nicht aber mit xs:decimal (das aber genauere Ergebnisse als xs:double liefert) und xs:integer. Das gewünschte Verhalten ist wohl sehr vom Einsatzzweck der Funktionen abhängig. Der jetzige Kompromiss ist daher, dass bei diesen Werten der Cast von NaN, -INF oder INF auf ungeeignete Typen scheitert; wer Wert auf hohe Genauigkeit legt, kann vielleicht auch die kritischen Werte umschiffen.
Genauigkeit
Laut Standard müssen XPath-Implementierungen mit 18 signifikanten Stellen rechnen. Für die XSLT-SB habe ich mittels intern:round() die Genauigkeit auf 16 Stellen begrenzt, weil damit die meisten Tests erfolgreich absolviert werden. Trotzdem wird für manche Testwerte (etwa exp(100)) nicht das richtige Ergebnis ermittelt (bei vielen Berechnungsschritten summieren sich die Fehler halt). In diesen Fällen wird im Testprotokoll (hier z.B. für Saxon EE) eine Warnung (orange hinterlegt) ausgegeben. Diese sind zu unterscheiden von den gelb hinterlegten Fällen, bei denen ein Cast der Ergebnisse auf xs:decimal (den Typ der Tests) nicht möglich ist, siehe oben. In den Tests nicht berücksichtigt sind die Fälle, für die eine Funktion nicht definiert ist, etwa asin(3).
Intern (d.h. bei den Funktionen mit intern:-Prefix) wird mit einer höhren Stellenzahl gerechnet, diese müssen aber weder signifikant noch richtig sein.
AltovaXML in OxygenXML einbinden
Verfasst von Stf unter Allgemeines, Grundlagen am 30. Mai 2011
Um AltovaXML in OxygenXML nutzen zu können, muss man diesen XSLT-Prozessor als »Custom Engine« einrichten. So geht’s:
Unter Einstellungen/XML/XSLT-FO-XQuery/Custom Engines einen neuen Prozessor anlegen:
Als Prozessortyp ist »XSLT« vorausgewählt und richtig. Name und Beschreibung eingeben und dann in das Feld Kommandozeile »"C:\Program Files (x86)\Altova\AltovaXML2011\AltovaXML.exe" /xslt2 ${xsl} /in ${xml} /out ${out}« eintragen (Pfad zu AltovaXML bitte an lokale Gegebenheiten anpassen).
Speichern, fertig. In den Transformationsszenarien kann jetzt der neu angelegte Prozessor ausgewählt werden:
Leider kann OxygenXML keine Parameter oder initiale Modes bzw. initiale Templates an den so erzeugten Prozessor übergeben. Ein Workaround ist, für definierte Fälle eigene Prozessoren anzulegen. Für den ad-hoc-Selbsttest der XSL-SB sieht das so aus:
Der erste Teil der Kommandozeile »"C:\Program Files (x86)\Altova\AltovaXML2011\AltovaXML.exe" /xslt2 ${xsl} /in ${xml} /out ${out} /m internals.self-test -param internals.logging-level="'DEBUG'" -param internals.errors.die-on-critical-errors="'no'"« ist identisch zu oben, initialer Mode und Parameter werden zusätzlich hart codiert übergeben. Hier sollten die Entwickler von OxygenXML gelegentlich einmal nachbessern, es kann ja nicht so schwer sein, einen benannten Parameter als benanntes Makro anzubieten.
XSLT-SB – eine Standard-Bibliothek für XSLT
Verfasst von Stf unter Beispiele, XSLT und XPath, XSLT-SB am 14. Mai 2011
Es ist vollbracht. Nach ein paar Wochenenden mit Feinschliff und letzten Test habe ich Version 0.2 von XSLT-SB – einer Standard-Bibliothek für XSLT – veröffentlicht.
Was ist XSLT-SB?
Die XSLT-Standard-Bibliothek (XSLT-SB) beinhaltet nützliche, immer wieder gebrauchte Funktionen und Templates. Gleichzeitig dient sie als beispielhafte Implementierung bestimmter Techniken. Sie wendet sich als Beispielsammlung vor allem an deutschsprachige Entwickler, um für diese die Einstiegshürden zu senken.
Die XSLT-SB hat zwei Quellen: einerseits habe ich zeitig angefangen, immer wieder gebrauchte Funktionen und Templates in produktive Bibliothek-Stylesheets auszulagern. Für die XSLT-SB habe ich einige davon übernommen. Beispiele dafür sind xsb:force-cast-to-integer() und xsb:parse-string-to-boolean() sowie die Grundlagen des Logging-Systems. Andererseits habe ich aus Spaß (oder so) mal die eine oder andere Funktion implementiert, bspw. ist files.xsl wesentlich umfangreicher ausgefallen, als es für die eigentliche Aufgabe notwendig gewesen wäre.
Templates und Funktionen der XSLT-SB entstanden also nicht systematisch, sondern nach Bedarf oder Interesse. Im besonderen habe ich nicht versucht, bestehende Bibliotheken wie EXSLT zu ersetzen. Deshalb kann die XSLT-SB mit Fug und Recht als lückenhaft bezeichnet werden.
Ich habe die XSLT-SB in einigen kleineren Projekten produktiv eingesetzt, aber der dauernde Härtetest steht noch aus. Außerdem sind die Stylesheets durch Dokumentation und Tests recht umfangreich; und ich habe sie auch nicht auf eine hohe Ausführungsgeschwindigkeit optimiert. Deshalb möchte ich heute von einem produktiven Einsatz abraten, aber selbstverständlich können einzelne Templates oder Funktionen gezielt in eigene Projekte übernommen werden. Die Veröffentlichung der Stylesheets macht einen breiteren Einsatz möglich, und ich freue mich auf das Feedback. Abhängig davon mag sie sich in die eine oder andere Richtung entwickeln – mehr Beispielsammlung oder mehr produktive Bibliothek.
Drei Besonderheiten der XSLT-SB möchte ich hervorheben: files.xsl, das Logging-System und die Testumgebung.
files.xsl
files.xsl bündelt Funktionen rund um URLs. Da xs:anyURI kaum geprüft wird, habe ich die Regeln von RFC 1808 (URL) in diverse String-Tests gegossen und darauf aufbauend Funktionen zum Ermitteln von Dateiname, Dateipfad, Dateierweiterung usw. entwickelt. Ergänzt wird das Stylesheet durch Funktionen wie xsb:file-exists() und xsb:mediatype-from-url().
Das Stylesheet demonstriert einige spezielle XML- und XSLT-Techniken, etwa benannte Entities für lesbare reguläre Ausdrücke, von Systemeigenschaften abhängige Funktionen (mit use-when) und die Verwendung von Java-Funktionen.
Logging-System
Die XSLT-SB implementiert ein konfigurierbares Logging-System, um Nachrichten des Stylesheets während der Verarbeitung einfach und flexibel auszugeben. Meldungen können per xsl:message oder (soweit der Rückgabetyp einer Funktion oder eines Templates das zulässt) als Kommentar, XML-Element oder HTML ausgegeben werden, unterschiedliche Dringlichkeitsstufen werden unterstützt. Die XSLT-SB nutzt das Logging-System intensiv für die Selbsttests der Funktionen, für den Einstieg lohnt ein Blick auf xsb:internals.Error bzw. xsb:internals.FunctionError in internals.xsl.
Testumgebung
Für Funktionstest habe ich eine Testumgebung entwickelt (siehe internals.testing.xsl). Tests werden in Templates zusammengefasst, die im Stylesheet selbst oder in externen Teststylesheets abgelegt werden können und per initialem Mode oder initialem Template aufgerufen werden. Einige Funktionen und Templates helfen beim Vergleich von erwarteten und berechneten Werten und kümmern sich um die Protokollierung. Interessanterweise haben mir die Test nicht nur beim nachträglichen Absichern der Stylesheets geholfen, sondern ich bin relativ schnell auf eine testgetriebene Entwicklung umgestiegen. Diesen Aspekt möchte ich in meiner täglichen Arbeit nicht mehr missen.
Die Testumgebung wird durch formale Tests der Stylesheets selbst ergänzt (internals.stylecheck.xsl, Template intern:internals.Stylecheck). Sie warnen bei fehlender Typung von Variablen, Parametern und Funktionen, fehlender Dokumentation u.a. und listen ToDos.
Ein Beispiel für absolvierte Tests und den Stylecheck, ausgegeben über das Logging-System als HTML, sind die Testergebnisse für files.xml unter Saxon-HE.
Wie kann die XSLT-SB benutzt werden?
Wie ich oben schrieb, kann ich die XSLT-SB im Moment nicht für den produktiven Einsatz empfehlen. Wer es trotzdem wagen möchte, kann sich die Stylesheets herunterladen und in eigene Projekte einbinden. Ein neues Projekt kann einfach auf der Grundlage von pattern+includes.xsl begonnen werden. Natürlich kann man die Stylesheets auch zum Nachschauen oder für Kopieren & Einfügen verwenden.
Die Verwendung der meisten Funktionen sollte selbsterklärend sein, für die Logging- und Testumgebung können die XSLT-SB-Stylesheets als Beispiel herangezogen werden. Die Stylesheets sind dokumentiert; eine HTML-Version der Dokumentation liegt im doc-Verzeichnis der Distribution und – meist aktueller – online.
Lizenz
Die Stylesheets und das Drumherum sind dual lizenziert: EXPAT (MIT) für den Einsatz als Software und CC-by 3.0, so dass einer Verwendung keine rechtlichen Hürden im Weg stehen sollten.
Was kommt als nächstes?
Das hängt vom Feedback ab – oder von überraschenden neuen Projekten. Auszug aus meiner ToDo-List:
auf Intel SOAE zum laufen bringen, im Moment stürzt dieser Prozessor einfach ab[Nachtrag: Ich habe das Problem eingegrenzt und im Intel-Forum dargestellt. In neueren Versionen des Prozessors tritt es wohl nicht mehr auf, allerdings plant Intel keine Veröffentlichung einer neuen Version, siehe hier. Damit sind mir hier wohl die Hände gebunden …]- Dokumentation verbessern, z.B. Liste der Funktionen mit Kurzbeschreibung erstellen. [Nachtrag: Im Projektwiki gibt es jetzt aus den Stylesheets heraus generierte Übersichten.]
- zusätzliche Funktionen implementieren, bspw. habe ich gerade wieder mal das
p:directory-listaus XProc vermisst - Kompakt-Distribution ohne geschwätzige Kommentare und Dokumentation erzeugen, um die Startgeschwindigkeit zu erhöhen
Links
Ich habe das Projekt bei Google-Code eingestellt, dort gibt es sowohl ein SVN-Repository als auch fertige Distributionen, die gelegentlich dem aktuellen Entwicklungsstand hinterherhinken können. Auf den Expedimentum-Seiten gibt es ein aktuelles Checkout aus dem Trunk, hier kann man auch online die Dokumentation einsehen. Kommentare und Fehlermeldungen sollten über die Google-Seiten laufen.
- Download: http://code.google.com/p/xslt-sb/downloads/list
- Projektseite bei Google Code: http://code.google.com/p/xslt-sb/
- aktuelles Checkout: http://www.expedimentum.org/example/xslt/xslt-sb/
Apache Ant: Initialen Mode und Initiales Template für XSLT 2.0 mit Saxon setzen
Verfasst von Stf unter Apache Ant, XSLT und XPath am 2. April 2011
Ein schönes Feature von XSLT 2.0 ist, dass man ein Stylesheet in einem initialen Mode oder mit einem initialen Template starten kann (siehe Standard). Ich benutze diese Möglichkeit gern, um Selbsttests direkt im Stylesheet unterzubringen und über einen initialen Mode auszuführen – ohne die eigentliche Logik des Stylesheets zu beeinflussen.
In OxygenXML kann man den initialen Mode oder das initiale Template prima im Transformationsszenario einstellen, der kleine Button mit dem rasenden Zahnrädchen neben der Auswahlliste für die Transformations-Engine öffnet den passenden Einstellungs-Dialog (siehe Dokumentation).
Schon vor geraumer Zeit wollte ich diese Feature auch mit Apache Ant nutzen, bin aber wegen fehlender Unterstützung durch Saxon und einen zwischenzeitlichen Ant-Bug in Version 1.8.1 nicht weitergekommen. Inzwischen wurden Saxon und Ant aktualisiert, so dass es Zeit für einen neuen Anlauf war. Die größte Herausforderung war, die jeweils passende URI für die beiden Features zu finden, letztendlich habe ich in die Saxon-Quelltexte geschaut. So geht’s:
<target name="test"> <xslt in="input.xml" out="output.xml" style="stylesheet.xsl"> <!-- Pfad zu Saxon an lokale Installation anpassen! --> <classpath location="saxon9he.jar" /> <factory name="net.sf.saxon.TransformerFactoryImpl"> <!-- hier ggfs. "http://saxon.sf.net/feature/initialTemplate" einsetzen --> <attribute name="http://saxon.sf.net/feature/initialMode" value="MyMode"/> </factory> </xslt> </target>
Über die Factory-Attribute können auch viele weitere Saxon-Optionen – die oft auch über die Kommandozeile zu erreichen sind – von Ant aus gesteuert werden, etwa der Umgang mit Whitespace (http://saxon.sf.net/feature/strip-whitespace) oder die Zeilennummerierung (http://saxon.sf.net/feature/linenumbering). Das habe ich allerdings nicht getestet.
Quellen:
- http://ant.apache.org/manual/Tasks/style.html (unter »factory (‘trax’ processors only)« und »Using factory settings«)
- http://saxonica.com/documentation/configuration/config-interfaces/jaxp-configuration.xml
- http://saxonica.com/documentation/javadoc/constant-values.html in Verbindung mit http://saxonica.com/documentation/javadoc/net/sf/saxon/TransformerFactoryImpl.html und http://saxonica.com/documentation/javadoc/net/sf/saxon/lib/FeatureKeys.html
Apache Ant 1.8.2 unter Mac OS X einrichten
Verfasst von Stf unter Apache Ant, Mac OS X am 27. Februar 2011
Weil Ant 1.8.1 im XSLT-Task vergisst, den Classpath auszulesen, funktionieren mit dieser Version keine XSLT-2.0-Stylesheets (näheres siehe Bugzilla). Und weil Apple auch zwei Monate nach Erscheinen von Version 1.8.2 (mit dem Bugfix) noch kein Update durchgeführt hat, musste ich von Hand für Abhilfe sorgen. So geht’s:
- Ant 1.8.2 herunterladen und entpacken
- Ich habe den entpackten Ordner unter
~/Applicationsabgelegt, gleich neben der alten 1.8.0-Version. Bei mir sieht das dann so aus:
localhost:Applications stf$ ls -F -1 Crane-xslstyle-20100817-0240z/ apache-ant-1.8.0/ apache-ant-1.8.2/ calabash-0.9.24/
- Erzeugen eines SymLinks auf den Ant-Ordner. Dazu ein Terminalfenster öffnen und
ln -s ~/Applications/apache-ant-1.8.2 ~/Applications/ant
eingeben. Durch Umbiegen des SymLinks auf ein anderes Verzeichnis kann man einfach auf andere Ant-Versionen umschalten: auf eine ältere oder später auch auf eine neuere.
- Jetzt muss man
bash– dem Programm hinter dem Terminalfenster – noch sagen, dass es die neue Ant-Version benutzen soll. Dazu fügt man der PATH-Variablen dem Pfad zum neuen Ant-Verzeichnis hinzu. Ich habe dazu im Benutzerverzeichnis eine Datei./bash_profileangelegt und folgendes hineingeschrieben:
echo running ~/.bash_profile export PATH=~/Applications/ant/bin:$PATH export ANT_HOME=~/Applications/ant
Die erste Zeile gibt bei jedem Konsolenstart eine Statusmeldung aus, die zweite Zeile setzt die PATH-Umgebungsvariable, die dritte Zeile sorgt dafür, das Ant seine Dateien findet.
Da verborgene Dateien (mit Punkt am Anfang des Dateinamens) im Finder standardmäßig ausgeblendet werden, habe ich ganz UNIX-like auf der Konsole gearbeitet. Mitpico ~/.bash_profilewird der Editor geöffnet, Speichern funktioniert über
CTRL-o, Verlassen mitCTRL-x. - Eine neues Terminalfenster starten. In der zweiten Zeile sollte jetzt soetwas wie
running /Users/stf/.bash_profilestehen. Mit dem Terminal-Kommando
setlässt sich eine Liste der Umgebunsvariablen ausgeben, hier sollten jetzt für
PATHundANT_HOMEdie neuen Werte angezeigt werden. Schließlich bringt die Versionsangabe mitant -vGewissheit, ob alles geklappt hat.
Meine Helferlein auf diesem Weg waren die beiden unten angegebenen Artikel sowie man ln und man ls.
Hoffen wir, dass Apple bald auf 1.8.2 aktualisiert und zukünftig solche Workarounds nicht mehr notwendig sind …
Quellen:
- Stackoverflow: How to use an alternate version of Apache Ant on OS X without installing over existing version? (englisch)
- Cameron Hayne: Unix FAQ (for OS X) (englisch) – eine sehr übersichtliche Seite mit dem wichtigsten, was man über UNIX unter Mac OS X wissen muss.
EPUB-Beispiel aus Wikipedia
Die Beispiele aus dem Wikipedia-Artikel EPUB ergeben ein vollständiges E-Book. Leider kann man bei Commons noch keine EPUBs hochladen, siehe https://bugzilla.wikimedia.org/show_bug.cgi?id=17858. Ich habe deshalb die dazugehörigen Dateien und das EPUB in der Beispielsammlung abgelegt.
XSLT/XPath: arithmetische Operationen mit einer Leersequenz
Verfasst von Stf unter XSLT und XPath am 17. Juli 2010
Neues aus der Serie »Man lernt nie aus…«: Ist bei arithmetischen Operationen einer der Operanden die empty sequence, so ist das Ergebnis bei XSLT/XPath 1.0 NaN (»not a number«), bei XSLT/XPath 2.0 aber die empty sequence. Dieses Verhalten ist im XPath-Standard unter 3.4 Arithmetic Expressions definiert.
Ich stand vor dem Problem, eine Variable, die entweder eine xs:decimal-Zahl oder aber auch die Leersequenz enthält, in eine gültige Instanz von xs:decimal umzuwandeln, d.h. statt der Leersequenz sollte 0 geliefert werden. Es ist gängige Programmiertechnik, eine Leersequenz durch Anhängen eines Leerstrings – z.B. xs:string( ( (), '') ) – in eine gültige Instanz von xs:string (d.h. einen Leerstring) umzuwandeln. Die analoge Technik – Addieren einer Null zu einer Leersequenz – funktioniert aber wegen des im Standard definierten Verhaltens nicht. Abhilfe schafft bei XSLT 2.0 eine spezielle Funktion:
<xsl:function name="xsb:force-cast-to-integer" as="xs:decimal"> <xsl:param name="input" as="xs:string?"/> <xsl:choose> <xsl:when test="$input castable as xs:decimal"> <xsl:sequence select="xs:decimal($input)"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="0"/> </xsl:otherwise> </xsl:choose> </xsl:function>
oder kürzer:
<xsl:function name="xsb:force-cast-to-integer" as="xs:decimal"> <xsl:param name="input" as="xs:string?"/> <xsl:sequence select="if ($input castable as xs:decimal) then xs:decimal($input) else 0"/> </xsl:function>
Außer bei Leerstring und Leersequenz gibt diese Funktion auch bei nicht konvertierbaren Strings (wie z.B. römischen Zahlen) 0 zurück (was bei mir häufig das gewünschte Verhalten ist), aber die Beschränkung auf Leerstring und Leersequenz lässt sich einfach durch Ersetzen von $input castable as xs:decimal mit normalize-space($input) erzielen.
Nachtrag:
Thomas Meinicke merkte zum Rechnen mit Leersequenzen an, dass man zuerst mit exists() oder empty() prüfen kann, ob eine Sequenz leer ist, um dann den resultierenden Wahrheitswert in xs:decimal zu casten, etwa so: xs:decimal(exists( () ) ). Achtung: Dabei wird die Leersequenz zu 0, während der Leerstring zu 1 wird.
Nachtrag II:
Leersequenzen führen auch bei Vergleichs-Operationen zur Rückgabe einer Leersequenz, siehe im XPath-Standard unter 3.5.1 Value Comparisons. Da Leersequenzen zu false() evaluiert werden, ergibt beispielsweise () eq () immer false(). Um zu testen, ob eine Leersequenz vorliegt, muss deshalb empty() oder exist() verwendet werden.






