#20 Skriptování: Makra ve skriptech a Skripty v makrech + výpis verzí z Mercurialu.
authorFrantišek Kučera <franta-hg@frantovo.cz>
Thu, 05 Jul 2012 19:10:42 +0200
changeset 107379a2a893fd1
parent 106 ae484a54d7fb
child 108 8d9cab64c335
#20 Skriptování: Makra ve skriptech a Skripty v makrech + výpis verzí z Mercurialu.
vstup/makra/hg-verze.xsl
vstup/skriptování.xml
šablona/funkce/src/cz/frantovo/xmlWebGenerator/Xmlns.java
šablona/funkce/src/cz/frantovo/xmlWebGenerator/makra/Skriptování.java
šablona/makra/skriptování.xsl
     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&gt;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'">