Zadanie polega na wydłubaniu z pliku GPX pierwszego i ostatniego elementu <time>, który jest dzieckiem elementu <trkpt>. (Nie może być po prostu <time>, bo element ten występuje także w innym kontekście.)
Coś takiego wymyśliłem:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:gpx="http://www.topografix.com/GPX/1/0"> <xsl:output method="text"/> <xsl:param name='Position' select="'First'"/> <xsl:template match="/" > <xsl:for-each select='//gpx:trkpt'> <xsl:if test="position()=1 and $Position='First'"> <xsl:value-of select='gpx:time'/> <xsl:text> </xsl:text> </xsl:if> <xsl:if test="position()=last() and $Position='Last'"> <xsl:value-of select='gpx:time'/> <xsl:text> </xsl:text> </xsl:if> </xsl:for-each> </xsl:template> </xsl:stylesheet>
W praniu się okazało, że jest jeden drobny, komplikujący życie feler-nie-feler.
Struktura plików GPX (w zależności od tego
czym są one generowane) jest identyfikowana albo
z przestrzenią nazw http://www.topografix.com/GPX/1/0
albo z http://www.topografix.com/GPX/1/1
. Praktycznie żadna różnica, ale szablon
przestaje działać. Aby uodpornić szablon na wersje formatu można zamienić:
<xsl:for-each select='//gpx:trkpt'>
na
<xsl:for-each select='//*[local-name()="trkpt"]'>
Teraz szablon `reaguje' na element <trkpt> z dowolnej przestrzeni nazw. Oczywiście reguła wyboru węzłów stała się teraz `mniej specyficzna', co w przypadku bardziej skomplikowanych transformacji może nie być najlepszym pomysłem, ale w przypadku tak prostego schematu jak GPX i banalnej transformacji, jak powyższa nie powinno być problemów.
Podobnie można zamienić:
<xsl:value-of select='gpx:time'/>
na:
<xsl:value-of select='*[local-name()="time"]'/>
Teraz, przykładowo uruchomienie xsltproc (opisany wyżej
szablon jest zawartością pliku gpxtimestamp.xsl
):
xsltproc --param Position '"First"' gpxtimestamp.xsl 20120107.xml xsltproc --param Position '"Last"' gpxtimestamp.xsl 20120107.xml
Wypisuje odpowiednio zawartość pierwszego i ostatniego elementu <time>.