#20 Skriptování: podpora výstupu ve formátu XML (musí být validní)
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sat Jun 23 19:22:21 2012 +0200 (2012-06-23)
changeset 95eea9c4713045
parent 94 4b3ba32f613c
child 96 8de228c9ac10
#20 Skriptování: podpora výstupu ve formátu XML (musí být validní)
vstup/skriptování.xml
šablona/funkce/src/cz/frantovo/xmlWebGenerator/makra/Skriptování.java
šablona/makra/skriptování.xsl
     1.1 --- a/vstup/skriptování.xml	Sat Jun 23 18:00:41 2012 +0200
     1.2 +++ b/vstup/skriptování.xml	Sat Jun 23 19:22:21 2012 +0200
     1.3 @@ -8,30 +8,51 @@
     1.4  	
     1.5  		<p>
     1.6  			Na stránkách můžeme používat skripty.
     1.7 -			Spouští se při generování a jejich standardní výstup se vloží do stránky.
     1.8 -			Třeba doprostřed ostavce nebo do jiného elementu.
     1.9 +			Spouští se při generování a jejich standardní výstup se vloží do stránky.
    1.10 +			Třeba doprostřed textu ostavce nebo do jiného elementu.
    1.11  		</p>
    1.12  		<p>
    1.13  			Příklad:
    1.14 -			Tyto stránky byly vygenerované v systému <m:skript jazyk="bash">uname -o</m:skript>.
    1.15 +			<em>
    1.16 +				Tyto stránky byly vygenerované v systému
    1.17 +				<span title="tento text pochází ze skriptu"><m:skript jazyk="bash">uname -o</m:skript></span>.
    1.18 +			</em>
    1.19 +		</p>
    1.20 +
    1.21 +		<p>
    1.22 +			Díky skriptování můžeme stránky obohatit o prakticky libovolný obsah.
    1.23 +			Tato funkce ale může být nebezpečná – pokud byste spustili generátor na stránkách,
    1.24 +			které psal někdo nedůvěryhodný a vložil do nich škodlivý kód.
    1.25 +			Proto je skriptování ve výchozím stavu vypnuté – je potřeba ho povolit v souboru <code>web.conf</code>.
    1.26 +		</p>
    1.27 +
    1.28 +		<h2>Podporované jazyky</h2>
    1.29 +		<p>
    1.30 +			V současnosti jsou podporované tyto jazyky:
    1.31  		</p>
    1.32  		
    1.33 -		<p>
    1.34 -			V současnosti jsou podporované tyto jazyky:
    1.35 -		</p>
    1.36 -		
    1.37 -		<pre><m:skript jazyk="perl"><![CDATA[
    1.38 +		<table>
    1.39 +			<thead>
    1.40 +				<tr>
    1.41 +					<td>Jazyk</td>
    1.42 +					<td>Interpret</td>
    1.43 +				</tr>
    1.44 +			</thead>
    1.45 +			<tbody>
    1.46 +				<m:skript jazyk="perl"  výstup="xml"><![CDATA[
    1.47  use strict;
    1.48  
    1.49 -open(JAVA, "<", "šablona/funkce/src/cz/frantovo/xmlWebGenerator/makra/Skriptování.java") or die $!;
    1.50 +open(JAVA, "<", $ENV{"XWG_SKRIPTOVANI_JAVA"}) or die $!;
    1.51  
    1.52  while (<JAVA>) {
    1.53  #i.put("bash", "/bin/bash");
    1.54  	if (/podporovanýJazyk\.put\("(\w+)",\s*"(.*)"\);/) {
    1.55 -		print "$1\n";
    1.56 +		print "<tr><td><code>$1</code></td><td><code>$2</code></td></tr>\n";
    1.57  	}
    1.58  }
    1.59 -			]]></m:skript></pre>
    1.60 +				]]></m:skript>
    1.61 +			</tbody>
    1.62 +		</table>
    1.63  
    1.64  		<h2>Perl</h2>
    1.65  		<p>Jazyky použité nebo citované na této stránce:</p>
    1.66 @@ -76,12 +97,28 @@
    1.67  				Ve skriptech máme dostupné následující proměnné prostředí:
    1.68  			</p>
    1.69  			
    1.70 -			<ul>
    1.71 -				<li><code>XWG_STRANKA_URI</code> – URI aktuálně zpracovávané stránky</li>
    1.72 -				<li><code>XWG_STRANKA_SOUBOR</code> – absolutní cesta k souboru</li>
    1.73 -				<li><code>XWG_STRANKA_NADPIS</code> – nadpis stránky</li>
    1.74 -				<li><code>XWG_STRANKA_PEREX</code> – perex stránky</li>
    1.75 -			</ul>
    1.76 +			<table>
    1.77 +				<thead>
    1.78 +					<tr>
    1.79 +						<td>Proměnná</td>
    1.80 +						<td>Význam</td>
    1.81 +					</tr>
    1.82 +				</thead>
    1.83 +				<tbody>
    1.84 +					<m:skript jazyk="perl" výstup="xml"><![CDATA[
    1.85 +use strict;
    1.86 +
    1.87 +open(JAVA, "<", $ENV{"XWG_SKRIPTOVANI_JAVA"}) or die $!;
    1.88 +
    1.89 +while (<JAVA>) {
    1.90 +#i.put("bash", "/bin/bash");
    1.91 +	if (/"(.*)=".*\/\/\s+env:(.*)/) {
    1.92 +		print "<tr><td><code>$1</code></td><td>$2</td></tr>\n";
    1.93 +	}
    1.94 +}
    1.95 +					]]></m:skript>
    1.96 +				</tbody>
    1.97 +			</table>
    1.98  			
    1.99  			<p>
   1.100  				Kód:
     2.1 --- a/šablona/funkce/src/cz/frantovo/xmlWebGenerator/makra/Skriptování.java	Sat Jun 23 18:00:41 2012 +0200
     2.2 +++ b/šablona/funkce/src/cz/frantovo/xmlWebGenerator/makra/Skriptování.java	Sat Jun 23 19:22:21 2012 +0200
     2.3 @@ -18,12 +18,16 @@
     2.4  package cz.frantovo.xmlWebGenerator.makra;
     2.5  
     2.6  import static cz.frantovo.xmlWebGenerator.NástrojeCLI.načtiProud;
     2.7 +import java.io.ByteArrayInputStream;
     2.8  import java.io.File;
     2.9  import java.io.PrintStream;
    2.10  import java.net.URI;
    2.11  import java.util.Collections;
    2.12  import java.util.HashMap;
    2.13  import java.util.Map;
    2.14 +import javax.xml.parsers.DocumentBuilder;
    2.15 +import javax.xml.parsers.DocumentBuilderFactory;
    2.16 +import org.w3c.dom.Document;
    2.17  
    2.18  /**
    2.19   * Provedeme skript a do stránky vložíme jeho výstup.
    2.20 @@ -53,12 +57,13 @@
    2.21  	 *
    2.22  	 * @param skript program k vykonání
    2.23  	 * @param jazyk programovací jazyk
    2.24 +	 * @param výstupníFormát text (výchozí) | xml (v tom případě kontrolujeme validitu)
    2.25  	 * @param uriStránky URI aktuálně generované stránky → proměnná prostředí
    2.26  	 * @param nadpisStránky nadpis stránky → proměnná prostředí
    2.27  	 * @param perexStránky perex stránky → proměnná prostředí
    2.28  	 * @return výstup příkazu
    2.29  	 */
    2.30 -	public static String interpretuj(String skript, String jazyk, String uriStránky, String nadpisStránky, String perexStránky) {
    2.31 +	public static String interpretuj(String skript, String jazyk, String výstupníFormát, String uriStránky, String nadpisStránky, String perexStránky) {
    2.32  		try {
    2.33  			System.err.println("\tInterpretuji skript v jazyce: " + jazyk);
    2.34  			String interpret = interpreti.get(jazyk);
    2.35 @@ -76,19 +81,20 @@
    2.36  				ps.print(skript);
    2.37  				ps.close();
    2.38  
    2.39 -				f.setExecutable(true);
    2.40  
    2.41  				String[] prostředí = new String[]{
    2.42  					"LANG=" + System.getenv("LANG"),
    2.43  					"USER=" + System.getenv("USER"),
    2.44 -					"XWG_STRANKA_URI=" + uriStránky,
    2.45 -					"XWG_STRANKA_SOUBOR=" + (new File(new URI(uriStránky)).getAbsolutePath()),
    2.46 -					"XWG_STRANKA_NADPIS=" + nadpisStránky,
    2.47 -					"XWG_STRANKA_PEREX=" + perexStránky
    2.48 +					"XWG_SKRIPTOVANI_JAVA=" + "šablona" + File.separator + "funkce" + File.separator + "src" + File.separator + Skriptování.class.getName().replaceAll("\\.", File.separator) + ".java",
    2.49 +					"XWG_STRANKA_URI=" + uriStránky, // env:URI aktuálně zpracovávané stránky
    2.50 +					"XWG_STRANKA_SOUBOR=" + (new File(new URI(uriStránky)).getAbsolutePath()), // env:absolutní cesta k souboru
    2.51 +					"XWG_STRANKA_NADPIS=" + nadpisStránky, // env:nadpis stránky
    2.52 +					"XWG_STRANKA_PEREX=" + perexStránky // env:perex stránky
    2.53  				};
    2.54  
    2.55  
    2.56  
    2.57 +				f.setExecutable(true);
    2.58  				Runtime r = Runtime.getRuntime();
    2.59  				Process p = r.exec(new String[]{f.getAbsolutePath()}, prostředí);
    2.60  
    2.61 @@ -97,19 +103,15 @@
    2.62  
    2.63  				p.waitFor();
    2.64  
    2.65 -				/**
    2.66 -				 * TODO: podporovat zvláštní návratový kód, kterým skript řekne,
    2.67 -				 * že výstupem je XML a má se vložit jako fragment do dokumentu,
    2.68 -				 * ne jako prostý text.
    2.69 -				 */
    2.70  				if (p.exitValue() == 0) {
    2.71  					if (chyby.length() > 0) {
    2.72 -						System.err.println("--- Cyhbový výstup skriptu -----");
    2.73 +						System.err.println("--- Chybový výstup skriptu -----");
    2.74  						System.err.println(chyby);
    2.75  						System.err.println("--------------------------------");
    2.76 +						System.err.println("Nicméně skript skončil úspěšně, takže pokračujeme dál.");
    2.77  					}
    2.78  
    2.79 -					return výsledek.trim();
    2.80 +					return připravVýstup(výsledek, výstupníFormát);
    2.81  				} else {
    2.82  					System.err.println("--- Standardní výstup skriptu: -----");
    2.83  					System.err.println(výsledek);
    2.84 @@ -128,4 +130,35 @@
    2.85  			return null;
    2.86  		}
    2.87  	}
    2.88 +
    2.89 +	private static String připravVýstup(String výsledek, String formát) {
    2.90 +		if ("xml".equals(formát)) {
    2.91 +			if (zkontrolujXml(výsledek)) {
    2.92 +				return výsledek.trim();
    2.93 +			} else {
    2.94 +				System.err.println("Chyba v XML generovaném skriptem:");
    2.95 +				System.err.println(výsledek);
    2.96 +				return null;
    2.97 +			}
    2.98 +		} else {
    2.99 +			return výsledek.trim();
   2.100 +		}
   2.101 +	}
   2.102 +
   2.103 +	/**
   2.104 +	 * @param xml fragment XML vygenerovaný skriptem
   2.105 +	 * @return true v případě, že výstup je validním fragmentem XML
   2.106 +	 */
   2.107 +	private static boolean zkontrolujXml(String xml) {
   2.108 +		try {
   2.109 +			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
   2.110 +			DocumentBuilder db = dbf.newDocumentBuilder();
   2.111 +			xml = "<xml>" + xml + "</xml>";
   2.112 +			Document d = db.parse(new ByteArrayInputStream(xml.getBytes()));
   2.113 +			return true;
   2.114 +		} catch (Exception e) {
   2.115 +			e.printStackTrace(System.err);
   2.116 +			return false;
   2.117 +		}
   2.118 +	}
   2.119  }
     3.1 --- a/šablona/makra/skriptování.xsl	Sat Jun 23 18:00:41 2012 +0200
     3.2 +++ b/šablona/makra/skriptování.xsl	Sat Jun 23 19:22:21 2012 +0200
     3.3 @@ -30,6 +30,7 @@
     3.4  		Provedeme skript zadaný v těle elementu a jeho výstup vložíme do stránky.
     3.5  		*
     3.6  		@jazyk programovací jazyk, např. bash, perl, php
     3.7 +		@výstup formát výstupu skriptu: text (výchozí) | xml (musí být validním fragmentem XML)
     3.8  		@src skript uložený v souboru místo v těle elementu
     3.9  	-->
    3.10  	<xsl:template match="m:skript">
    3.11 @@ -39,7 +40,28 @@
    3.12  			- nastavení z web.conf (zákaz nebo ignorace skriptů)
    3.13  			- podpora vkládání fragmentů XML, ne jen prostého textu
    3.14  		-->
    3.15 -		<xsl:value-of select="j:interpretuj(text(), @jazyk, document-uri(/), //s:stránka/s:nadpis/text(), //s:stránka/s:perex/text())"/>
    3.16 +		
    3.17 +		<xsl:variable name="výstupSkriptu" select="j:interpretuj(
    3.18 +															text(),
    3.19 +															@jazyk,
    3.20 +															@výstup,
    3.21 +															document-uri(/),
    3.22 +															//s:stránka/s:nadpis/text(),
    3.23 +															//s:stránka/s:perex/text()
    3.24 +														)"/>
    3.25 +		<xsl:choose>
    3.26 +			<xsl:when test="$výstupSkriptu">
    3.27 +				<xsl:choose>
    3.28 +					<xsl:when test="@výstup = 'xml'"><xsl:value-of select="$výstupSkriptu" disable-output-escaping="yes"/></xsl:when>
    3.29 +					<xsl:otherwise><xsl:value-of select="$výstupSkriptu"/></xsl:otherwise>
    3.30 +				</xsl:choose>
    3.31 +			</xsl:when>
    3.32 +			<xsl:otherwise>
    3.33 +				<xsl:message terminate="yes">Při interpretaci skriptu došlo k chybě.</xsl:message>
    3.34 +			</xsl:otherwise>
    3.35 +		</xsl:choose>
    3.36 +
    3.37 +		
    3.38  	</xsl:template>
    3.39  
    3.40  </xsl:stylesheet>