#20 Skriptování: Makra ve skriptech a Skripty v makrech + výpis verzí z Mercurialu.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/vstup/makra/hg-verze.xsl Thu Jul 05 19:10:42 2012 +0200
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet version="2.0"
+ xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://www.w3.org/1999/xhtml"
+ xmlns:s="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/strana"
+ xmlns:k="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/konfigurace"
+ xmlns:m="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/makro"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:fn="http://www.w3.org/2005/xpath-functions"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ exclude-result-prefixes="fn h s k m xs">
+
+ <!-- Vypíše verze z verzovacího systému: -->
+ <xsl:template match="m:hg-verze">
+ <xsl:variable name="zadáníSkriptu">
+ <!--
+ TODO:
+ Zahazovat XML deklaraci bychom mohli v Javě u všech skriptů…
+ Nicméně současná dohoda je taková, že skripty vracejí fragment, ne celý dokument,
+ což má výhodu v tom, že můžou vrátit kus textu a nějakou tu značku
+ a nemusí to být zabalené v kořenovém elementu.
+
+ -->
+ <m:skript jazyk="bash" výstup="xml">hg log --style xml | awk '{if(NR>1)print}';</m:skript>
+ <!--
+ Také bychom filtrování mohli provés ve skriptu…
+ hg log … | xpath -e "//logentry[tag[starts-with(., 'v')]]" 2>/dev/null
+ …ale to by bylo trochu zbytečně pracné.
+ -->
+ </xsl:variable>
+
+ <xsl:variable name="výstupSkriptu">
+ <xsl:apply-templates select="$zadáníSkriptu/*"/>
+ </xsl:variable>
+
+ <table>
+ <thead>
+ <tr>
+ <td>Číslo verze</td>
+ <td>Datum vydání</td>
+ </tr>
+ </thead>
+ <tbody style="text-align: right;">
+ <!--
+ Výstup skriptu se bude nacházet v XHTML jmenném prostoru, což je obvykle v pořádku,
+ ale pro mezivýsledky to není úplně vhodné.
+ -->
+ <xsl:for-each select="$výstupSkriptu/h:log/h:logentry[h:tag[starts-with(text(), 'v')]]">
+ <tr>
+ <td><xsl:value-of select="substring(h:tag/text(), 2)"/></td>
+ <td><xsl:value-of select="format-dateTime(h:date, '[D]. [M]. [Y0001]')"/></td>
+ </tr>
+ </xsl:for-each>
+ </tbody>
+ </table>
+ </xsl:template>
+
+</xsl:stylesheet>
+
--- a/vstup/skriptování.xml Thu Jul 05 14:27:01 2012 +0200
+++ b/vstup/skriptování.xml Thu Jul 05 19:10:42 2012 +0200
@@ -22,9 +22,11 @@
<p>
Díky skriptování můžeme stránky obohatit o prakticky libovolný obsah –
- jak prostý text, tak i XHTML fragmenty.<m:podČarou>zapíná se pomocí atributu
- <code>výstup="xml"</code> a generátor pak kontroluje správné formátování –
- nestane se vám, že byste omylem vygenerovali stránky s překříženými nebo neuzavřenými značkami.</m:podČarou>
+ jak prostý text, tak i XHTML fragmenty.<m:podČarou>
+ Zapíná se pomocí atributu <code>výstup="xml"</code> a generátor pak kontroluje správné formátování –
+ nestane se vám, že byste omylem vygenerovali stránky s překříženými nebo neuzavřenými značkami.
+ Výchozím jmenným prostorem je XHTML a je dostupný i jmenný prostor pro makra (<code>m</code>).
+ </m:podČarou>
</p>
<p>
Skriptování ale může být nebezpečné, pokud byste spustili generátor na stránkách,
@@ -62,7 +64,7 @@
</tbody>
</table>
- <h2>Perl</h2>
+ <h2>Perl – ukázka</h2>
<p>Jazyky použité nebo citované na této stránce:</p>
<!--
Lepšího výsledku bychom samozřejmě dosáhli pomocí XPath dotazu,
@@ -86,7 +88,7 @@
}
]]></m:skript></pre>
- <h2>BASH</h2>
+ <h2>BASH – ukázka</h2>
<pre><m:skript jazyk="bash"><![CDATA[
echo -n "Právě je: ";
date;
@@ -143,6 +145,90 @@
echo "Perex: $XWG_STRANKA_PEREX";
]]></m:skript></pre>
+ <h2>Makra ve skriptech</h2>
+ <p>
+ XML generované skriptem může také obsahovat makra, která se následně interptetují.
+ <m:skript jazyk="bash" výstup="xml"><![CDATA[
+echo '<m:skript jazyk="bash">'; # Ty zrůdo! :-)
+echo 'echo "Takže můžeš skriptovat, když skriptuješ,";';
+echo '</m:skript>';
+ ]]></m:skript>
+ nebo dělat něco užitečnějšího.
+ </p>
+
+ <m:skript jazyk="perl" výstup="xml"><![CDATA[
+use strict;
+use warnings;
+
+my $adresar = "vstup/makra";
+
+print "<m:diagram nadpis='Uživatelská makra v adresáři $adresar'>\n";
+print " node [shape=\"box\"];\n";
+print " koren [label=\"Uživatelská makra\"];\n";
+
+opendir(DIR, $adresar) or die $!;
+my $i = 0;
+while (readdir(DIR)) {
+ next if (/^\./);
+ # Měli bychom ošetřit zvláštní znaky v názvech souborů,
+ # abychom nezpůsobili chybu GraphVizu.
+ print "n$i [label=\"$_\"];\n";
+ print "koren -> n$i;\n";
+ $i++;
+}
+print "</m:diagram>";
+closedir(DIR);
+ ]]></m:skript>
+
+ <p>…třeba vygenerovat tento diagram následujícím perlovským skriptem:</p>
+
+ <m:pre jazyk="perl"><![CDATA[
+use strict;
+use warnings;
+
+my $adresar = "vstup/makra";
+
+print "<m:diagram nadpis='Uživatelská makra v adresáři $adresar'>\n";
+print " node [shape=\"box\"];\n";
+print " koren [label=\"Uživatelská makra\"];\n";
+
+opendir(DIR, $adresar) or die $!;
+my $i = 0;
+while (readdir(DIR)) {
+ next if (/^\./);
+ # Měli bychom ošetřit zvláštní znaky v názvech souborů,
+ # abychom nezpůsobili chybu GraphVizu.
+ print "n$i [label=\"$_\"];\n";
+ print "koren -> n$i;\n";
+ $i++;
+}
+print "</m:diagram>";
+closedir(DIR);]]></m:pre>
+
+ <p>
+ Který vložíme zabalený v <code><![CDATA[<m:skript jazyk="perl" výstup="xml"> … </m:skript>]]></code> do stránky.
+ </p>
+ <p>
+ Známá chyba: ve skriptech zatím nefungují poznámky pod čarou (a není jisté, jestli kdy fungovat budou – pravděpodobně by to vyžadovalo vícefázové zpracování).
+ </p>
+
+ <h2>Skripty v makrech</h2>
+ <p>
+ Uvnitř maker můžeme volat<m:podČarou>
+ Ovšem trochu jiným způsobem, než ve stránkách –
+ nacházíme se totiž v <em>programu</em> (XSL šablona definující makro)
+ nikoli v <em>datovém souboru</em> (XML stránka).
+ </m:podČarou>
+ jiná makra – mj. skripty.
+ Toho jsme využili v makru, které generuje tabulku verzí z mercurialu:
+ </p>
+
+ <m:hg-verze/>
+
+ <p>
+ Toto makro naleznete v souboru <code>vstup/makra/hg-verze.xsl</code>.
+ </p>
+
</text>
</stránka>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/šablona/funkce/src/cz/frantovo/xmlWebGenerator/Xmlns.java Thu Jul 05 19:10:42 2012 +0200
@@ -0,0 +1,15 @@
+package cz.frantovo.xmlWebGenerator;
+
+/**
+ * XML jmenné prostory používané v generátoru
+ *
+ * @author Ing. František Kučera (frantovo.cz)
+ */
+public class Xmlns {
+
+ public static final String XHTML = "http://www.w3.org/1999/xhtml";
+ public static final String MAKRO = "https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/makro";
+
+ private Xmlns() {
+ }
+}
--- a/šablona/funkce/src/cz/frantovo/xmlWebGenerator/makra/Skriptování.java Thu Jul 05 14:27:01 2012 +0200
+++ b/šablona/funkce/src/cz/frantovo/xmlWebGenerator/makra/Skriptování.java Thu Jul 05 19:10:42 2012 +0200
@@ -18,6 +18,7 @@
package cz.frantovo.xmlWebGenerator.makra;
import static cz.frantovo.xmlWebGenerator.NástrojeCLI.načtiProud;
+import static cz.frantovo.xmlWebGenerator.Xmlns.*;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.PrintStream;
@@ -27,7 +28,10 @@
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Source;
+import javax.xml.transform.dom.DOMSource;
import org.w3c.dom.Document;
+import org.w3c.dom.Node;
/**
* Provedeme skript a do stránky vložíme jeho výstup.
@@ -62,9 +66,15 @@
* @param uriStránky URI aktuálně generované stránky → proměnná prostředí
* @param nadpisStránky nadpis stránky → proměnná prostředí
* @param perexStránky perex stránky → proměnná prostředí
- * @return výstup příkazu
+ * @return výstup příkazu buď jako textový řetězec nebo jako XML (DOMSource)
*/
- public static String interpretuj(String skriptText, String skriptSoubor, String jazyk, String výstupníFormát, String uriStránky, String nadpisStránky, String perexStránky) {
+ public static Source interpretuj(String skriptText, String skriptSoubor, String jazyk, String výstupníFormát, String uriStránky, String nadpisStránky, String perexStránky) throws Exception {
+ String výstupSkriptu = získejVýstupSkriptu(skriptText, skriptSoubor, jazyk, uriStránky, nadpisStránky, perexStránky);
+ return vyrobXml(výstupSkriptu, "xml".equals(výstupníFormát));
+ }
+
+ private static String získejVýstupSkriptu(String skriptText, String skriptSoubor, String jazyk, String uriStránky, String nadpisStránky, String perexStránky) throws Exception {
+
try {
if (isNeprázdný(skriptSoubor)) {
System.err.println("\tInterpretuji skript ze souboru: " + skriptSoubor);
@@ -136,7 +146,7 @@
System.err.println("Nicméně skript skončil úspěšně, takže pokračujeme dál.");
}
- return připravVýstup(výsledek, výstupníFormát);
+ return výsledek.trim();
} else {
System.err.println("--- Standardní výstup skriptu: -----");
System.err.println(výsledek);
@@ -146,26 +156,12 @@
throw new Exception("Návratová hodnota: " + p.exitValue());
}
} catch (Exception e) {
- System.err.println("Došlo k chybě při vykonávání skriptu v jazyce: " + jazyk);
+ System.err.println("Došlo k chybě při vykonávání skriptu.");
System.err.println("--------");
System.err.println(skriptText);
System.err.println("--------");
e.printStackTrace(System.err);
- return null;
- }
- }
-
- private static String připravVýstup(String výsledek, String formát) {
- if ("xml".equals(formát)) {
- if (zkontrolujXml(výsledek)) {
- return výsledek.trim();
- } else {
- System.err.println("Chyba v XML generovaném skriptem:");
- System.err.println(výsledek);
- return null;
- }
- } else {
- return výsledek.trim();
+ throw e;
}
}
@@ -174,19 +170,34 @@
}
/**
- * @param xml fragment XML vygenerovaný skriptem
- * @return true v případě, že výstup je validním fragmentem XML
+ * @param zadání výstup vygenerovaný skriptem
+ * @param xmlFormát formát zadání: true = xml fragment | false = prostý text
+ * @return xml fragment nebo prostý text zabalený do html/body
+ * @throws Exception
*/
- private static boolean zkontrolujXml(String xml) {
- try {
- DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- DocumentBuilder db = dbf.newDocumentBuilder();
- xml = "<xml>" + xml + "</xml>";
- Document d = db.parse(new ByteArrayInputStream(xml.getBytes()));
- return true;
- } catch (Exception e) {
- e.printStackTrace(System.err);
- return false;
+ private static Source vyrobXml(String zadání, boolean xmlFormát) throws Exception {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document d;
+
+ if (xmlFormát) {
+ try {
+ zadání = "<html xmlns='" + XHTML + "' xmlns:m='" + MAKRO + "'><body>" + zadání + "</body></html>";
+ d = db.parse(new ByteArrayInputStream(zadání.getBytes()));
+ } catch (Exception e) {
+ System.err.println("Chyba: Skript vrátil neplatné XML.");
+ throw e;
+ }
+ } else {
+ d = db.newDocument();
+ Node html = d.createElementNS(XHTML, "html");
+ Node body = d.createElementNS(XHTML, "body");
+ Node text = d.createTextNode(zadání);
+ body.appendChild(text);
+ html.appendChild(body);
+ d.appendChild(html);
}
+
+ return new DOMSource(d);
}
}
--- a/šablona/makra/skriptování.xsl Thu Jul 05 14:27:01 2012 +0200
+++ b/šablona/makra/skriptování.xsl Thu Jul 05 19:10:42 2012 +0200
@@ -18,6 +18,7 @@
-->
<xsl:stylesheet version="2.0"
xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:m="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/makro"
xmlns:j="java:cz.frantovo.xmlWebGenerator.makra.Skriptování"
xmlns:k="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/konfigurace"
@@ -49,17 +50,7 @@
//s:stránka/s:nadpis/text(),
//s:stránka/s:perex/text()
)"/>
- <xsl:choose>
- <xsl:when test="$výstupSkriptu">
- <xsl:choose>
- <xsl:when test="@výstup = 'xml'"><xsl:value-of select="$výstupSkriptu" disable-output-escaping="yes"/></xsl:when>
- <xsl:otherwise><xsl:value-of select="$výstupSkriptu"/></xsl:otherwise>
- </xsl:choose>
- </xsl:when>
- <xsl:otherwise>
- <xsl:message terminate="yes">Při interpretaci skriptu došlo k chybě.</xsl:message>
- </xsl:otherwise>
- </xsl:choose>
+ <xsl:apply-templates select="$výstupSkriptu/h:html/h:body/node()"/>
</xsl:when>
<xsl:when test="$režim = 'zakázat'">