#20 Skriptování: Makra ve skriptech a Skripty v makrech + výpis verzí z Mercurialu.
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/vstup/makra/hg-verze.xsl Thu Jul 05 19:10:42 2012 +0200
1.3 @@ -0,0 +1,60 @@
1.4 +<?xml version="1.0" encoding="UTF-8"?>
1.5 +<xsl:stylesheet version="2.0"
1.6 + xmlns="http://www.w3.org/1999/xhtml"
1.7 + xmlns:h="http://www.w3.org/1999/xhtml"
1.8 + xmlns:s="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/strana"
1.9 + xmlns:k="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/konfigurace"
1.10 + xmlns:m="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/makro"
1.11 + xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
1.12 + xmlns:fn="http://www.w3.org/2005/xpath-functions"
1.13 + xmlns:svg="http://www.w3.org/2000/svg"
1.14 + xmlns:xs="http://www.w3.org/2001/XMLSchema"
1.15 + exclude-result-prefixes="fn h s k m xs">
1.16 +
1.17 + <!-- Vypíše verze z verzovacího systému: -->
1.18 + <xsl:template match="m:hg-verze">
1.19 + <xsl:variable name="zadáníSkriptu">
1.20 + <!--
1.21 + TODO:
1.22 + Zahazovat XML deklaraci bychom mohli v Javě u všech skriptů…
1.23 + Nicméně současná dohoda je taková, že skripty vracejí fragment, ne celý dokument,
1.24 + což má výhodu v tom, že můžou vrátit kus textu a nějakou tu značku
1.25 + a nemusí to být zabalené v kořenovém elementu.
1.26 +
1.27 + -->
1.28 + <m:skript jazyk="bash" výstup="xml">hg log --style xml | awk '{if(NR>1)print}';</m:skript>
1.29 + <!--
1.30 + Také bychom filtrování mohli provés ve skriptu…
1.31 + hg log … | xpath -e "//logentry[tag[starts-with(., 'v')]]" 2>/dev/null
1.32 + …ale to by bylo trochu zbytečně pracné.
1.33 + -->
1.34 + </xsl:variable>
1.35 +
1.36 + <xsl:variable name="výstupSkriptu">
1.37 + <xsl:apply-templates select="$zadáníSkriptu/*"/>
1.38 + </xsl:variable>
1.39 +
1.40 + <table>
1.41 + <thead>
1.42 + <tr>
1.43 + <td>Číslo verze</td>
1.44 + <td>Datum vydání</td>
1.45 + </tr>
1.46 + </thead>
1.47 + <tbody style="text-align: right;">
1.48 + <!--
1.49 + Výstup skriptu se bude nacházet v XHTML jmenném prostoru, což je obvykle v pořádku,
1.50 + ale pro mezivýsledky to není úplně vhodné.
1.51 + -->
1.52 + <xsl:for-each select="$výstupSkriptu/h:log/h:logentry[h:tag[starts-with(text(), 'v')]]">
1.53 + <tr>
1.54 + <td><xsl:value-of select="substring(h:tag/text(), 2)"/></td>
1.55 + <td><xsl:value-of select="format-dateTime(h:date, '[D]. [M]. [Y0001]')"/></td>
1.56 + </tr>
1.57 + </xsl:for-each>
1.58 + </tbody>
1.59 + </table>
1.60 + </xsl:template>
1.61 +
1.62 +</xsl:stylesheet>
1.63 +
2.1 --- a/vstup/skriptování.xml Thu Jul 05 14:27:01 2012 +0200
2.2 +++ b/vstup/skriptování.xml Thu Jul 05 19:10:42 2012 +0200
2.3 @@ -22,9 +22,11 @@
2.4
2.5 <p>
2.6 Díky skriptování můžeme stránky obohatit o prakticky libovolný obsah –
2.7 - jak prostý text, tak i XHTML fragmenty.<m:podČarou>zapíná se pomocí atributu
2.8 - <code>výstup="xml"</code> a generátor pak kontroluje správné formátování –
2.9 - nestane se vám, že byste omylem vygenerovali stránky s překříženými nebo neuzavřenými značkami.</m:podČarou>
2.10 + jak prostý text, tak i XHTML fragmenty.<m:podČarou>
2.11 + Zapíná se pomocí atributu <code>výstup="xml"</code> a generátor pak kontroluje správné formátování –
2.12 + nestane se vám, že byste omylem vygenerovali stránky s překříženými nebo neuzavřenými značkami.
2.13 + Výchozím jmenným prostorem je XHTML a je dostupný i jmenný prostor pro makra (<code>m</code>).
2.14 + </m:podČarou>
2.15 </p>
2.16 <p>
2.17 Skriptování ale může být nebezpečné, pokud byste spustili generátor na stránkách,
2.18 @@ -62,7 +64,7 @@
2.19 </tbody>
2.20 </table>
2.21
2.22 - <h2>Perl</h2>
2.23 + <h2>Perl – ukázka</h2>
2.24 <p>Jazyky použité nebo citované na této stránce:</p>
2.25 <!--
2.26 Lepšího výsledku bychom samozřejmě dosáhli pomocí XPath dotazu,
2.27 @@ -86,7 +88,7 @@
2.28 }
2.29 ]]></m:skript></pre>
2.30
2.31 - <h2>BASH</h2>
2.32 + <h2>BASH – ukázka</h2>
2.33 <pre><m:skript jazyk="bash"><![CDATA[
2.34 echo -n "Právě je: ";
2.35 date;
2.36 @@ -143,6 +145,90 @@
2.37 echo "Perex: $XWG_STRANKA_PEREX";
2.38 ]]></m:skript></pre>
2.39
2.40 + <h2>Makra ve skriptech</h2>
2.41 + <p>
2.42 + XML generované skriptem může také obsahovat makra, která se následně interptetují.
2.43 + <m:skript jazyk="bash" výstup="xml"><![CDATA[
2.44 +echo '<m:skript jazyk="bash">'; # Ty zrůdo! :-)
2.45 +echo 'echo "Takže můžeš skriptovat, když skriptuješ,";';
2.46 +echo '</m:skript>';
2.47 + ]]></m:skript>
2.48 + nebo dělat něco užitečnějšího.
2.49 + </p>
2.50 +
2.51 + <m:skript jazyk="perl" výstup="xml"><![CDATA[
2.52 +use strict;
2.53 +use warnings;
2.54 +
2.55 +my $adresar = "vstup/makra";
2.56 +
2.57 +print "<m:diagram nadpis='Uživatelská makra v adresáři $adresar'>\n";
2.58 +print " node [shape=\"box\"];\n";
2.59 +print " koren [label=\"Uživatelská makra\"];\n";
2.60 +
2.61 +opendir(DIR, $adresar) or die $!;
2.62 +my $i = 0;
2.63 +while (readdir(DIR)) {
2.64 + next if (/^\./);
2.65 + # Měli bychom ošetřit zvláštní znaky v názvech souborů,
2.66 + # abychom nezpůsobili chybu GraphVizu.
2.67 + print "n$i [label=\"$_\"];\n";
2.68 + print "koren -> n$i;\n";
2.69 + $i++;
2.70 +}
2.71 +print "</m:diagram>";
2.72 +closedir(DIR);
2.73 + ]]></m:skript>
2.74 +
2.75 + <p>…třeba vygenerovat tento diagram následujícím perlovským skriptem:</p>
2.76 +
2.77 + <m:pre jazyk="perl"><![CDATA[
2.78 +use strict;
2.79 +use warnings;
2.80 +
2.81 +my $adresar = "vstup/makra";
2.82 +
2.83 +print "<m:diagram nadpis='Uživatelská makra v adresáři $adresar'>\n";
2.84 +print " node [shape=\"box\"];\n";
2.85 +print " koren [label=\"Uživatelská makra\"];\n";
2.86 +
2.87 +opendir(DIR, $adresar) or die $!;
2.88 +my $i = 0;
2.89 +while (readdir(DIR)) {
2.90 + next if (/^\./);
2.91 + # Měli bychom ošetřit zvláštní znaky v názvech souborů,
2.92 + # abychom nezpůsobili chybu GraphVizu.
2.93 + print "n$i [label=\"$_\"];\n";
2.94 + print "koren -> n$i;\n";
2.95 + $i++;
2.96 +}
2.97 +print "</m:diagram>";
2.98 +closedir(DIR);]]></m:pre>
2.99 +
2.100 + <p>
2.101 + Který vložíme zabalený v <code><![CDATA[<m:skript jazyk="perl" výstup="xml"> … </m:skript>]]></code> do stránky.
2.102 + </p>
2.103 + <p>
2.104 + 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í).
2.105 + </p>
2.106 +
2.107 + <h2>Skripty v makrech</h2>
2.108 + <p>
2.109 + Uvnitř maker můžeme volat<m:podČarou>
2.110 + Ovšem trochu jiným způsobem, než ve stránkách –
2.111 + nacházíme se totiž v <em>programu</em> (XSL šablona definující makro)
2.112 + nikoli v <em>datovém souboru</em> (XML stránka).
2.113 + </m:podČarou>
2.114 + jiná makra – mj. skripty.
2.115 + Toho jsme využili v makru, které generuje tabulku verzí z mercurialu:
2.116 + </p>
2.117 +
2.118 + <m:hg-verze/>
2.119 +
2.120 + <p>
2.121 + Toto makro naleznete v souboru <code>vstup/makra/hg-verze.xsl</code>.
2.122 + </p>
2.123 +
2.124 </text>
2.125
2.126 </stránka>
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/šablona/funkce/src/cz/frantovo/xmlWebGenerator/Xmlns.java Thu Jul 05 19:10:42 2012 +0200
3.3 @@ -0,0 +1,15 @@
3.4 +package cz.frantovo.xmlWebGenerator;
3.5 +
3.6 +/**
3.7 + * XML jmenné prostory používané v generátoru
3.8 + *
3.9 + * @author Ing. František Kučera (frantovo.cz)
3.10 + */
3.11 +public class Xmlns {
3.12 +
3.13 + public static final String XHTML = "http://www.w3.org/1999/xhtml";
3.14 + public static final String MAKRO = "https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/makro";
3.15 +
3.16 + private Xmlns() {
3.17 + }
3.18 +}
4.1 --- a/šablona/funkce/src/cz/frantovo/xmlWebGenerator/makra/Skriptování.java Thu Jul 05 14:27:01 2012 +0200
4.2 +++ b/šablona/funkce/src/cz/frantovo/xmlWebGenerator/makra/Skriptování.java Thu Jul 05 19:10:42 2012 +0200
4.3 @@ -18,6 +18,7 @@
4.4 package cz.frantovo.xmlWebGenerator.makra;
4.5
4.6 import static cz.frantovo.xmlWebGenerator.NástrojeCLI.načtiProud;
4.7 +import static cz.frantovo.xmlWebGenerator.Xmlns.*;
4.8 import java.io.ByteArrayInputStream;
4.9 import java.io.File;
4.10 import java.io.PrintStream;
4.11 @@ -27,7 +28,10 @@
4.12 import java.util.Map;
4.13 import javax.xml.parsers.DocumentBuilder;
4.14 import javax.xml.parsers.DocumentBuilderFactory;
4.15 +import javax.xml.transform.Source;
4.16 +import javax.xml.transform.dom.DOMSource;
4.17 import org.w3c.dom.Document;
4.18 +import org.w3c.dom.Node;
4.19
4.20 /**
4.21 * Provedeme skript a do stránky vložíme jeho výstup.
4.22 @@ -62,9 +66,15 @@
4.23 * @param uriStránky URI aktuálně generované stránky → proměnná prostředí
4.24 * @param nadpisStránky nadpis stránky → proměnná prostředí
4.25 * @param perexStránky perex stránky → proměnná prostředí
4.26 - * @return výstup příkazu
4.27 + * @return výstup příkazu buď jako textový řetězec nebo jako XML (DOMSource)
4.28 */
4.29 - public static String interpretuj(String skriptText, String skriptSoubor, String jazyk, String výstupníFormát, String uriStránky, String nadpisStránky, String perexStránky) {
4.30 + 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 {
4.31 + String výstupSkriptu = získejVýstupSkriptu(skriptText, skriptSoubor, jazyk, uriStránky, nadpisStránky, perexStránky);
4.32 + return vyrobXml(výstupSkriptu, "xml".equals(výstupníFormát));
4.33 + }
4.34 +
4.35 + private static String získejVýstupSkriptu(String skriptText, String skriptSoubor, String jazyk, String uriStránky, String nadpisStránky, String perexStránky) throws Exception {
4.36 +
4.37 try {
4.38 if (isNeprázdný(skriptSoubor)) {
4.39 System.err.println("\tInterpretuji skript ze souboru: " + skriptSoubor);
4.40 @@ -136,7 +146,7 @@
4.41 System.err.println("Nicméně skript skončil úspěšně, takže pokračujeme dál.");
4.42 }
4.43
4.44 - return připravVýstup(výsledek, výstupníFormát);
4.45 + return výsledek.trim();
4.46 } else {
4.47 System.err.println("--- Standardní výstup skriptu: -----");
4.48 System.err.println(výsledek);
4.49 @@ -146,26 +156,12 @@
4.50 throw new Exception("Návratová hodnota: " + p.exitValue());
4.51 }
4.52 } catch (Exception e) {
4.53 - System.err.println("Došlo k chybě při vykonávání skriptu v jazyce: " + jazyk);
4.54 + System.err.println("Došlo k chybě při vykonávání skriptu.");
4.55 System.err.println("--------");
4.56 System.err.println(skriptText);
4.57 System.err.println("--------");
4.58 e.printStackTrace(System.err);
4.59 - return null;
4.60 - }
4.61 - }
4.62 -
4.63 - private static String připravVýstup(String výsledek, String formát) {
4.64 - if ("xml".equals(formát)) {
4.65 - if (zkontrolujXml(výsledek)) {
4.66 - return výsledek.trim();
4.67 - } else {
4.68 - System.err.println("Chyba v XML generovaném skriptem:");
4.69 - System.err.println(výsledek);
4.70 - return null;
4.71 - }
4.72 - } else {
4.73 - return výsledek.trim();
4.74 + throw e;
4.75 }
4.76 }
4.77
4.78 @@ -174,19 +170,34 @@
4.79 }
4.80
4.81 /**
4.82 - * @param xml fragment XML vygenerovaný skriptem
4.83 - * @return true v případě, že výstup je validním fragmentem XML
4.84 + * @param zadání výstup vygenerovaný skriptem
4.85 + * @param xmlFormát formát zadání: true = xml fragment | false = prostý text
4.86 + * @return xml fragment nebo prostý text zabalený do html/body
4.87 + * @throws Exception
4.88 */
4.89 - private static boolean zkontrolujXml(String xml) {
4.90 - try {
4.91 - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
4.92 - DocumentBuilder db = dbf.newDocumentBuilder();
4.93 - xml = "<xml>" + xml + "</xml>";
4.94 - Document d = db.parse(new ByteArrayInputStream(xml.getBytes()));
4.95 - return true;
4.96 - } catch (Exception e) {
4.97 - e.printStackTrace(System.err);
4.98 - return false;
4.99 + private static Source vyrobXml(String zadání, boolean xmlFormát) throws Exception {
4.100 + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
4.101 + DocumentBuilder db = dbf.newDocumentBuilder();
4.102 + Document d;
4.103 +
4.104 + if (xmlFormát) {
4.105 + try {
4.106 + zadání = "<html xmlns='" + XHTML + "' xmlns:m='" + MAKRO + "'><body>" + zadání + "</body></html>";
4.107 + d = db.parse(new ByteArrayInputStream(zadání.getBytes()));
4.108 + } catch (Exception e) {
4.109 + System.err.println("Chyba: Skript vrátil neplatné XML.");
4.110 + throw e;
4.111 + }
4.112 + } else {
4.113 + d = db.newDocument();
4.114 + Node html = d.createElementNS(XHTML, "html");
4.115 + Node body = d.createElementNS(XHTML, "body");
4.116 + Node text = d.createTextNode(zadání);
4.117 + body.appendChild(text);
4.118 + html.appendChild(body);
4.119 + d.appendChild(html);
4.120 }
4.121 +
4.122 + return new DOMSource(d);
4.123 }
4.124 }
5.1 --- a/šablona/makra/skriptování.xsl Thu Jul 05 14:27:01 2012 +0200
5.2 +++ b/šablona/makra/skriptování.xsl Thu Jul 05 19:10:42 2012 +0200
5.3 @@ -18,6 +18,7 @@
5.4 -->
5.5 <xsl:stylesheet version="2.0"
5.6 xmlns="http://www.w3.org/1999/xhtml"
5.7 + xmlns:h="http://www.w3.org/1999/xhtml"
5.8 xmlns:m="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/makro"
5.9 xmlns:j="java:cz.frantovo.xmlWebGenerator.makra.Skriptování"
5.10 xmlns:k="https://trac.frantovo.cz/xml-web-generator/wiki/xmlns/konfigurace"
5.11 @@ -49,17 +50,7 @@
5.12 //s:stránka/s:nadpis/text(),
5.13 //s:stránka/s:perex/text()
5.14 )"/>
5.15 - <xsl:choose>
5.16 - <xsl:when test="$výstupSkriptu">
5.17 - <xsl:choose>
5.18 - <xsl:when test="@výstup = 'xml'"><xsl:value-of select="$výstupSkriptu" disable-output-escaping="yes"/></xsl:when>
5.19 - <xsl:otherwise><xsl:value-of select="$výstupSkriptu"/></xsl:otherwise>
5.20 - </xsl:choose>
5.21 - </xsl:when>
5.22 - <xsl:otherwise>
5.23 - <xsl:message terminate="yes">Při interpretaci skriptu došlo k chybě.</xsl:message>
5.24 - </xsl:otherwise>
5.25 - </xsl:choose>
5.26 + <xsl:apply-templates select="$výstupSkriptu/h:html/h:body/node()"/>
5.27 </xsl:when>
5.28
5.29 <xsl:when test="$režim = 'zakázat'">