<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://commons.oreilly.com/wiki/skins/common/feed.css?97"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title>SVG Essentials/Generating SVG - Revision history</title>
		<link>http://commons.oreilly.com/wiki/index.php?title=SVG_Essentials/Generating_SVG&amp;action=history</link>
		<description>Revision history for this page on the wiki</description>
		<language>en</language>
		<generator>MediaWiki 1.11.0</generator>
		<lastBuildDate>Mon, 20 May 2013 15:26:19 GMT</lastBuildDate>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=SVG_Essentials/Generating_SVG&amp;diff=7378&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 13:40, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 13:40:50 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:SVG_Essentials/Generating_SVG</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=SVG_Essentials/Generating_SVG&amp;diff=6043&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 12:51, 7 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,027:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,027:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;The wind speed is expressed in meters per second. If two numbers are given, separated by a dash, the second number indicates the speed of gusts of wind. This information will be displayed in text form.&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;The wind speed is expressed in meters per second. If two numbers are given, separated by a dash, the second number indicates the speed of gusts of wind. This information will be displayed in text form.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/dl&amp;gt;;&amp;lt;tt&amp;gt;Vis&amp;lt;/tt&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/dl&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot;&gt;&amp;nbsp;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;;&amp;lt;tt&amp;gt;Vis&amp;lt;/tt&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;: Surface visibility in meters, or the value &amp;lt;tt&amp;gt;INF&amp;lt;/tt&amp;gt; for unlimited visibility. The final graphic will represent this by filling in a horizontal bar. Any visibility above 40 kilometers will be presumed to be unlimited.&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;: Surface visibility in meters, or the value &amp;lt;tt&amp;gt;INF&amp;lt;/tt&amp;gt; for unlimited visibility. The final graphic will represent this by filling in a horizontal bar. Any visibility above 40 kilometers will be presumed to be unlimited.&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,095:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,096:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &amp;lt;xsl:template match=&amp;quot;''element''&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &amp;lt;xsl:template match=&amp;quot;''element''&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;     &amp;amp;lt;&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;!&lt;/del&gt;-- output to produce --&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;     &amp;amp;lt;&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;&amp;amp;#33;&lt;/ins&gt;-- output to produce --&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &amp;lt;/xsl:template&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &amp;lt;/xsl:template&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;|-&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;|-&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,109:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,110:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &amp;lt;xsl:variable name=&amp;quot;''var''&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &amp;lt;xsl:variable name=&amp;quot;''var''&amp;quot;&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;     &amp;amp;lt;&lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;!&lt;/del&gt;-- instructions to produce ''item'''s value --&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;     &amp;amp;lt;&lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;&amp;amp;#33;&lt;/ins&gt;-- instructions to produce ''item'''s value --&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &amp;lt;/xsl:variable&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt; &amp;lt;/xsl:variable&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;|}&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;|}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</description>
			<pubDate>Fri, 07 Mar 2008 12:51:41 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:SVG_Essentials/Generating_SVG</comments>		</item>
		<item>
			<title>Evanlenz: 1 revision(s)</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=SVG_Essentials/Generating_SVG&amp;diff=3716&amp;oldid=prev</link>
			<description>&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 23:40, 6 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Thu, 06 Mar 2008 23:40:41 GMT</pubDate>			<dc:creator>Evanlenz</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:SVG_Essentials/Generating_SVG</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=SVG_Essentials/Generating_SVG&amp;diff=3715&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 23:33, 6 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Thu, 06 Mar 2008 23:33:32 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:SVG_Essentials/Generating_SVG</comments>		</item>
		<item>
			<title>Evanlenz: 1 revision(s)</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=SVG_Essentials/Generating_SVG&amp;diff=3257&amp;oldid=prev</link>
			<description>&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 22:52, 6 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Thu, 06 Mar 2008 22:52:49 GMT</pubDate>			<dc:creator>Evanlenz</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:SVG_Essentials/Generating_SVG</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=SVG_Essentials/Generating_SVG&amp;diff=3256&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 22:38, 6 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Thu, 06 Mar 2008 22:38:57 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:SVG_Essentials/Generating_SVG</comments>		</item>
		<item>
			<title>Evanlenz: 1 revision(s)</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=SVG_Essentials/Generating_SVG&amp;diff=2671&amp;oldid=prev</link>
			<description>&lt;p&gt;1 revision(s)&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 22:22, 6 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/table&gt;</description>
			<pubDate>Thu, 06 Mar 2008 22:22:10 GMT</pubDate>			<dc:creator>Evanlenz</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:SVG_Essentials/Generating_SVG</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=SVG_Essentials/Generating_SVG&amp;diff=2670&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;

			&lt;table style=&quot;background-color: white; color:black;&quot;&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;col class='diff-marker' /&gt;
			&lt;col class='diff-content' /&gt;
			&lt;tr&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;←Older revision&lt;/td&gt;
				&lt;td colspan='2' style=&quot;background-color: white; color:black;&quot;&gt;Revision as of 22:21, 6 March 2008&lt;/td&gt;
			&lt;/tr&gt;
		&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 230:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 230:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 12-1. Conversion from ARC/INFO ungenerate to SVG'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 12-1. Conversion from ARC/INFO ungenerate to SVG'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:SVG &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Essentials/I_12_tt272&lt;/del&gt;.png|Conversion from ARC/INFO ungenerate to SVG]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:SVG &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Essentials_I_12_tt272&lt;/ins&gt;.png|Conversion from ARC/INFO ungenerate to SVG]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 982:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 982:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 12-2. Sample converted from MathML to SVG'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 12-2. Sample converted from MathML to SVG'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:SVG &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Essentials/I_12_tt287&lt;/del&gt;.png|Sample converted from MathML to SVG]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:SVG &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Essentials_I_12_tt287&lt;/ins&gt;.png|Sample converted from MathML to SVG]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,008:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,008:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 12-3. Graphic weather template'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 12-3. Graphic weather template'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:SVG &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Essentials/I_12_tt289&lt;/del&gt;.png|Graphic weather template]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:SVG &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Essentials_I_12_tt289&lt;/ins&gt;.png|Graphic weather template]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,262:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,262:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 12-4. XSL-generated SVG file showing thermometer'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 12-4. XSL-generated SVG file showing thermometer'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:SVG &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Essentials/I_12_tt304&lt;/del&gt;.png|XSL-generated SVG file showing thermometer]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:SVG &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Essentials_I_12_tt304&lt;/ins&gt;.png|XSL-generated SVG file showing thermometer]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,403:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,403:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 12-5. XSLT-generated SVG file without time data'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 12-5. XSLT-generated SVG file without time data'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:SVG &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Essentials/I_12_tt308&lt;/del&gt;.png|XSLT-generated SVG file without time data]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:SVG &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Essentials_I_12_tt308&lt;/ins&gt;.png|XSLT-generated SVG file without time data]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,526:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 1,526:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 12-6. XSLT-generated SVG file showing complete data'''&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;'''Figure 12-6. XSLT-generated SVG file showing complete data'''&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;-&lt;/td&gt;&lt;td style=&quot;background: #ffa; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:SVG &lt;del style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Essentials/I_12_tt314&lt;/del&gt;.png|XSLT-generated SVG file showing complete data]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;background: #cfc; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;[[Image:SVG &lt;ins style=&quot;color: red; font-weight: bold; text-decoration: none;&quot;&gt;Essentials_I_12_tt314&lt;/ins&gt;.png|XSLT-generated SVG file showing complete data]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;div&gt;&amp;lt;/div&amp;gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background: #eee; color:black; font-size: smaller;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;</description>
			<pubDate>Thu, 06 Mar 2008 22:21:01 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:SVG_Essentials/Generating_SVG</comments>		</item>
		<item>
			<title>Docbook2Wiki: Initial conversion from Docbook</title>
			<link>http://commons.oreilly.com/wiki/index.php?title=SVG_Essentials/Generating_SVG&amp;diff=2426&amp;oldid=prev</link>
			<description>&lt;p&gt;Initial conversion from Docbook&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;{{SVG Essentials/TOC}}&lt;br /&gt;
The previous chapters have described the major features of SVG. All the examples have been relatively modest and have been written in an ordinary text editor. For graphics of any great complexity, though, few people will write the SVG from scratch. Let's face it: almost nobody does this by hand. Instead, graphic designers and programmers will use some sort of graphic tool that outputs SVG, or they will take existing raw data and convert it to SVG. If you're dealing with a graphic program's output that is already in SVG format, you can sit back and relax; all the heavy lifting has been done for you. If you ever take a look at the SVG that it generated, it may be hard to read. Some programs, for example, may not use groups (the &amp;lt;tt&amp;gt;&amp;lt;g&amp;gt;&amp;lt;/tt&amp;gt; element) efficiently or they may not optimize paths. When you use these programs, you are trading off the ease of generating SVG for the absolute control you have when you write the entire file by hand.&lt;br /&gt;
&lt;br /&gt;
If you're dealing with data that's already in XML format, you may just need to extract the pertinent data and plug it into an SVG framework. In such a case, you can use tools that implement Extensible Stylesheet Language Transformations (XSLT). If the data is in XML but needs a fair amount of processing, you may need to write a program in Java or some other language to do the conversion. Luckily, you can take advantage of freely available XML parsers to do the busy work for you.&lt;br /&gt;
&lt;br /&gt;
Finally, if you are dealing with data that isn't in XML format, you have some work ahead of you. If you have raw data in either ASCII or binary form you may need to write custom code to do the conversion.&lt;br /&gt;
&lt;br /&gt;
In this chapter, we'll start with a custom Perl program to convert geographical mapping data that's not in an XML format to an SVG file. Then we will use Java to convert a representation of a matrix in Mathematical Markup Language (MathML) format to SVG. The last example will use XSLT to convert an XML-formatted aeronautical weather report to SVG.&lt;br /&gt;
&lt;br /&gt;
== Using Perl to Convert Custom Data to SVG ==&lt;br /&gt;
&lt;br /&gt;
If anyone lives a life that revolves around graphics display, it's a mapmaker. Cartographers are finding XML markup in general and SVG in particular to be excellent vehicles for putting data into a portable format. At present, though, much of the data that is currently available is in custom or proprietary formats. One of these is the proprietary format developed by Earth Science Resources, Inc. for use by their ARC/INFO Geographic Information System. Data created in this system can be exported in an ASCII &amp;quot;ungenerate&amp;quot; form. Such a file contains a series of polygon descriptions, followed by a line with the word &amp;lt;tt&amp;gt;END&amp;lt;/tt&amp;gt; on it. Each polygon starts with a line that consists of an integer polygon identification number and the ''x''- and ''y''-coordinates of the polygon's centroid. This line is followed by the ''x''- and ''y''-coordinates of the polygon's vertices, one vertex per line. A line with the word &amp;lt;tt&amp;gt;END&amp;lt;/tt&amp;gt; on it marks the end of the polygon. Here is a sample file:&lt;br /&gt;
&lt;br /&gt;
          1      -0.122432044171565E+03       0.378635608621089E+02&lt;br /&gt;
       -0.122418712172884E+03       0.378527169597E+02&lt;br /&gt;
       -0.122434402770255E+03       0.378524342437443E+02&lt;br /&gt;
       -0.122443301934511E+03       0.378554484803880E+02&lt;br /&gt;
       -0.122446316168374E+03       0.378610463416856E+02&lt;br /&gt;
       -0.122438565286068E+03       0.378683666259093E+02&lt;br /&gt;
       -0.122418712172884E+03       0.378527169591107E+02&lt;br /&gt;
 END&lt;br /&gt;
          2      -122.36                      37.82&lt;br /&gt;
       -122.378                     37.826&lt;br /&gt;
       -122.377                     37.831&lt;br /&gt;
       -122.370                     37.832&lt;br /&gt;
       -122.378                     378.826&lt;br /&gt;
 END&lt;br /&gt;
 END&lt;br /&gt;
&lt;br /&gt;
Converting such a file to SVG is a simple task. The only twist is that ARC/INFO stores data in Cartesian coordinates, so we will have to flip the ''y''-coordinates upside-down. The program we'll write in Perl will run from the command line as follows:&lt;br /&gt;
&lt;br /&gt;
 perl mapSVG.pl ''input-file'' &lt;br /&gt;
             ''width'' &lt;br /&gt;
             ''decimals''&lt;br /&gt;
          &lt;br /&gt;
&lt;br /&gt;
Where the &amp;lt;tt&amp;gt;''width''&amp;lt;/tt&amp;gt; is the width of the resulting SVG graphic in pixels, and &amp;lt;tt&amp;gt;''decimals''&amp;lt;/tt&amp;gt; is an optional parameter giving the number of digits you wish to keep after the decimal point in coordinate values.&lt;br /&gt;
&lt;br /&gt;
The program will start with a utility subroutine that grabs one token at a time from the input file:&lt;br /&gt;
&lt;br /&gt;
 #!/usr/bin/perl&lt;br /&gt;
 &lt;br /&gt;
 #&lt;br /&gt;
 #   @line_buffer is a global&lt;br /&gt;
 #&lt;br /&gt;
 @line_buffer = ( );&lt;br /&gt;
 &lt;br /&gt;
 #&lt;br /&gt;
 #   Input file PFILE is opened in main&lt;br /&gt;
 #   part of program.&lt;br /&gt;
 #&lt;br /&gt;
 sub get_token&lt;br /&gt;
 {&lt;br /&gt;
     my ($data);&lt;br /&gt;
     if ((scalar @line_buffer) == 0) # out of data?&lt;br /&gt;
     {&lt;br /&gt;
         $data = &amp;lt;PFILE&amp;gt;;          # grab a line&lt;br /&gt;
         $data =~ s/^\s+//;          # get rid of leading... &lt;br /&gt;
         $data =~ s/\s+$//;          # ...and trailing whitespace&lt;br /&gt;
         @line_buffer = split /\s+/, $data;  # place tokens into a buffer&lt;br /&gt;
     }&lt;br /&gt;
     $data = shift @line_buffer;     # take one token out and return it&lt;br /&gt;
     return $data;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Here is the remainder of the program:&lt;br /&gt;
&lt;br /&gt;
 if (scalar @ARGV &amp;lt; 2)     '''[1]'''&lt;br /&gt;
 {&lt;br /&gt;
     print &amp;quot;Usage: $0 polygon_file width (decimals)\n&amp;quot;;&lt;br /&gt;
     print &amp;quot;polygon_file - file in ARC/INFO ungenerate format\n&amp;quot;;&lt;br /&gt;
     print &amp;quot;width - desired width of output SVG\n&amp;quot;;&lt;br /&gt;
     print &amp;quot;decimals - optional # of decimal places to keep\n&amp;quot;;&lt;br /&gt;
     print &amp;quot;Output SVG goes to standard output.\n&amp;quot;;&lt;br /&gt;
     exit 0;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 open PFILE, $ARGV[0] or die(&amp;quot;Cannot open polygon file $ARGV[1]&amp;quot;); &lt;br /&gt;
 &lt;br /&gt;
 $width = $ARGV[1];&lt;br /&gt;
 if ($width &amp;lt;= 0)&lt;br /&gt;
 {&lt;br /&gt;
     die(&amp;quot;Width must be greater than zero.&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 $n_decimals =  ((scalar @ARGV) == 3) ? $ARGV[2] : 0;&lt;br /&gt;
 &lt;br /&gt;
 #&lt;br /&gt;
 #   Set maxima and minima     '''[2]'''&lt;br /&gt;
 #&lt;br /&gt;
 $min_x = 1.0e100;&lt;br /&gt;
 $min_y = 1.0e100;&lt;br /&gt;
 $max_x = -1.0e100;&lt;br /&gt;
 $max_y = -1.0e100;&lt;br /&gt;
 &lt;br /&gt;
 undef @polygon_list; &lt;br /&gt;
 &lt;br /&gt;
 #&lt;br /&gt;
 #   a file consists of a series of polygon numbers followed&lt;br /&gt;
 #   by pairs of x-y coordinates. Each polygon is finished&lt;br /&gt;
 #   by an END token, and the file is marked by an END token&lt;br /&gt;
 #   instead of a polygon number&lt;br /&gt;
 #&lt;br /&gt;
 while (1)       '''[3]'''&lt;br /&gt;
 {&lt;br /&gt;
     $polygon_number = get_token();&lt;br /&gt;
     last if ($polygon_number =~ /END/);&lt;br /&gt;
     &lt;br /&gt;
     undef   @polygon;   # the storage area for this particular polygon&lt;br /&gt;
     &lt;br /&gt;
     while (1)&lt;br /&gt;
     {&lt;br /&gt;
         $x = get_token();&lt;br /&gt;
         last if ($x =~ /END/);&lt;br /&gt;
         $y = get_token();&lt;br /&gt;
         push @polygon, $x, $y;&lt;br /&gt;
 &lt;br /&gt;
         #&lt;br /&gt;
         # keep track of maximum and minimum coordinates&lt;br /&gt;
         #&lt;br /&gt;
         if ($x &amp;lt; $min_x) {$min_x = $x;}&lt;br /&gt;
         if ($x &amp;gt; $max_x) {$max_x = $x;}&lt;br /&gt;
         if ($y &amp;lt; $min_y) {$min_y = $y;}&lt;br /&gt;
         if ($y &amp;gt; $max_y) {$max_y = $y;}&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     push @polygon_list, [ @polygon ];     '''[4]'''&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 close PFILE;&lt;br /&gt;
 &lt;br /&gt;
 print STDERR &amp;quot;max x=$max_x  min x=$min_x width=&amp;quot;, $max_x-$min_x, &amp;quot;\n&amp;quot;;&lt;br /&gt;
 print STDERR &amp;quot;max y=$max_y  min y=$min_y height=&amp;quot;, $max_y-$min_y, &amp;quot;\n&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
 #&lt;br /&gt;
 #   Figure out the scaling factor to make the width equal to&lt;br /&gt;
 #   the one specified on the command line, then find the&lt;br /&gt;
 #   corresponding height.&lt;br /&gt;
 #&lt;br /&gt;
 $scale = $width / ($max_x - $min_x );&lt;br /&gt;
 $height = ($max_y - $min_y) * $scale;&lt;br /&gt;
 &lt;br /&gt;
 #&lt;br /&gt;
 #   Round it up so viewport and viewBox are integral&lt;br /&gt;
 #&lt;br /&gt;
 $height = int ($height + 0.5);&lt;br /&gt;
 &lt;br /&gt;
 #&lt;br /&gt;
 #   Insert extra pixels for padding&lt;br /&gt;
 #&lt;br /&gt;
 $pad_width = $width + 30;&lt;br /&gt;
 $pad_height = $height + 30;&lt;br /&gt;
 &lt;br /&gt;
 #&lt;br /&gt;
 #   Begin constructing the SVG file&lt;br /&gt;
 #&lt;br /&gt;
 print &amp;lt;&amp;lt;&amp;quot;SVG_HEADER&amp;quot;;        '''[5]'''&amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE svg PUBLIC &amp;quot;-//W3C//DTD SVG 1.0//EN&amp;quot;&lt;br /&gt;
    &amp;quot;http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;svg width=&amp;quot;$pad_width&amp;quot; height=&amp;quot;$pad_height&amp;quot;&lt;br /&gt;
    viewBox=&amp;quot;0 0 $pad_width $pad_height&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;title&amp;gt;Map constructed from $ARGV[0]&amp;lt;/title&amp;gt;&lt;br /&gt;
&amp;lt;g transform=&amp;quot;translate(15,15)&amp;quot; style=&amp;quot;fill: none; stroke: black;&amp;quot;&amp;gt;&lt;br /&gt;
SVG_HEADER&lt;br /&gt;
&lt;br /&gt;
$poly_num = 1;&lt;br /&gt;
foreach $poly (@polygon_list)&lt;br /&gt;
{&lt;br /&gt;
    $n = 0;&lt;br /&gt;
    print qq%&amp;lt;polyline id=&amp;quot;poly$poly_num&amp;quot; points=&amp;quot;\n\t%;&lt;br /&gt;
    &lt;br /&gt;
    #&lt;br /&gt;
    #   get rid of first coordinate&lt;br /&gt;
    #&lt;br /&gt;
    shift @$poly;        &amp;lt;/nowiki&amp;gt;'''[6]'''&lt;br /&gt;
     shift @$poly;&lt;br /&gt;
     &lt;br /&gt;
     foreach $coord (@$poly)&lt;br /&gt;
     {&lt;br /&gt;
         if ($n % 2 == 0)    # x-coordinate&lt;br /&gt;
         {&lt;br /&gt;
             $coord = ($coord - $min_x) * $scale;&lt;br /&gt;
         }&lt;br /&gt;
         else                # flip y-coordinate&lt;br /&gt;
         {&lt;br /&gt;
             $coord = ($max_y - $coord) * $scale;     '''[7]'''&lt;br /&gt;
         }&lt;br /&gt;
         if ($n_decimals != 0)&lt;br /&gt;
         {&lt;br /&gt;
             $coord = int($coord * (10**$n_decimals))/(10**$n_decimals);&lt;br /&gt;
         }&lt;br /&gt;
             &lt;br /&gt;
         print $coord, &amp;quot; &amp;quot;;&lt;br /&gt;
         &lt;br /&gt;
         #&lt;br /&gt;
         #   to avoid excessively long text lines, place only&lt;br /&gt;
         #   eight coordinates on a line&lt;br /&gt;
         #&lt;br /&gt;
         $n = ($n+1) % 8;&lt;br /&gt;
         print &amp;quot;\n\t&amp;quot; if ($n == 0);&lt;br /&gt;
     }&lt;br /&gt;
     print qq%&amp;quot; /&amp;gt;\n%;    # close off the &amp;lt;path&amp;gt; element&lt;br /&gt;
     $poly_num++;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 #&lt;br /&gt;
 #   Close off open tags to end the file.&lt;br /&gt;
 #&lt;br /&gt;
 print &amp;quot;&amp;lt;/g&amp;gt;\n&amp;lt;/svg&amp;gt;\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[1]'''&amp;lt;/tt&amp;gt; Obligatory argument retrieval and error checking.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[2]'''&amp;lt;/tt&amp;gt; Set up variables. The initial maxima and minima are huge enough to handle the coordinates of a map of anything smaller than a minor galaxy. The variable &amp;lt;tt&amp;gt;@polygon_list&amp;lt;/tt&amp;gt; will be a list of the polygons, each of which will itself be represented as a list.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[3]'''&amp;lt;/tt&amp;gt; The outer loop reads polygon ID numbers, and the inner loop stores the coordinates in the &amp;lt;tt&amp;gt;@polygon&amp;lt;/tt&amp;gt; list.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[4]'''&amp;lt;/tt&amp;gt; The square brackets are very important. They create an anonymous list to contain the coordinates in &amp;lt;tt&amp;gt;@polygon&amp;lt;/tt&amp;gt;, and that list is pushed onto &amp;lt;tt&amp;gt;@polygon_list&amp;lt;/tt&amp;gt;. Without the brackets, it would simply append all the coordinates, ungrouped, to the end of &amp;lt;tt&amp;gt;@polygon_list&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[5]'''&amp;lt;/tt&amp;gt; This line prints, verbatim, all the text up to (but not including) a line that begins with the literal &amp;lt;tt&amp;gt;SVG_HEADER&amp;lt;/tt&amp;gt;. Because &amp;lt;tt&amp;gt;SVG_HEADER&amp;lt;/tt&amp;gt; is enclosed in double quotes, we can use variable interpolation in the verbatim text.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[6]'''&amp;lt;/tt&amp;gt; The &amp;lt;tt&amp;gt;$poly&amp;lt;/tt&amp;gt; loop variable, set in the outer &amp;lt;tt&amp;gt;foreach&amp;lt;/tt&amp;gt;, is an entire list, which is why it must be preceded by an &amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt; to be accessed properly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[7]'''&amp;lt;/tt&amp;gt; We had to keep track of the maximum and minimum ''x''-coordinate to calculate the width scaling factor properly; we kept track of the maximum ''y''-coordinate so we could change from Cartesian coordinates to SVG style coordinates.&lt;br /&gt;
&lt;br /&gt;
Running this program with the data for the state of Michigan with an output width of 250 pixels and a decimal accuracy of three digits produces [[SVG Essentials/Generating SVG#svgess-CHP-12-FIG-1|Figure 12-1]]. Michigan was chosen because it requires several polygons to draw, and its outline is more visually interesting than that of, say, Colorado. The data came from the U.S. Census Bureau Cartographic Boundary Files Web Site at ''http://www.census.gov/geo/www/cob/''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;svgess-CHP-12-FIG-1&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 12-1. Conversion from ARC/INFO ungenerate to SVG'''&lt;br /&gt;
&lt;br /&gt;
[[Image:SVG Essentials/I_12_tt272.png|Conversion from ARC/INFO ungenerate to SVG]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Using Java to Convert XML to SVG ==&lt;br /&gt;
&lt;br /&gt;
While preparing to write [[SVG Essentials/Matrix Algebra|Appendix D]] I had to decide how to produce the matrix equations. At that time, I didn't have a definitive answer from the production staff at O'Reilly on the format in which to submit the data. I decided on an ad-hoc subset of MathML,&amp;lt;ref&amp;gt;You can find out about the complete MathML specification at ''http://www.w3.org/Math/''.&amp;lt;/ref&amp;gt; an XML application for describing the presentation and content of mathematical information. This choice gave me the maximum flexibility; I would not be tied down to a proprietary equation editor, conversion to the TeX typesetting language (a common format among publishers) could be done with a trivial XSLT file, and using MathML would give me an example for this chapter.&lt;br /&gt;
&lt;br /&gt;
This example is atypical in that the majority of its output will be &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;&amp;lt;/tt&amp;gt; elements. It is further atypical in that it is not a general tool, nor is it intended to be. It is, however, typical in that it shows how to parse an input XML document, construct a new XML document in memory and output through a serializer.&lt;br /&gt;
&lt;br /&gt;
The subset of MathML in this example is as follows; all the elements are container elements:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! MathML element !! Contains&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;math&amp;gt;&amp;lt;/tt&amp;gt; || root element of a MathML document&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;mrow&amp;gt;&amp;lt;/tt&amp;gt; || a formula&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;mtable&amp;gt;&amp;lt;/tt&amp;gt; || a matrix (table)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;mtr&amp;gt;&amp;lt;/tt&amp;gt; || a matrix row&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;mtd&amp;gt;&amp;lt;/tt&amp;gt; || a data cell within a row&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;mn&amp;gt;&amp;lt;/tt&amp;gt; || a numeric value&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;mi&amp;gt;&amp;lt;/tt&amp;gt; || an identifier (variable)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;mo&amp;gt;&amp;lt;/tt&amp;gt; || a mathematical operator&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;msub&amp;gt;&amp;lt;/tt&amp;gt; || subscripted content&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The general outline of the program is as follows:&lt;br /&gt;
&lt;br /&gt;
* Parse the input document to create a Document Object Model in memory.&lt;br /&gt;
* Find the matrix with the maximum number of rows; this will determine the height of the output SVG document.&lt;br /&gt;
* Go through the formula and output matrices and operators as specified. These become elements in an SVG Document that is also built in memory.&lt;br /&gt;
* If the operator is a parenthesis, make it as large as the largest matrix in the entire formula. This is an assumption that saves a lot of programming, and works well for most of the formulas that the appendix needs.&lt;br /&gt;
* Each matrix is output within an SVG group (&amp;lt;tt&amp;gt;&amp;lt;g&amp;gt;&amp;lt;/tt&amp;gt;) element. Again, for ease of programming, the matrix is drawn with its upper left corner at (0,0) and will be moved to its proper place with a &amp;lt;tt&amp;gt;translate&amp;lt;/tt&amp;gt; transformation. The square brackets that enclose the matrix's values will be drawn with a &amp;lt;tt&amp;gt;&amp;lt;path&amp;gt;&amp;lt;/tt&amp;gt; element.&lt;br /&gt;
* Once the SVG document has been built, use the parser's &amp;lt;tt&amp;gt;serialize&amp;lt;/tt&amp;gt; method to create an output file.&lt;br /&gt;
&lt;br /&gt;
This program uses the Xerces XML parser from the Apache Software Foundation; you may download it and read its documentation at ''http://xml.apache.org''. The program starts with a large number of imports from the standard Java libraries and the Xerces parser.&lt;br /&gt;
&lt;br /&gt;
 import java.awt.Dimension;&lt;br /&gt;
 import java.awt.Font;&lt;br /&gt;
 import java.awt.FontMetrics;&lt;br /&gt;
 import java.awt.Graphics;&lt;br /&gt;
 import java.awt.Image;&lt;br /&gt;
 import java.awt.image.BufferedImage;&lt;br /&gt;
 &lt;br /&gt;
 import java.io.OutputStreamWriter;&lt;br /&gt;
 import java.io.PrintWriter;&lt;br /&gt;
 import java.io.UnsupportedEncodingException;&lt;br /&gt;
 import java.io.IOException;&lt;br /&gt;
 &lt;br /&gt;
 import org.w3c.dom.Attr;&lt;br /&gt;
 import org.w3c.dom.Document;&lt;br /&gt;
 import org.w3c.dom.DocumentFragment;&lt;br /&gt;
 import org.w3c.dom.DocumentType;&lt;br /&gt;
 import org.w3c.dom.DOMImplementation;&lt;br /&gt;
 import org.w3c.dom.Element;&lt;br /&gt;
 import org.w3c.dom.NamedNodeMap;&lt;br /&gt;
 import org.w3c.dom.Node;&lt;br /&gt;
 import org.w3c.dom.NodeList;&lt;br /&gt;
 import org.w3c.dom.Text;&lt;br /&gt;
 &lt;br /&gt;
 import org.apache.xerces.parsers.DOMParser;&lt;br /&gt;
 import org.apache.xml.serialize.XMLSerializer;&lt;br /&gt;
 import org.apache.xml.serialize.OutputFormat;&lt;br /&gt;
&lt;br /&gt;
The program itself starts with constants that establish the default line height, font height for normal characters, font height for subscripted characters, extra height at the top and bottom of the image, and extra horizontal space between items:&lt;br /&gt;
&lt;br /&gt;
 public class MLtoSVG {&lt;br /&gt;
 &lt;br /&gt;
     //&lt;br /&gt;
     // Constants&lt;br /&gt;
     //&lt;br /&gt;
 &lt;br /&gt;
     private static final int LINE_HEIGHT = 24;&lt;br /&gt;
     private static final int FONT_HEIGHT = 14;&lt;br /&gt;
     private static final int SUBSCRIPT_HEIGHT = 12;&lt;br /&gt;
     private static final int EXTRA_HEIGHT = 10;&lt;br /&gt;
     private static final int X_SPACING = 2;&lt;br /&gt;
&lt;br /&gt;
Although global variables are considered a mortal sin, I was too lazy to pass parameters ad infinitum, so the input document, output document, and root element of the output document became properties of the class:&lt;br /&gt;
&lt;br /&gt;
     /** The &amp;quot;before&amp;quot; document */&lt;br /&gt;
     protected Document mlDocument;&lt;br /&gt;
     &lt;br /&gt;
     /** The &amp;quot;after&amp;quot; document */&lt;br /&gt;
     protected Document svgDocument;&lt;br /&gt;
 &lt;br /&gt;
     /** Permanent pointer to SVG document's root element */&lt;br /&gt;
     protected Element svgRoot;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;main&amp;lt;/tt&amp;gt; function is entirely straightforward:&lt;br /&gt;
&lt;br /&gt;
     public static void main(String argv[]) {&lt;br /&gt;
 &lt;br /&gt;
         // is there anything to do?&lt;br /&gt;
         if ( argv.length == 0 ) {&lt;br /&gt;
             System.err.println(&amp;quot;usage: java MLtoSVG filename&amp;quot;);&lt;br /&gt;
             System.exit(1);&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         // vars&lt;br /&gt;
         MLtoSVG converter = null;&lt;br /&gt;
 &lt;br /&gt;
         converter = new MLtoSVG();  &lt;br /&gt;
         converter.readDocument( argv[0] );&lt;br /&gt;
         converter.processDocument( );&lt;br /&gt;
         converter.printDocument( );&lt;br /&gt;
 &lt;br /&gt;
     } // main(String[])&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;readDocument&amp;lt;/tt&amp;gt; method will set up a DOM parser and read the input file. However, the standard parser does not come with any error handling. Thus, there is the following implementation of the &amp;lt;tt&amp;gt;org.xml.saxErrorHandler&amp;lt;/tt&amp;gt; abstract class. Rather than reinvent the wheel, I stole the code outright from a sample program that came with the Xerces parser, and produced the &amp;lt;tt&amp;gt;ParserErrorHandler&amp;lt;/tt&amp;gt; class.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
 * ParserErrorHandler code taken from DOMWriter.java sample code.&lt;br /&gt;
 * Copyright (c) 1999 The Apache Software Foundation.  All rights &lt;br /&gt;
 * reserved. For licensing details, see http://www.apache.org/&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
import org.xml.sax.ErrorHandler;&lt;br /&gt;
import org.xml.sax.SAXException;&lt;br /&gt;
import org.xml.sax.SAXParseException;&lt;br /&gt;
import org.xml.sax.SAXNotRecognizedException;&lt;br /&gt;
import org.xml.sax.SAXNotSupportedException;&lt;br /&gt;
&lt;br /&gt;
public class ParserErrorHandler&lt;br /&gt;
    implements ErrorHandler {&lt;br /&gt;
&lt;br /&gt;
    //&lt;br /&gt;
    // ErrorHandler methods&lt;br /&gt;
    //&lt;br /&gt;
&lt;br /&gt;
    /** Warning. */&lt;br /&gt;
    public void warning(SAXParseException ex) {&lt;br /&gt;
        System.err.println(&amp;quot;[Warning] &amp;quot;+&lt;br /&gt;
                           getLocationString(ex)+&amp;quot;: &amp;quot;+&lt;br /&gt;
                           ex.getMessage());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /** Error. */&lt;br /&gt;
    public void error(SAXParseException ex) {&lt;br /&gt;
        System.err.println(&amp;quot;[Error] &amp;quot;+&lt;br /&gt;
                           getLocationString(ex)+&amp;quot;: &amp;quot;+&lt;br /&gt;
                           ex.getMessage());&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /** Fatal error. */&lt;br /&gt;
    public void fatalError(SAXParseException ex) throws SAXException {&lt;br /&gt;
        System.err.println(&amp;quot;[Fatal Error] &amp;quot;+&lt;br /&gt;
                           getLocationString(ex)+&amp;quot;: &amp;quot;+&lt;br /&gt;
                           ex.getMessage());&lt;br /&gt;
        throw ex;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    //&lt;br /&gt;
    // Private methods&lt;br /&gt;
    //&lt;br /&gt;
&lt;br /&gt;
    /** Returns a string of the location. */&lt;br /&gt;
    private String getLocationString(SAXParseException ex) {&lt;br /&gt;
        StringBuffer str = new StringBuffer();&lt;br /&gt;
&lt;br /&gt;
        String systemId = ex.getSystemId();&lt;br /&gt;
        if (systemId != null) {&lt;br /&gt;
            int index = systemId.lastIndexOf('/');&lt;br /&gt;
            if (index != -1) &lt;br /&gt;
                systemId = systemId.substring(index + 1);&lt;br /&gt;
            str.append(systemId);&lt;br /&gt;
        }&lt;br /&gt;
        str.append(':');&lt;br /&gt;
        str.append(ex.getLineNumber());&lt;br /&gt;
        str.append(':');&lt;br /&gt;
        str.append(ex.getColumnNumber());&lt;br /&gt;
&lt;br /&gt;
        return str.toString();&lt;br /&gt;
&lt;br /&gt;
    } // getLocationString(SAXParseException):String&lt;br /&gt;
&lt;br /&gt;
}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This program uses the Xerces parser explicitly; some programs will put the parser name in a string and then instantiate it dynamically:&lt;br /&gt;
&lt;br /&gt;
 String parserName = &amp;quot;org.apache.xerces.parsers.DOMParser&amp;quot;;&lt;br /&gt;
 DOMParser parser =&lt;br /&gt;
  (DOMParser)Class.forName(parserName).newInstance();&lt;br /&gt;
&lt;br /&gt;
I didn't see the need for this, so I constructed the parser directly, set the error handler, parsed the file whose name is the input to the &amp;lt;tt&amp;gt;readDocument&amp;lt;/tt&amp;gt; function, and saved the document that is returned. Failure at any point is met with a stack trace.&lt;br /&gt;
&lt;br /&gt;
     /** Read the input document and construct a document tree. */&lt;br /&gt;
     public void readDocument( String uri ) {&lt;br /&gt;
         ParserErrorHandler errHandler = new ParserErrorHandler();&lt;br /&gt;
         mlDocument = null;&lt;br /&gt;
         try {&lt;br /&gt;
             DOMParser parser = new org.apache.xerces.parsers.DOMParser();&lt;br /&gt;
             parser.setErrorHandler( errHandler );&lt;br /&gt;
             parser.parse( uri );&lt;br /&gt;
             mlDocument = parser.getDocument();&lt;br /&gt;
         } catch ( Exception e ) {&lt;br /&gt;
             e.printStackTrace(System.err);&lt;br /&gt;
         }&lt;br /&gt;
     } // readDocument(String)&lt;br /&gt;
&lt;br /&gt;
Similarly, once the SVG document has been built, sending it to a file — in this case the standard output — is no great challenge. Most of this function performs error-checking.&lt;br /&gt;
&lt;br /&gt;
     public void printDocument( ) {&lt;br /&gt;
         &lt;br /&gt;
         if (svgDocument == null)&lt;br /&gt;
         {&lt;br /&gt;
             return;&lt;br /&gt;
         }&lt;br /&gt;
         PrintWriter out = null;&lt;br /&gt;
         try{&lt;br /&gt;
             out =&lt;br /&gt;
             new PrintWriter(new OutputStreamWriter(System.out, &amp;quot;UTF8&amp;quot;));    '''[1]'''&lt;br /&gt;
         }&lt;br /&gt;
         catch (Exception e)&lt;br /&gt;
         {&lt;br /&gt;
             System.out.println(&amp;quot;Error creating output stream&amp;quot;);&lt;br /&gt;
             System.out.println(e.getMessage());&lt;br /&gt;
             System.exit(1);&lt;br /&gt;
         }&lt;br /&gt;
         OutputFormat oFormat = new OutputFormat( &amp;quot;xml&amp;quot;, &amp;quot;UTF8&amp;quot;, true );    '''[2]'''&lt;br /&gt;
         XMLSerializer serial = new XMLSerializer( out, oFormat );    '''[3]'''&lt;br /&gt;
         try&lt;br /&gt;
         {&lt;br /&gt;
             serial.serialize( svgDocument );&lt;br /&gt;
         }&lt;br /&gt;
         catch (java.io.IOException e)&lt;br /&gt;
         {&lt;br /&gt;
             System.out.println(e.getMessage());&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[1]'''&amp;lt;/tt&amp;gt; First, construct an output stream with your favorite encoding method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[2]'''&amp;lt;/tt&amp;gt; A serializer requires an output format. This constructor's three parameters are the output method (which is normally one of &amp;lt;tt&amp;gt;&amp;quot;xml&amp;quot;&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;quot;html&amp;quot;&amp;lt;/tt&amp;gt;, or &amp;lt;tt&amp;gt;&amp;quot;text&amp;quot;&amp;lt;/tt&amp;gt;); the character encoding, which should be &amp;lt;tt&amp;gt;&amp;quot;UTF8&amp;quot;&amp;lt;/tt&amp;gt; to keep your international clients happy; and a Boolean that tells whether the output should be indented or not.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[3]'''&amp;lt;/tt&amp;gt; The &amp;lt;tt&amp;gt;OutputFormat&amp;lt;/tt&amp;gt; is used when creating the serializer.&lt;br /&gt;
&lt;br /&gt;
This leaves the majority of the work to the &amp;lt;tt&amp;gt;processDocument&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&lt;br /&gt;
     public void processDocument( )&lt;br /&gt;
     {&lt;br /&gt;
         svgDocument = null;&lt;br /&gt;
         &lt;br /&gt;
         /* anything to do? */&lt;br /&gt;
         if (mlDocument == null)&lt;br /&gt;
         {&lt;br /&gt;
             return;&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         /* Create the output document */&lt;br /&gt;
         DOMImplementation dImplement = mlDocument.getImplementation();     '''[1]'''&lt;br /&gt;
         DocumentType dType = dImplement.createDocumentType(     '''[2]'''&amp;lt;nowiki&amp;gt;&lt;br /&gt;
            &amp;quot;svg&amp;quot;,&lt;br /&gt;
            &amp;quot;-//W3C//DTD SVG 1.0//EN&amp;quot;,&lt;br /&gt;
            &amp;quot;http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        svgDocument = dImplement.createDocument( null, &amp;quot;svg&amp;quot;, dType);&lt;br /&gt;
        svgRoot = (Element) svgDocument.getDocumentElement();&lt;br /&gt;
&lt;br /&gt;
        Element     mrowElement;    // store &amp;lt;mrow&amp;gt; element for ease &lt;br /&gt;
                                       of access&lt;br /&gt;
        NodeList    matrices;       // list of all &amp;lt;mtable&amp;gt; elements&lt;br /&gt;
        NodeList    rows;           // list of all &amp;lt;mtr&amp;gt; elements&lt;br /&gt;
        NodeList    nodes;          // immediate children of &amp;lt;mrow&amp;gt;&lt;br /&gt;
        int         i;              // ubiquitous counter&lt;br /&gt;
        &lt;br /&gt;
        /* current x  position while creating matrices */&lt;br /&gt;
        int currX = 0;&lt;br /&gt;
&lt;br /&gt;
        /* maximum number of rows in any one matrix */&lt;br /&gt;
        int maxRows = 0;&lt;br /&gt;
        int totalHeight;&lt;br /&gt;
&lt;br /&gt;
            &amp;lt;/nowiki&amp;gt;'''[3]'''&lt;br /&gt;
 &lt;br /&gt;
         /* Find the first &amp;lt;mrow&amp;gt; node */&lt;br /&gt;
         nodes = mlDocument.getElementsByTagName(&amp;quot;mrow&amp;quot;);     '''[4]'''&lt;br /&gt;
         mrowElement = (Element) nodes.item(0);&lt;br /&gt;
         &lt;br /&gt;
         /* Find the maximum number of rows among all the matrices */&lt;br /&gt;
         matrices = mrowElement.getElementsByTagName(&amp;quot;mtable&amp;quot;);      '''[5]'''    &lt;br /&gt;
         for (i = 0; i &amp;lt; matrices.getLength(); i++)&lt;br /&gt;
         {&lt;br /&gt;
             rows = ((Element) matrices.item(i)).getElementsByTagName(&amp;quot;mtr&amp;quot;);&lt;br /&gt;
             if (rows.getLength() &amp;gt; maxRows)&lt;br /&gt;
             {&lt;br /&gt;
                 maxRows = rows.getLength();&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         /* Calculate total height */ &lt;br /&gt;
         totalHeight = maxRows * LINE_HEIGHT + EXTRA_HEIGHT;&lt;br /&gt;
         &lt;br /&gt;
         /* Now create the SVG for the matrices and operators */&lt;br /&gt;
         nodes = mrowElement.getChildNodes();     '''[6]'''&lt;br /&gt;
         for (i=0; i &amp;lt; nodes.getLength(); i++)     '''[7]'''&lt;br /&gt;
         {&lt;br /&gt;
             if (nodes.item(i).getNodeName().equals(&amp;quot;mtable&amp;quot;))&lt;br /&gt;
             {&lt;br /&gt;
                 currX += generateMatrix( nodes.item(i), currX, totalHeight );&lt;br /&gt;
             }&lt;br /&gt;
             else if (nodes.item(i).getNodeName().equals(&amp;quot;mo&amp;quot;))&lt;br /&gt;
             {&lt;br /&gt;
                 currX += generateOperator( nodes.item(i), currX, totalHeight );&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
         &lt;br /&gt;
         currX += 2 * X_SPACING; // put some padding at the right&lt;br /&gt;
 &lt;br /&gt;
         svgRoot.setAttribute(&amp;quot;width&amp;quot;, Integer.toString( currX ));     '''[8]'''&lt;br /&gt;
         svgRoot.setAttribute(&amp;quot;height&amp;quot;, Integer.toString( totalHeight) );&lt;br /&gt;
         svgRoot.setAttribute(&amp;quot;viewBox&amp;quot;,&lt;br /&gt;
             &amp;quot;0 0 &amp;quot; + currX + &amp;quot; &amp;quot; + totalHeight);&lt;br /&gt;
 &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[1]'''&amp;lt;/tt&amp;gt; The &amp;lt;tt&amp;gt;processDocument&amp;lt;/tt&amp;gt; function starts by creating the SVG document. Since every parser implementation has its own way of storing the objects, you must ask the &amp;lt;tt&amp;gt;DOMImplementation&amp;lt;/tt&amp;gt; class to give you the details.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[2]'''&amp;lt;/tt&amp;gt; The implementation is asked to create a document. The &amp;lt;tt&amp;gt;createDocumentType&amp;lt;/tt&amp;gt; function's parameters will be used when producing the &amp;lt;tt&amp;gt;&amp;lt;!DOCTYPE&amp;gt;&amp;lt;/tt&amp;gt; in the output; you provide a root element name, and a public and system identifier for the DTD. The &amp;lt;tt&amp;gt;createDocument&amp;lt;/tt&amp;gt; function's parameters are the namespace URI (in this case, none is needed), the name of the top-level document element, and the document type. The root element is retrieved for future reference by calling &amp;lt;tt&amp;gt;getDocumentElement&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[3]'''&amp;lt;/tt&amp;gt; Now it's time to extract information from the MathML document. Among the methods you use to access information in the Document Object Model are the following:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;NodeList getElementsByTag (DOMString ''tagName'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calling &amp;lt;tt&amp;gt;''element''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.getElementsByTag(&amp;quot;&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;''name''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;&amp;quot;)&amp;lt;/tt&amp;gt; returns a list of all the descendant nodes of the specified element that have the specified tag name. These are not just the child nodes; they are descendants at any depth, which is very advantageous in this program.&lt;br /&gt;
;&amp;lt;tt&amp;gt;Node item (int ''n'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calling &amp;lt;tt&amp;gt;''nodeList''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.item(&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;)&amp;lt;/tt&amp;gt; retrieves node number &amp;lt;tt&amp;gt;''n''&amp;lt;/tt&amp;gt; from the given node list.&lt;br /&gt;
;&amp;lt;tt&amp;gt;NodeList getChildNodes ( )&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calling &amp;lt;tt&amp;gt;''node''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.getChildNodes( )&amp;lt;/tt&amp;gt; retrieves a list of all the immediate children of the given node.&lt;br /&gt;
;&amp;lt;tt&amp;gt;short getNodeType ( )&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calling &amp;lt;tt&amp;gt;''node''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.getNodeType( )&amp;lt;/tt&amp;gt; returns an integer that tells which kind of node this is (element, text, CDATA, entity, etc.).&lt;br /&gt;
;&amp;lt;tt&amp;gt;String getNodeName ( )&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calling &amp;lt;tt&amp;gt;''node''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.getNodeName( )&amp;lt;/tt&amp;gt; returns a string based on the node type. If the node is an element, the tag name is returned; if it's a text node, the string &amp;lt;tt&amp;gt;&amp;quot;#text&amp;quot;&amp;lt;/tt&amp;gt; is returned.&lt;br /&gt;
;&amp;lt;tt&amp;gt;Node getNextSibling ( )&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calling &amp;lt;tt&amp;gt;''node''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.getNextSibling( )&amp;lt;/tt&amp;gt; retrieves the given node's next sibling, or null if this is the last of the siblings. Sibling nodes are nodes that are all descendants of a common parent, listed in the order in which they appear in the document.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[4]'''&amp;lt;/tt&amp;gt; The first &amp;lt;tt&amp;gt;&amp;lt;mrow&amp;gt;&amp;lt;/tt&amp;gt; element encloses the entire matrix expression. The easiest way to find it is to grab all the tags and store the address of the first one. The code casts the results of the &amp;lt;tt&amp;gt;item&amp;lt;/tt&amp;gt; call to &amp;lt;tt&amp;gt;Element&amp;lt;/tt&amp;gt;. This is safe, since the node lists were constructed by calls that return only &amp;lt;tt&amp;gt;Element&amp;lt;/tt&amp;gt;s.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[5]'''&amp;lt;/tt&amp;gt; In order to center all the matrices vertically, we need to find the matrix with the largest number of rows. Presuming that there are no nested matrices, this is done by walking through each &amp;lt;tt&amp;gt;&amp;lt;mtable&amp;gt;&amp;lt;/tt&amp;gt; element, extracting a list of all its &amp;lt;tt&amp;gt;&amp;lt;mtr&amp;gt;&amp;lt;/tt&amp;gt; descendants, and checking that list's length. This maximum number of rows is used to calculate the &amp;lt;tt&amp;gt;''totalHeight''&amp;lt;/tt&amp;gt; of the resulting graphic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[6]'''&amp;lt;/tt&amp;gt; We then call the &amp;lt;tt&amp;gt;getChildNodes&amp;lt;/tt&amp;gt; function to retrieve a &amp;lt;tt&amp;gt;NodeList&amp;lt;/tt&amp;gt; of all the immediate children of the &amp;lt;tt&amp;gt;&amp;lt;mrow&amp;gt;&amp;lt;/tt&amp;gt; element.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[7]'''&amp;lt;/tt&amp;gt; The program iterates through these children, generating a matrix when encountering an &amp;lt;tt&amp;gt;&amp;lt;mtable&amp;gt;&amp;lt;/tt&amp;gt;, or an operator symbol when encountering an &amp;lt;tt&amp;gt;&amp;lt;mo&amp;gt;&amp;lt;/tt&amp;gt; element. Everything else is ignored, which conveniently skips over the &amp;quot;hidden&amp;quot; text nodes that come from carriage returns between lines in the source file.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;generateMatrix&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;generateOperator&amp;lt;/tt&amp;gt; create the output SVG. Once they are done, the &amp;lt;tt&amp;gt;''currX''&amp;lt;/tt&amp;gt; variable will contain the total width of the graphic.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[8]'''&amp;lt;/tt&amp;gt; The &amp;lt;tt&amp;gt;processDocument&amp;lt;/tt&amp;gt; function wraps up by using the &amp;lt;tt&amp;gt;setAttribute&amp;lt;/tt&amp;gt; function to add the &amp;lt;tt&amp;gt;width&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;height&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;viewBox&amp;lt;/tt&amp;gt; attributes to the &amp;lt;tt&amp;gt;''svgRoot''&amp;lt;/tt&amp;gt; variable.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;setAttribute&amp;lt;/tt&amp;gt; is just one of the functions used to populate the new document. Other functions include:&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;Element createElement (DOMString ''elementName'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calling &amp;lt;tt&amp;gt;''document''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.createElement(&amp;quot;&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;''name''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;&amp;quot;)&amp;lt;/tt&amp;gt; returns an element which belongs to the specified document, but is ''not'' part of the document hierarchy (it hasn't been placed in the &amp;quot;tree&amp;quot; yet).&lt;br /&gt;
;&amp;lt;tt&amp;gt;Text createTextNode (String ''data'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calling &amp;lt;tt&amp;gt;''document''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.createTextNode(&amp;quot;&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;''value''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;&amp;quot;)&amp;lt;/tt&amp;gt; returns a text node whose content is the given value. Again, this node belongs to the specified document, but it is ''not'' part of the document hierarchy (it hasn't been placed in the &amp;quot;tree&amp;quot; yet).&lt;br /&gt;
;&amp;lt;tt&amp;gt;void setAttribute (DOMString ''data'', DOMString ''value'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calling &amp;lt;tt&amp;gt;''element''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.setAttribute(&amp;quot;&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;''attr''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;&amp;quot;,&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;&amp;quot;&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;''value''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;&amp;quot;)&amp;lt;/tt&amp;gt; sets the particular attribute of the specified element to the given value. If the attribute already exists, any previous value it had is replaced with the new value.&lt;br /&gt;
;&amp;lt;tt&amp;gt;Node appendChild (Node ''newchild'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calling &amp;lt;tt&amp;gt;''parentNode''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.appendChild(&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;''newchild''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;)&amp;lt;/tt&amp;gt; appends the given new child node to the child nodes of the parent node. It returns a reference to the new child node. This puts the node into the document hierarchy.&lt;br /&gt;
;&amp;lt;tt&amp;gt;Node insertBefore (Node ''newchild'', Node ''refchild'')&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Calling &amp;lt;tt&amp;gt;''parentNode''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;.insertBefore(&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;''newChild''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;,&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;''referenceChild''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;)&amp;lt;/tt&amp;gt; in- serts the new child node into the list of child nodes of the parent node just before the child node specified in the second parameter. The function returns a reference to the new child node. (The sample program doesn't use this function, but it's included here because it's generally useful.)&lt;br /&gt;
&lt;br /&gt;
Let us now turn our attention to the &amp;lt;tt&amp;gt;generateMatrix&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&lt;br /&gt;
 public int generateMatrix( Node mtableNode, int currX, int totalHeight )&lt;br /&gt;
 {&lt;br /&gt;
     double      y;                 '''[1]'''&lt;br /&gt;
     int         x = 0;&lt;br /&gt;
     NodeList    rowList;        // list of all &amp;lt;mtr&amp;gt; elements&lt;br /&gt;
     NodeList    cellList;       // list of all &amp;lt;mtd&amp;gt; elements&lt;br /&gt;
     Element     newElement;     // a catch-all &amp;quot;new element&amp;quot;&lt;br /&gt;
     Element     gElement;       // a created &amp;lt;g&amp;gt; element&lt;br /&gt;
     Element     startColumn;    // marks beginning of a column&lt;br /&gt;
     Element     textElement;    // a created &amp;lt;text&amp;gt; element&lt;br /&gt;
         &lt;br /&gt;
     int         nRows;          // number of rows in table&lt;br /&gt;
     int         nCells;         // number of cells per row&lt;br /&gt;
     int         i;              // ubiquitous loop counter&lt;br /&gt;
     int         row, col;       // more counter variables&lt;br /&gt;
     int         colWidth;       // maximum width of a column&lt;br /&gt;
         &lt;br /&gt;
     Dimension   textInfo;       // holds text width and height&lt;br /&gt;
 &lt;br /&gt;
     '''[2]'''&lt;br /&gt;
     rowList = ((Element) mtableNode).getElementsByTagName(&amp;quot;mtr&amp;quot;);&lt;br /&gt;
     nRows = rowList.getLength();&lt;br /&gt;
         &lt;br /&gt;
     /* Check to see that all rows have the same number of cells */&lt;br /&gt;
     cellList = ((Element) rowList.item(0)).getElementsByTagName(&amp;quot;mtd&amp;quot;);&lt;br /&gt;
     nCells = cellList.getLength();&lt;br /&gt;
         &lt;br /&gt;
     for (i = 1; i &amp;lt; nRows; i++)&lt;br /&gt;
     {&lt;br /&gt;
         cellList = ((Element) rowList.item(i)).getElementsByTagName(&amp;quot;mtd&amp;quot;);&lt;br /&gt;
         if (cellList.getLength() != nCells)&lt;br /&gt;
         {&lt;br /&gt;
             System.err.println(&amp;quot;All rows must have &amp;quot; + nCells + &amp;quot; cells &amp;quot;);&lt;br /&gt;
             System.exit(1);&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
         &lt;br /&gt;
     y = (totalHeight - nRows * LINE_HEIGHT) / 2.0;      '''[3]'''&lt;br /&gt;
         &lt;br /&gt;
     newElement = svgDocument.createElement(&amp;quot;g&amp;quot;);     '''[4]'''&lt;br /&gt;
     newElement.setAttribute(&amp;quot;transform&amp;quot;,&lt;br /&gt;
         &amp;quot;translate(&amp;quot; + currX + &amp;quot;, &amp;quot; + y + &amp;quot;)&amp;quot; );&lt;br /&gt;
     newElement.setAttribute(&amp;quot;font-family&amp;quot;, &amp;quot;sans-serif&amp;quot;);&lt;br /&gt;
     newElement.setAttribute(&amp;quot;font-size&amp;quot;,&lt;br /&gt;
         Integer.toString(FONT_HEIGHT));&lt;br /&gt;
     gElement = (Element) svgRoot.appendChild( newElement );&lt;br /&gt;
         &lt;br /&gt;
     newElement = svgDocument.createElement(&amp;quot;path&amp;quot;);     '''[5]'''&lt;br /&gt;
     newElement.setAttribute(&amp;quot;d&amp;quot;,&lt;br /&gt;
         &amp;quot;M3 0h-3v&amp;quot; + (nRows*LINE_HEIGHT) +&lt;br /&gt;
             &amp;quot;h3&amp;quot;);&lt;br /&gt;
     newElement.setAttribute(&amp;quot;fill&amp;quot;, &amp;quot;none&amp;quot;);&lt;br /&gt;
     newElement.setAttribute(&amp;quot;stroke&amp;quot;, &amp;quot;black&amp;quot;);&lt;br /&gt;
         &lt;br /&gt;
     /* The next &amp;quot;nCells&amp;quot; siblings of this element     '''[6]'''&lt;br /&gt;
        will be the first column of the matrix */ &lt;br /&gt;
     startColumn = (Element) gElement.appendChild( newElement );&lt;br /&gt;
 &lt;br /&gt;
     /* Now get all the &amp;lt;mtd&amp;gt; cells in order */     '''[7]'''&lt;br /&gt;
     cellList = ((Element) mtableNode).getElementsByTagName(&amp;quot;mtd&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
     x = X_SPACING;&lt;br /&gt;
 &lt;br /&gt;
     textElement = null;&lt;br /&gt;
 &lt;br /&gt;
     for (col = 0; col &amp;lt; nCells; col++)&lt;br /&gt;
     {&lt;br /&gt;
         Node    currNode;&lt;br /&gt;
 &lt;br /&gt;
         colWidth = 0;&lt;br /&gt;
         for (row = 0; row &amp;lt; nRows; row++)&lt;br /&gt;
         {&lt;br /&gt;
             currNode = cellList.item( row * nCells + col );&lt;br /&gt;
             newElement = svgDocument.createElement(&amp;quot;text&amp;quot;);     '''[8]'''&lt;br /&gt;
             textInfo = constructTextNode( newElement, currNode,&lt;br /&gt;
                 FONT_HEIGHT );&lt;br /&gt;
             textElement = (Element) gElement.appendChild( newElement );&lt;br /&gt;
             textElement.setAttribute(&amp;quot;y&amp;quot;,&lt;br /&gt;
                 Integer.toString( row * LINE_HEIGHT + textInfo.height ) );&lt;br /&gt;
             textElement.setAttribute(&amp;quot;text-anchor&amp;quot;, &amp;quot;middle&amp;quot;);&lt;br /&gt;
             textElement.setAttribute(&amp;quot;font-size&amp;quot;,&lt;br /&gt;
                 Integer.toString(FONT_HEIGHT));&lt;br /&gt;
             if (textInfo.width &amp;gt; colWidth)&lt;br /&gt;
             {&lt;br /&gt;
                 colWidth = textInfo.width;&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
             &lt;br /&gt;
         /* go back and put in the &amp;quot;x&amp;quot; coordinates */     '''[9]'''&lt;br /&gt;
         startColumn = (Element) startColumn.getNextSibling();&lt;br /&gt;
         for (row = 0; row &amp;lt; nRows; row++)&lt;br /&gt;
         {&lt;br /&gt;
             startColumn.setAttribute(&amp;quot;x&amp;quot;,&lt;br /&gt;
                 Double.toString( x + colWidth/2.0 ) );&lt;br /&gt;
             startColumn = (Element) startColumn.getNextSibling();&lt;br /&gt;
         }&lt;br /&gt;
         x += colWidth + X_SPACING;&lt;br /&gt;
         startColumn = textElement;&lt;br /&gt;
 &lt;br /&gt;
     }&lt;br /&gt;
         &lt;br /&gt;
     x += X_SPACING;&lt;br /&gt;
     /* the closing bracket */     '''[10]'''&lt;br /&gt;
     newElement = svgDocument.createElement(&amp;quot;path&amp;quot;);&lt;br /&gt;
     newElement.setAttribute(&amp;quot;d&amp;quot;,&lt;br /&gt;
         &amp;quot;M&amp;quot; + (x-3) + &amp;quot; 0h3v&amp;quot; + (nRows*LINE_HEIGHT) +&lt;br /&gt;
         &amp;quot;h-3&amp;quot;);&lt;br /&gt;
     newElement.setAttribute(&amp;quot;fill&amp;quot;, &amp;quot;none&amp;quot;);&lt;br /&gt;
     newElement.setAttribute(&amp;quot;stroke&amp;quot;, &amp;quot;black&amp;quot;);&lt;br /&gt;
     startColumn = (Element) gElement.appendChild( newElement );&lt;br /&gt;
 &lt;br /&gt;
     return x + 2*X_SPACING;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[1]'''&amp;lt;/tt&amp;gt; We start off with a clump of declarations. I tend to use a lot of temporary variables so that I don't have to constantly call the DOM access functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[2]'''&amp;lt;/tt&amp;gt; The function starts by extracting the number of rows in this matrix and seeing that all the rows have the same number of cells in them.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[3]'''&amp;lt;/tt&amp;gt; After this sanity check, the function calculates where the top ''y'' coordinate of the matrix should be when the matrix is vertically centered.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[4]'''&amp;lt;/tt&amp;gt; Once the top position of the matrix is known, the program creates a &amp;lt;tt&amp;gt;&amp;lt;g&amp;gt;&amp;lt;/tt&amp;gt; element to enclose the matrix. The &amp;lt;tt&amp;gt;transform&amp;lt;/tt&amp;gt; attribute positions it, and the &amp;lt;tt&amp;gt;font-family&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;font-size&amp;lt;/tt&amp;gt; will apply to all the text in that matrix. We are using presentation attributes because it's easier to set them individually than to construct a string for the appropriate &amp;lt;tt&amp;gt;style&amp;lt;/tt&amp;gt; attribute.&lt;br /&gt;
&lt;br /&gt;
The resulting element is appended to the root element's children, and, for ease of future access, is stored in the variable &amp;lt;tt&amp;gt;''gElement''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[5]'''&amp;lt;/tt&amp;gt; The first thing inside the &amp;lt;tt&amp;gt;&amp;lt;g&amp;gt;&amp;lt;/tt&amp;gt; is a &amp;lt;tt&amp;gt;&amp;lt;path&amp;gt;&amp;lt;/tt&amp;gt; that draws the left bracket enclosing the matrix.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[6]'''&amp;lt;/tt&amp;gt; Following the bracket, &amp;lt;tt&amp;gt;generateMatrix&amp;lt;/tt&amp;gt; draws the matrix's cells column by column. Each cell will become a &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;&amp;lt;/tt&amp;gt; element. As we insert each cell for a particular column into the output tree, we'll keep track of its text width. At the end of the column, we'll know the column's maximum width, and we will go back and update the &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt; attributes of each of the &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;&amp;lt;/tt&amp;gt; elements. This requires us to remember the starting point after which we began adding cells. That's why we had to save the position of the &amp;lt;tt&amp;gt;&amp;lt;path&amp;gt;&amp;lt;/tt&amp;gt; element in &amp;lt;tt&amp;gt;''startColumn''&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[7]'''&amp;lt;/tt&amp;gt; Here's the code that creates the cells for the entire matrix. Note that we grabbed all the &amp;lt;tt&amp;gt;&amp;lt;mtd&amp;gt;&amp;lt;/tt&amp;gt; descendants of the &amp;lt;tt&amp;gt;&amp;lt;mtable&amp;gt;&amp;lt;/tt&amp;gt; node. This bypasses any intervening elements, but that's OK since we don't have any nested tables.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[8]'''&amp;lt;/tt&amp;gt; The actual task of building the cell contents is left to the &amp;lt;tt&amp;gt;constructTextNode&amp;lt;/tt&amp;gt; function; in this segment of the code we set the &amp;lt;tt&amp;gt;y&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;font-size&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;text-anchor&amp;lt;/tt&amp;gt; attributes of the cell.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[9]'''&amp;lt;/tt&amp;gt; Here is the code that goes back to fill in the &amp;lt;tt&amp;gt;x&amp;lt;/tt&amp;gt; attribute after each column is complete. The &amp;lt;tt&amp;gt;getNextSibling&amp;lt;/tt&amp;gt; function proceeds through the text elements that were just added. Once this is done, we reset the &amp;lt;tt&amp;gt;''startColumn''&amp;lt;/tt&amp;gt; variable to point to the very last &amp;lt;tt&amp;gt;''textElement''&amp;lt;/tt&amp;gt; element we added, for its siblings will become the next column.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[10]'''&amp;lt;/tt&amp;gt; Finally, the function creates another &amp;lt;tt&amp;gt;&amp;lt;path&amp;gt;&amp;lt;/tt&amp;gt; element for the right bracket of the matrix, and the matrix has been generated. We return the total width of the matrix, plus a bit of extra padding.&lt;br /&gt;
&lt;br /&gt;
Now let's look at the &amp;lt;tt&amp;gt;constructTextNode&amp;lt;/tt&amp;gt; function. The way the program is set up, text may be subscripted within an &amp;lt;tt&amp;gt;&amp;lt;msub&amp;gt;&amp;lt;/tt&amp;gt; element, which this function should handle. If the text is enclosed in &amp;lt;tt&amp;gt;&amp;lt;mi&amp;gt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;lt;mn&amp;gt;&amp;lt;/tt&amp;gt; elements, &amp;lt;tt&amp;gt;constructTextNode&amp;lt;/tt&amp;gt; ignores the tags and takes only the enclosed text. The parameters to &amp;lt;tt&amp;gt;constructTextNode&amp;lt;/tt&amp;gt; are the destination node to which the text is to be added in the output tree, the parent source node that contains the original text, and the font size for the text.&lt;br /&gt;
&lt;br /&gt;
 public Dimension constructTextNode( Node destNode, Node parentNode, &lt;br /&gt;
     int size )&lt;br /&gt;
 {&lt;br /&gt;
     NodeList    children = parentNode.getChildNodes();     '''[1]'''&lt;br /&gt;
     Node        currNode;&lt;br /&gt;
     int         i;&lt;br /&gt;
     Dimension   d = new Dimension(0, 0);&lt;br /&gt;
     Dimension   subDim;&lt;br /&gt;
 &lt;br /&gt;
     for (i=0; i &amp;lt; children.getLength(); i++ )&lt;br /&gt;
     {&lt;br /&gt;
         subDim = new Dimension(0,0);&lt;br /&gt;
         currNode = children.item(i);&lt;br /&gt;
         if (currNode.getNodeName().equals(&amp;quot;#text&amp;quot;))       '''[2]'''&lt;br /&gt;
         {&lt;br /&gt;
             Text    textNode;&lt;br /&gt;
             String  value = currNode.getNodeValue();&lt;br /&gt;
 &lt;br /&gt;
             subDim = stringInfo( value, size );&lt;br /&gt;
             textNode = svgDocument.createTextNode( value );&lt;br /&gt;
             destNode.appendChild( textNode );&lt;br /&gt;
         }&lt;br /&gt;
         else if (currNode.getNodeName().equals(&amp;quot;msub&amp;quot;))     '''[3]'''&lt;br /&gt;
         {&lt;br /&gt;
             Element newElement;&lt;br /&gt;
             newElement = svgDocument.createElement(&amp;quot;tspan&amp;quot;);&lt;br /&gt;
             newElement.setAttribute( &amp;quot;baseline-shift&amp;quot;,&lt;br /&gt;
                 &amp;quot;sub&amp;quot;);&lt;br /&gt;
             newElement.setAttribute(&amp;quot;font-size&amp;quot;,&lt;br /&gt;
                 Integer.toString(SUBSCRIPT_HEIGHT));&lt;br /&gt;
             newElement = (Element) destNode.appendChild( newElement );&lt;br /&gt;
             subDim = constructTextNode( newElement, currNode,&lt;br /&gt;
                 SUBSCRIPT_HEIGHT );             &lt;br /&gt;
         }&lt;br /&gt;
         else if (currNode.getNodeType() == Node.ELEMENT_NODE)      '''[4]'''&lt;br /&gt;
         {&lt;br /&gt;
             subDim = constructTextNode( destNode, currNode, size );&lt;br /&gt;
         }&lt;br /&gt;
             &lt;br /&gt;
         d.width += subDim.width;      '''[5]'''&lt;br /&gt;
         if (subDim.height &amp;gt; d.height)&lt;br /&gt;
         {&lt;br /&gt;
             d.height = subDim.height;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
     return d;&lt;br /&gt;
 }&lt;br /&gt;
     &lt;br /&gt;
 public Dimension stringInfo( String str, int fontSize )     '''[6]'''&lt;br /&gt;
 {&lt;br /&gt;
     BufferedImage buffer = new BufferedImage(&lt;br /&gt;
         100, 100, BufferedImage.TYPE_INT_RGB);&lt;br /&gt;
     Graphics g = buffer.getGraphics();&lt;br /&gt;
     Font f = new Font(&amp;quot;SansSerif&amp;quot;, Font.PLAIN, fontSize);&lt;br /&gt;
     g.setFont( f );&lt;br /&gt;
     FontMetrics fm = g.getFontMetrics();&lt;br /&gt;
 &lt;br /&gt;
     return new Dimension( fm.stringWidth( str ), fm.getAscent() );&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[1]'''&amp;lt;/tt&amp;gt; The function starts by getting all the immediate children of the source node and setting the total width and height of the text, stored in variable &amp;lt;tt&amp;gt;''d''&amp;lt;/tt&amp;gt;, to zero.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[2]'''&amp;lt;/tt&amp;gt; We look at each of the children of the current source node in turn. If the child is a text element, we create a text node for it, find its width and ascent height by calling &amp;lt;tt&amp;gt;stringInfo&amp;lt;/tt&amp;gt;, and append it to the destination node's children.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[3]'''&amp;lt;/tt&amp;gt; However, if the child is an &amp;lt;tt&amp;gt;&amp;lt;msub&amp;gt;&amp;lt;/tt&amp;gt; element, we must create a &amp;lt;tt&amp;gt;&amp;lt;tspan&amp;gt;&amp;lt;/tt&amp;gt; element in the output with a &amp;lt;tt&amp;gt;baseline-shift&amp;lt;/tt&amp;gt; attribute for subscripting. We then recursively call &amp;lt;tt&amp;gt;constructTextNode&amp;lt;/tt&amp;gt; to add all the enclosed text to this new &amp;lt;tt&amp;gt;&amp;lt;tspan&amp;gt;&amp;lt;/tt&amp;gt; node.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[4]'''&amp;lt;/tt&amp;gt; If it's not text and not subscripted, it's some other element node that we don't care to handle, so just do a recursive call to gather all its text and append it to the destination node.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[5]'''&amp;lt;/tt&amp;gt; No matter what course of action we took, &amp;lt;tt&amp;gt;''subDim''&amp;lt;/tt&amp;gt; now contains the width and height of the text that was appended. We add the width to the total and keep track of the maximum height.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[6]'''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;constructTextNode&amp;lt;/tt&amp;gt; calls the &amp;lt;tt&amp;gt;stringInfo&amp;lt;/tt&amp;gt; function to determine the width and ascent height of text. Because we don't know how an SVG viewer will render text, and thus can't determine its length exactly, we have to do the best we can. In this instance, we load the generic sans-serif font, set its size, get the font metrics, and use the results from that. Since the output will come from the Batik SVG viewer, which is also Java-based, it's reasonable to presume that the numbers will come out fairly close to the final results. &amp;lt;tt&amp;gt;stringInfo&amp;lt;/tt&amp;gt; opens up an in-memory image in order to access a graphics environment.&lt;br /&gt;
&lt;br /&gt;
The last function to consider is &amp;lt;tt&amp;gt;generateOperator&amp;lt;/tt&amp;gt;, which contains no new DOM concepts. It checks to see if the first child of the &amp;lt;tt&amp;gt;mo&amp;lt;/tt&amp;gt; element is a text node whose value is a left or right parenthesis. If so, the function produces an elliptical arc as tall as the largest matrix in the entire expression. Otherwise, it's some other mathematical operator, and is treated as plain text by calling the &amp;lt;tt&amp;gt;constructTextNode&amp;lt;/tt&amp;gt; function.&lt;br /&gt;
&lt;br /&gt;
 public int generateOperator( Node moNode, int currX, int totalHeight )&lt;br /&gt;
 {&lt;br /&gt;
     double      y;&lt;br /&gt;
     int         fontsize;&lt;br /&gt;
     Element     newElement, textElement;&lt;br /&gt;
     Dimension   textInfo;&lt;br /&gt;
 &lt;br /&gt;
     currX += X_SPACING;&lt;br /&gt;
     y = (totalHeight) / 2.0;&lt;br /&gt;
         &lt;br /&gt;
     fontsize = FONT_HEIGHT;&lt;br /&gt;
     if (moNode.getFirstChild().getNodeType() == Node.TEXT_NODE)&lt;br /&gt;
     {&lt;br /&gt;
         String str = moNode.getFirstChild().getNodeValue();&lt;br /&gt;
         if (str.equals( &amp;quot;(&amp;quot; ))&lt;br /&gt;
         {&lt;br /&gt;
             newElement = svgDocument.createElement(&amp;quot;path&amp;quot;);&lt;br /&gt;
             newElement.setAttribute( &amp;quot;d&amp;quot;,&lt;br /&gt;
                 &amp;quot;M&amp;quot; + (currX+12) + &amp;quot; 8 a12 &amp;quot; + y + &amp;quot; 0 0 0 &amp;quot; +&lt;br /&gt;
                     &amp;quot;0&amp;quot; + &amp;quot; &amp;quot; + (totalHeight-EXTRA_HEIGHT - 8) );&lt;br /&gt;
             newElement.setAttribute( &amp;quot;fill&amp;quot;, &amp;quot;none&amp;quot;);&lt;br /&gt;
             newElement.setAttribute( &amp;quot;stroke&amp;quot;, &amp;quot;black&amp;quot; );&lt;br /&gt;
             svgRoot.appendChild( newElement );&lt;br /&gt;
             return 16 + X_SPACING;&lt;br /&gt;
         }&lt;br /&gt;
         else if (str.equals( &amp;quot;)&amp;quot; ))&lt;br /&gt;
         {&lt;br /&gt;
             newElement = svgDocument.createElement(&amp;quot;path&amp;quot;);&lt;br /&gt;
             newElement.setAttribute( &amp;quot;d&amp;quot;,&lt;br /&gt;
                 &amp;quot;M&amp;quot; + currX + &amp;quot; 8 a12 &amp;quot; + y + &amp;quot; 0 0 1 &amp;quot; +&lt;br /&gt;
                     &amp;quot;0&amp;quot; + &amp;quot; &amp;quot; + (totalHeight-EXTRA_HEIGHT - 8) );&lt;br /&gt;
             newElement.setAttribute( &amp;quot;fill&amp;quot;, &amp;quot;none&amp;quot;);&lt;br /&gt;
             newElement.setAttribute( &amp;quot;stroke&amp;quot;, &amp;quot;black&amp;quot; );&lt;br /&gt;
             svgRoot.appendChild( newElement );&lt;br /&gt;
             return 10 + X_SPACING;&lt;br /&gt;
         }&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     newElement = svgDocument.createElement(&amp;quot;text&amp;quot;);&lt;br /&gt;
     textInfo = constructTextNode( newElement, moNode, fontsize );&lt;br /&gt;
         &lt;br /&gt;
     textElement = (Element) svgRoot.appendChild( newElement );&lt;br /&gt;
     if (fontsize != FONT_HEIGHT)&lt;br /&gt;
     {&lt;br /&gt;
         y = 0;&lt;br /&gt;
         textElement.setAttribute(&amp;quot;stroke-width&amp;quot;,&lt;br /&gt;
             Double.toString( (FONT_HEIGHT * 1.0 / fontsize )) );&lt;br /&gt;
     }&lt;br /&gt;
     textElement.setAttribute(&amp;quot;transform&amp;quot;,&lt;br /&gt;
         &amp;quot;translate(&amp;quot; + currX + &amp;quot;, &amp;quot; + (y+textInfo.height/2.0) + &amp;quot;)&amp;quot; );&lt;br /&gt;
     textElement.setAttribute(&amp;quot;font-size&amp;quot;,&lt;br /&gt;
         Integer.toString(fontsize));&lt;br /&gt;
         &lt;br /&gt;
     return textInfo.width + 2 * X_SPACING;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
What do we get when we put this all together? The following MathML matrices:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;math&amp;gt;&lt;br /&gt;
 &amp;lt;mrow&amp;gt;&lt;br /&gt;
 &amp;lt;mo&amp;gt;(&amp;lt;/mo&amp;gt;&lt;br /&gt;
 &amp;lt;mtable&amp;gt;&lt;br /&gt;
 &amp;lt;mtr&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mi&amp;gt;x&amp;lt;/mi&amp;gt;&amp;lt;msub&amp;gt;&amp;lt;mn&amp;gt;1&amp;lt;/mn&amp;gt;&amp;lt;/msub&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mi&amp;gt;y&amp;lt;/mi&amp;gt;&amp;lt;msub&amp;gt;&amp;lt;mn&amp;gt;1&amp;lt;/mn&amp;gt;&amp;lt;/msub&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mi&amp;gt;1&amp;lt;/mi&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
 &amp;lt;/mtr&amp;gt;&lt;br /&gt;
 &amp;lt;/mtable&amp;gt;&lt;br /&gt;
 &amp;lt;mo&amp;gt;*&amp;lt;/mo&amp;gt;&lt;br /&gt;
 &amp;lt;mtable&amp;gt;&lt;br /&gt;
 &amp;lt;mtr&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mo&amp;gt;cos(&amp;lt;/mo&amp;gt;&amp;lt;mi&amp;gt;a&amp;lt;/mi&amp;gt;&amp;lt;mo&amp;gt;)&amp;lt;/mo&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mo&amp;gt;-sin(&amp;lt;/mo&amp;gt;&amp;lt;mi&amp;gt;a&amp;lt;/mi&amp;gt;&amp;lt;mo&amp;gt;)&amp;lt;/mo&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mn&amp;gt;0&amp;lt;/mn&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
 &amp;lt;/mtr&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;mtr&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mo&amp;gt;sin(&amp;lt;/mo&amp;gt;&amp;lt;mi&amp;gt;a&amp;lt;/mi&amp;gt;&amp;lt;mo&amp;gt;)&amp;lt;/mo&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mo&amp;gt;cos(&amp;lt;/mo&amp;gt;&amp;lt;mi&amp;gt;a&amp;lt;/mi&amp;gt;&amp;lt;mo&amp;gt;)&amp;lt;/mo&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mn&amp;gt;0&amp;lt;/mn&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
 &amp;lt;/mtr&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;mtr&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mn&amp;gt;0&amp;lt;/mn&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mn&amp;gt;0&amp;lt;/mn&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mn&amp;gt;1&amp;lt;/mn&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
 &amp;lt;/mtr&amp;gt;&lt;br /&gt;
 &amp;lt;/mtable&amp;gt;&lt;br /&gt;
 &amp;lt;mo&amp;gt;)&amp;lt;/mo&amp;gt;&lt;br /&gt;
 &amp;lt;mo&amp;gt;=&amp;lt;/mo&amp;gt;&lt;br /&gt;
 &amp;lt;mtable&amp;gt;&lt;br /&gt;
 &amp;lt;mtr&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mi&amp;gt;x&amp;lt;/mi&amp;gt;&amp;lt;msub&amp;gt;&amp;lt;mn&amp;gt;2&amp;lt;/mn&amp;gt;&amp;lt;/msub&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mi&amp;gt;y&amp;lt;/mi&amp;gt;&amp;lt;msub&amp;gt;&amp;lt;mn&amp;gt;2&amp;lt;/mn&amp;gt;&amp;lt;/msub&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
     &amp;lt;mtd&amp;gt; &amp;lt;mi&amp;gt;1&amp;lt;/mi&amp;gt; &amp;lt;/mtd&amp;gt;&lt;br /&gt;
 &amp;lt;/mtr&amp;gt;&lt;br /&gt;
 &amp;lt;/mtable&amp;gt;&lt;br /&gt;
 &amp;lt;/mrow&amp;gt;&lt;br /&gt;
 &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
become this SVG:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE svg PUBLIC &amp;quot;-//W3C//DTD SVG 20001102//EN&amp;quot;&lt;br /&gt;
    &amp;quot;http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;svg height=&amp;quot;82&amp;quot; viewBox=&amp;quot;0 0 378 82&amp;quot; width=&amp;quot;378&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;path d=&amp;quot;M14 8 a12 41.0 0 0 0 0 64&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;black&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;g font-family=&amp;quot;sans-serif&amp;quot; font-size=&amp;quot;14&amp;quot; &lt;br /&gt;
        transform=&amp;quot;translate(18, 29.0)&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;path d=&amp;quot;M3 0h-3v24h3&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;black&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;15.5&amp;quot;&lt;br /&gt;
            y=&amp;quot;15&amp;quot;&amp;gt;x&amp;lt;tspan baseline-shift=&amp;quot;sub&amp;quot; font-size=&amp;quot;12&amp;quot;&amp;gt;1&amp;lt;/tspan&amp;gt;&lt;br /&gt;
        &amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;44.0&amp;quot;&lt;br /&gt;
            y=&amp;quot;15&amp;quot;&amp;gt;y&amp;lt;tspan baseline-shift=&amp;quot;sub&amp;quot; font-size=&amp;quot;12&amp;quot;&amp;gt;1&amp;lt;/tspan&amp;gt;&lt;br /&gt;
        &amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; &lt;br /&gt;
            x=&amp;quot;68.5&amp;quot; y=&amp;quot;15&amp;quot;&amp;gt;1&amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;path d=&amp;quot;M79 0h3v24h-3&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;black&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/g&amp;gt;&lt;br /&gt;
    &amp;lt;text font-size=&amp;quot;14&amp;quot; transform=&amp;quot;translate(106, 48.5)&amp;quot;&amp;gt;*&amp;lt;/text&amp;gt;&lt;br /&gt;
    &amp;lt;g font-family=&amp;quot;sans-serif&amp;quot; font-size=&amp;quot;14&amp;quot; &lt;br /&gt;
        transform=&amp;quot;translate(115, 5.0)&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;path d=&amp;quot;M3 0h-3v72h3&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;black&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; &lt;br /&gt;
            x=&amp;quot;28.5&amp;quot; y=&amp;quot;15&amp;quot;&amp;gt;cos(a)&amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; &lt;br /&gt;
            x=&amp;quot;28.5&amp;quot; y=&amp;quot;39&amp;quot;&amp;gt;sin(a)&amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; &lt;br /&gt;
            x=&amp;quot;28.5&amp;quot; y=&amp;quot;63&amp;quot;&amp;gt;0&amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; &lt;br /&gt;
            x=&amp;quot;86.5&amp;quot; y=&amp;quot;15&amp;quot;&amp;gt;-sin(a)&amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; &lt;br /&gt;
            x=&amp;quot;86.5&amp;quot; y=&amp;quot;39&amp;quot;&amp;gt;cos(a)&amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; &lt;br /&gt;
            x=&amp;quot;86.5&amp;quot; y=&amp;quot;63&amp;quot;&amp;gt;0&amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; &lt;br /&gt;
            x=&amp;quot;127.5&amp;quot; y=&amp;quot;15&amp;quot;&amp;gt;0&amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; &lt;br /&gt;
            x=&amp;quot;127.5&amp;quot; y=&amp;quot;39&amp;quot;&amp;gt;0&amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; &lt;br /&gt;
            x=&amp;quot;127.5&amp;quot; y=&amp;quot;63&amp;quot;&amp;gt;1&amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;path d=&amp;quot;M138 0h3v72h-3&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;black&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/g&amp;gt;&lt;br /&gt;
    &amp;lt;path d=&amp;quot;M262 8 a12 41.0 0 0 1 0 64&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;black&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;text font-size=&amp;quot;14&amp;quot; transform=&amp;quot;translate(274, 48.5)&amp;quot;&amp;gt;=&amp;lt;/text&amp;gt;&lt;br /&gt;
    &amp;lt;g font-family=&amp;quot;sans-serif&amp;quot; font-size=&amp;quot;14&amp;quot; &lt;br /&gt;
        transform=&amp;quot;translate(288, 29.0)&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;path d=&amp;quot;M3 0h-3v24h3&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;black&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;15.5&amp;quot;&lt;br /&gt;
            y=&amp;quot;15&amp;quot;&amp;gt;x&amp;lt;tspan baseline-shift=&amp;quot;sub&amp;quot; font-size=&amp;quot;12&amp;quot;&amp;gt;2&amp;lt;/tspan&amp;gt;&lt;br /&gt;
        &amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; x=&amp;quot;44.0&amp;quot;&lt;br /&gt;
            y=&amp;quot;15&amp;quot;&amp;gt;y&amp;lt;tspan baseline-shift=&amp;quot;sub&amp;quot; font-size=&amp;quot;12&amp;quot;&amp;gt;2&amp;lt;/tspan&amp;gt;&lt;br /&gt;
        &amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;text font-size=&amp;quot;14&amp;quot; text-anchor=&amp;quot;middle&amp;quot; &lt;br /&gt;
            x=&amp;quot;68.5&amp;quot; y=&amp;quot;15&amp;quot;&amp;gt;1&amp;lt;/text&amp;gt;&lt;br /&gt;
        &amp;lt;path d=&amp;quot;M79 0h3v24h-3&amp;quot; fill=&amp;quot;none&amp;quot; stroke=&amp;quot;black&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/g&amp;gt;&lt;br /&gt;
&amp;lt;/svg&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
which becomes [[SVG Essentials/Generating SVG#svgess-CHP-12-FIG-2|Figure 12-2]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;svgess-CHP-12-FIG-2&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 12-2. Sample converted from MathML to SVG'''&lt;br /&gt;
&lt;br /&gt;
[[Image:SVG Essentials/I_12_tt287.png|Sample converted from MathML to SVG]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find out more about manipulating XML with Java in the aptly named book ''Java &amp;amp; XML'' by Brett McLaughlin, published by O'Reilly &amp;amp; Associates.&lt;br /&gt;
&lt;br /&gt;
== Using XSLT to Convert XML Data to SVG ==&lt;br /&gt;
&lt;br /&gt;
=== Defining the Task ===&lt;br /&gt;
&lt;br /&gt;
The final example in this chapter uses the Extensible Stylesheet Language Transformations (XSLT) to extract information from an XML file and insert it into an SVG file. The source data is in the Weather Observation Markup Format (OMF), defined at ''http://zowie.metnet.navy.mil/~spawar/JMV-TNG/XML/OMF.html''. OMF is, for the most part, a wrapper for several different types of weather reports. The OMF elements add annotation, decoded information, and quantities calculated from the raw reports. Here is a sample report:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;Reports TStamp=&amp;quot;997568716&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;lt;SYN Title='AAXX' TStamp='997573600' LatLon='37.567, 126.967' BId='471080'&lt;br /&gt;
 SName='RKSL, SEOUL' Elev='86'&amp;gt;&lt;br /&gt;
 &amp;lt;SYID&amp;gt;47108&amp;lt;/SYID&amp;gt;&lt;br /&gt;
 &amp;lt;SYG T='22.5' TD='14.1' P='1004.1' P0='1014.1' Pd='0 0.1' Vis='22000'&lt;br /&gt;
 Ceiling='INF' Wind='30-70, 1.5' WX='NOSIG' Prec=' ' Clouds='44070'&amp;gt;&lt;br /&gt;
 32972 40703 10225 20141 30041 40141 50001 84070&lt;br /&gt;
 &amp;lt;/SYG&amp;gt;&amp;lt;/SYN&amp;gt;&lt;br /&gt;
 &amp;lt;/Reports&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Our objective is to extract the reporting station, the date and time, temperature, wind speed and direction, and visibility from the report. These data will be filled into the graphic template of [[SVG Essentials/Generating SVG#svgess-CHP-12-FIG-3|Figure 12-3]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;svgess-CHP-12-FIG-3&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 12-3. Graphic weather template'''&lt;br /&gt;
&lt;br /&gt;
[[Image:SVG Essentials/I_12_tt289.png|Graphic weather template]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example is atypical, in that all the information is contained in the attributes of the source XML rather than the content of the elements. Paradoxically, this makes our example typical, since real-world markup so often fails to follow the pristine examples found in textbooks or reference manuals. You'll eventually encounter such data, so it may as well be now. The OMF format attributes we're interested in are listed here, along with the plan for displaying them in the final graphic. The first two required attributes come from the &amp;lt;tt&amp;gt;&amp;lt;SYN&amp;gt;&amp;lt;/tt&amp;gt; element, the rest are optional attributes from its child &amp;lt;tt&amp;gt;&amp;lt;SYG&amp;gt;&amp;lt;/tt&amp;gt; element.&lt;br /&gt;
&lt;br /&gt;
;&amp;lt;tt&amp;gt;TStamp&amp;lt;/tt&amp;gt;&lt;br /&gt;
: The timestamp in seconds since midnight, January 1, 1970 UTC. In the final graphic, the date and time will be represented in text, and the time will also be shown on an analog clock. The color of the clock face will be light yellow to indicate hours between 6 A.M. and 6 P.M., and light blue for evening and night hours.&lt;br /&gt;
;&amp;lt;tt&amp;gt;SName&amp;lt;/tt&amp;gt;&lt;br /&gt;
: The reporting station's call letters, possibly followed by a comma and the station's full name. The final graphic will represent this as text.&lt;br /&gt;
;&amp;lt;tt&amp;gt;T&amp;lt;/tt&amp;gt;&lt;br /&gt;
: The air temperature in degrees Celsius. This will be displayed by coloring in the thermometer to the appropriate level. If the temperature is greater than zero, the coloring will be red; if less than or equal to zero, it will be blue.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;dl&amp;gt;&lt;br /&gt;
&amp;lt;dt&amp;gt;&amp;lt;tt&amp;gt;Wind&amp;lt;/tt&amp;gt;&lt;br /&gt;
&amp;lt;dd&amp;gt;A direction and speed, separated by a comma. The direction is measured in degrees; 0 indicates wind blowing from true north, and 270 indicates wind from the west. This will be represented by a line on the compass.&lt;br /&gt;
&lt;br /&gt;
Wind direction may also be expressed as two numbers separated by a dash, indicating a range of directions. Thus, &amp;lt;tt&amp;gt;0-40&amp;lt;/tt&amp;gt; indicates wind from the north to north-east. In this case, two dashed lines will be drawn on the compass.&lt;br /&gt;
&lt;br /&gt;
The wind speed is expressed in meters per second. If two numbers are given, separated by a dash, the second number indicates the speed of gusts of wind. This information will be displayed in text form.&lt;br /&gt;
&amp;lt;/dl&amp;gt;;&amp;lt;tt&amp;gt;Vis&amp;lt;/tt&amp;gt;&lt;br /&gt;
: Surface visibility in meters, or the value &amp;lt;tt&amp;gt;INF&amp;lt;/tt&amp;gt; for unlimited visibility. The final graphic will represent this by filling in a horizontal bar. Any visibility above 40 kilometers will be presumed to be unlimited.&lt;br /&gt;
&lt;br /&gt;
=== How XSLT Works ===&lt;br /&gt;
&lt;br /&gt;
To convert an OMF source file to its destination SVG format, we will create a list of specifications that tells which elements and attributes in OMF are of interest to us. These specifications will then detail what SVG elements to generate whenever we encounter an item of interest. If we were asking a human to do the transformation by hand, we could write out an English language description:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;ul&amp;gt;&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Begin a new SVG document by typing this:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE svg PUBLIC &amp;quot;-//W3C/DTD SVG 1.0//EN&amp;quot;,&lt;br /&gt;
 &amp;quot;http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd&amp;quot;&amp;gt;	&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;Go through the source document. As you find each element, look for instructions on how to process it.&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;To process the &amp;lt;tt&amp;gt;&amp;lt;Reports&amp;gt;&amp;lt;/tt&amp;gt; element, type the following into a text editor, then process any sub-elements as specified in comments.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;svg viewBox=&amp;quot;0 0 350 200&amp;quot; height=&amp;quot;200&amp;quot; width=&amp;quot;350&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;amp;lt;!-- process any SYN elements you find within this element --&amp;gt;&lt;br /&gt;
 &amp;lt;/svg&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;To process a &amp;lt;tt&amp;gt;&amp;lt;SYN&amp;gt;&amp;lt;/tt&amp;gt; element, type this text and fill in the blanks:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;text font-size=&amp;quot;10pt&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;20&amp;quot;&amp;gt;&lt;br /&gt;
 &amp;amp;lt;!-- fill in the value of the SName attribute --&amp;gt; &lt;br /&gt;
 &amp;lt;/text&amp;gt;&lt;br /&gt;
     &lt;br /&gt;
 &amp;amp;lt;!-- process any SYG elements you find within this element --&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;To process a &amp;lt;tt&amp;gt;&amp;lt;SYG&amp;gt;&amp;lt;/tt&amp;gt; element:&lt;br /&gt;
&lt;br /&gt;
# Extract the value of the &amp;lt;tt&amp;gt;T&amp;lt;/tt&amp;gt; attribute, and use that value when following the instructions for &amp;quot;how to draw a thermometer.&amp;quot;&lt;br /&gt;
# Extract the value of the &amp;lt;tt&amp;gt;Wind&amp;lt;/tt&amp;gt; attribute, and use that value as you follow the instructions for &amp;quot;how to draw a wind compass.&amp;quot;&lt;br /&gt;
# (etc.)&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;To draw a thermometer, calculate the height of the bar as 50 minus the value you got from the &amp;lt;tt&amp;gt;T&amp;lt;/tt&amp;gt; attribute, and use that result where you see the italicized text as you type the following:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;path&lt;br /&gt;
     d = &amp;quot;M 25 ''height'' 25 90&lt;br /&gt;
     A 10 10 0 1 0 35 90&lt;br /&gt;
     L 35 ''height'' Z&amp;quot;&lt;br /&gt;
     style=&amp;quot;stroke: none; fill: {$tint};&amp;quot;/&amp;gt;&lt;br /&gt;
 &amp;lt;path &lt;br /&gt;
     d= &amp;quot;M 25 0 25 90 A 10 10 0 1 0 35 90 L 35 0 Z&amp;quot;&lt;br /&gt;
     style=&amp;quot;stroke: black; fill: none;&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;li&amp;gt;&amp;lt;div&amp;gt;To draw a wind compass (etc.).&lt;br /&gt;
&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Rather than writing our specifications in English and handing them to a human to perform, we will write the specifications in the XSLT markup format. We'll hand the XSLT file, along with the OMF file, to the Apache Software Foundation's Xalan processor, and it will process elements and fill in the blanks to produce an output SVG file. Here is a quick English-to-XSLT translation guide.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; &lt;br /&gt;
|-&lt;br /&gt;
! English !! XSLT&lt;br /&gt;
|-&lt;br /&gt;
| Process an &amp;lt;tt&amp;gt;''element''&amp;lt;/tt&amp;gt; element || &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:template match=&amp;quot;''element''&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;amp;lt;!-- output to produce --&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Process any &amp;lt;tt&amp;gt;''items''&amp;lt;/tt&amp;gt; within the current element || &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:apply-templates select=&amp;quot;''items''&amp;quot;/&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Fill in the value of an &amp;lt;tt&amp;gt;''item''&amp;lt;/tt&amp;gt; || &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:value-of select=&amp;quot;''item''&amp;quot;/&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Use the value of an &amp;lt;tt&amp;gt;''item''&amp;lt;/tt&amp;gt; as a variable named &amp;lt;tt&amp;gt;''var''&amp;lt;/tt&amp;gt; || &lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:variable name=&amp;quot;''var''&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;amp;lt;!-- instructions to produce ''item'''s value --&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Developing an XSL Stylesheet ===&lt;br /&gt;
&lt;br /&gt;
We'll add details as we proceed, but this gives us more than enough to start. The XSLT file begins like this:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;xsl:stylesheet version=&amp;quot;1.0&amp;quot;&lt;br /&gt;
   xmlns:xsl=&amp;quot;http://www.w3.org/1999/XSL/Transform&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xsl:output method=&amp;quot;xml&amp;quot; indent=&amp;quot;yes&amp;quot;     &amp;lt;/nowiki&amp;gt;'''[1]'''&amp;lt;nowiki&amp;gt;&lt;br /&gt;
    doctype-public=&amp;quot;-//W3C//DTD SVG 1.0//EN&amp;quot;&lt;br /&gt;
    doctype-system=&lt;br /&gt;
        &amp;quot;http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;xsl:template match=&amp;quot;Reports&amp;quot;&amp;gt;     &amp;lt;/nowiki&amp;gt;'''[2]'''&lt;br /&gt;
 &amp;lt;svg width=&amp;quot;350&amp;quot; height=&amp;quot;200&amp;quot; viewBox=&amp;quot;0 0 350 200&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;defs&amp;gt;&lt;br /&gt;
         &amp;lt;path id=&amp;quot;wind-line&amp;quot; d=&amp;quot;M 40 40 h 25&amp;quot;&lt;br /&gt;
             style=&amp;quot;stroke: black; fill: none;&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;/defs&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:apply-templates select=&amp;quot;SYN&amp;quot;/&amp;gt;     '''[3]'''&lt;br /&gt;
 &amp;lt;/svg&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[1]'''&amp;lt;/tt&amp;gt; The &amp;lt;tt&amp;gt;&amp;lt;xsl:output&amp;gt;&amp;lt;/tt&amp;gt; specifies that the output will be an XML file and that we want it indented nicely. It also generates the appropriate &amp;lt;tt&amp;gt;&amp;lt;!DOCTYPE ...&amp;gt;&amp;lt;/tt&amp;gt; instruction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[2]'''&amp;lt;/tt&amp;gt; &amp;lt;tt&amp;gt;&amp;lt;xsl:template&amp;gt;&amp;lt;/tt&amp;gt; directs the XSLT processor to generate the specified output whenever it encounters a &amp;lt;tt&amp;gt;&amp;lt;Reports&amp;gt;&amp;lt;/tt&amp;gt; element. This template will be called only once, since there's only one such element in the source document. It creates the outermost &amp;lt;tt&amp;gt;&amp;lt;svg&amp;gt;&amp;lt;/tt&amp;gt; element and a &amp;lt;tt&amp;gt;&amp;lt;defs&amp;gt;&amp;lt;/tt&amp;gt; element for later use.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[3]'''&amp;lt;/tt&amp;gt; After outputting the &amp;lt;tt&amp;gt;&amp;lt;svg&amp;gt;&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;&amp;lt;defs&amp;gt;&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;&amp;lt;xsl:apply-templates&amp;gt;&amp;lt;/tt&amp;gt; directs the processor to find any child &amp;lt;tt&amp;gt;&amp;lt;SYN&amp;gt;&amp;lt;/tt&amp;gt; elements and generate whatever its &amp;lt;tt&amp;gt;&amp;lt;xsl:template&amp;gt;&amp;lt;/tt&amp;gt; element specifies.&lt;br /&gt;
&lt;br /&gt;
And how is the &amp;lt;tt&amp;gt;&amp;lt;SYN&amp;gt;&amp;lt;/tt&amp;gt; element to be processed? Like this:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:template match=&amp;quot;SYN&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;amp;lt;!-- output the station name as a text element --&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;10&amp;quot; y=&amp;quot;20&amp;quot; style=&amp;quot;font-size: 10pt;&amp;quot;&amp;gt;&lt;br /&gt;
         '''&amp;lt;xsl:value-of select=&amp;quot;@SName&amp;quot;/&amp;gt;'''&lt;br /&gt;
     &amp;lt;/text&amp;gt;&lt;br /&gt;
     &lt;br /&gt;
     &amp;amp;lt;!-- process any child SYG elements --&amp;gt;&lt;br /&gt;
     '''&amp;lt;xsl:apply-templates select=&amp;quot;SYG&amp;quot;/&amp;gt;'''&lt;br /&gt;
 &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;xsl:value-of&amp;gt;&amp;lt;/tt&amp;gt; inserts the value of the selected item. The preceding &amp;lt;tt&amp;gt;@&amp;lt;/tt&amp;gt; indicates that we want the value of an attribute; in this case, the &amp;lt;tt&amp;gt;SName&amp;lt;/tt&amp;gt; attribute. We also want the timestamp from this element, but it requires special handling, so we'll come back to it later.&lt;br /&gt;
&lt;br /&gt;
The processor then finds all subordinate &amp;lt;tt&amp;gt;&amp;lt;SYG&amp;gt;&amp;lt;/tt&amp;gt; elements and processes them as our XSLT document specifies.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;&lt;br /&gt;
'''Note'''&lt;br /&gt;
&lt;br /&gt;
In this example, we've only used element and attribute names as the values of a &amp;lt;tt&amp;gt;match&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;select&amp;lt;/tt&amp;gt;. In reality, you can put any XPath expression as a value. XPath is a notation that lets you select parts of an XML document with extreme precision. For example, while processing an XHTML document, you could select only the odd &amp;lt;tt&amp;gt;&amp;amp;lt;td&amp;gt;&amp;lt;/tt&amp;gt; elements that are within &amp;lt;tt&amp;gt;&amp;amp;lt;tr&amp;gt;&amp;lt;/tt&amp;gt; elements that have been set &amp;lt;tt&amp;gt;align=&amp;quot;right&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The majority of the work needs to be done when we encounter the &amp;lt;tt&amp;gt;&amp;lt;SYG&amp;gt;&amp;lt;/tt&amp;gt; element, since it contains the temperature, wind, and visibility attributes. While it would be possible to output all the relevant SVG within one &amp;lt;tt&amp;gt;&amp;lt;xsl:template&amp;gt;&amp;lt;/tt&amp;gt;, a modular approach is easier to read and maintain. XSLT lets you create templates that act somewhat like functions; they don't correspond to any element in the source document, but you may explicitly call them by name and pass parameters to them. We take advantage of this in the following template:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:template match=&amp;quot;SYG&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;amp;lt;!-- pass the temperature to the thermometer --&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:call-template name=&amp;quot;draw-thermometer&amp;quot;&amp;gt;&lt;br /&gt;
         '''&amp;lt;xsl:with-param name=&amp;quot;t&amp;quot; select=&amp;quot;@T&amp;quot;/&amp;gt;'''&lt;br /&gt;
     &amp;lt;/xsl:call-template&amp;gt;&lt;br /&gt;
     &lt;br /&gt;
     &amp;amp;lt;!-- draw-wind needs wind speed and direction --&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:call-template name=&amp;quot;draw-wind&amp;quot;&amp;gt;&lt;br /&gt;
         '''&amp;lt;xsl:with-param name=&amp;quot;w&amp;quot; select=&amp;quot;@Wind&amp;quot;/&amp;gt;'''&lt;br /&gt;
     &amp;lt;/xsl:call-template&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
     &amp;amp;lt;!-- draw-visibility needs the value of the Vis attribute --&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:call-template name=&amp;quot;draw-visibility&amp;quot;&amp;gt;&lt;br /&gt;
         '''&amp;lt;xsl:with-param name=&amp;quot;v&amp;quot;&amp;gt;'''&lt;br /&gt;
 '''            &amp;lt;xsl:value-of select=&amp;quot;@Vis&amp;quot;/&amp;gt;'''&lt;br /&gt;
 '''        &amp;lt;/xsl:with-param&amp;gt;'''&lt;br /&gt;
     &amp;lt;/xsl:call-template&amp;gt;  &lt;br /&gt;
 &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If the value of a parameter is an attribute value, the easiest way to set it is with a &amp;lt;tt&amp;gt;select&amp;lt;/tt&amp;gt;. Another way to set the value is to put the content between a beginning and ending tag, as is shown in the third call.&lt;br /&gt;
&lt;br /&gt;
Now we can write the template for &amp;lt;tt&amp;gt;draw-thermometer&amp;lt;/tt&amp;gt;. We need to use the passed-in parameter to determine the height to fill the thermometer, and whether the thermometer should be filled with red or blue.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:template name=&amp;quot;draw-thermometer&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:param name=&amp;quot;t&amp;quot;&amp;gt;0&amp;lt;/xsl:param&amp;gt;     '''[1]'''&lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;height&amp;quot; select=&amp;quot;50-$t&amp;quot;/&amp;gt;      '''[2]'''&lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;tint&amp;quot;&amp;gt;     '''[3]'''&lt;br /&gt;
     &amp;lt;xsl:choose&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:when test=&amp;quot;$t &amp;amp;amp;gt; 0&amp;quot;&amp;gt;red&amp;lt;/xsl:when&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:otherwise&amp;gt;blue&amp;lt;/xsl:otherwise&amp;gt;&lt;br /&gt;
     &amp;lt;/xsl:choose&amp;gt;&lt;br /&gt;
     &amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;g id=&amp;quot;thermometer&amp;quot; transform=&amp;quot;translate(10, 40)&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;path&lt;br /&gt;
         d = &amp;quot;M 25 {$height} 25 90 A 10 10 0 1 0 35 90 L 35 {$height} Z&amp;quot;     '''[4]'''&lt;br /&gt;
         style=&amp;quot;stroke: none; fill: {$tint};&amp;quot;/&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
     &amp;lt;path d= &amp;quot;M 25 0 25 90 A 10 10 0 1 0 35 90 L 35 0 Z&amp;quot;&lt;br /&gt;
         style=&amp;quot;stroke: black; fill: none;&amp;quot;/&amp;gt;&lt;br /&gt;
         &lt;br /&gt;
     &amp;lt;g id=&amp;quot;thermometer-text&amp;quot;&lt;br /&gt;
         style=&amp;quot;font-size: 8pt; font-family: sans-serif;&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;text x=&amp;quot;20&amp;quot; y=&amp;quot;95&amp;quot; style=&amp;quot;text-anchor: end;&amp;quot;&amp;gt;-40&amp;lt;/text&amp;gt;&lt;br /&gt;
         &amp;lt;text x=&amp;quot;20&amp;quot; y=&amp;quot;55&amp;quot; style=&amp;quot;text-anchor: end;&amp;quot;&amp;gt;0&amp;lt;/text&amp;gt;&lt;br /&gt;
         &amp;lt;text x=&amp;quot;20&amp;quot; y=&amp;quot;5&amp;quot; style=&amp;quot;text-anchor: end;&amp;quot;&amp;gt;50&amp;lt;/text&amp;gt;&lt;br /&gt;
         &amp;lt;text x=&amp;quot;10&amp;quot; y=&amp;quot;110&amp;quot; style=&amp;quot;text-anchor: end;&amp;quot;&amp;gt;C&amp;lt;/text&amp;gt;&lt;br /&gt;
         &amp;lt;text x=&amp;quot;40&amp;quot; y=&amp;quot;95&amp;quot;&amp;gt;-40&amp;lt;/text&amp;gt;&lt;br /&gt;
         &amp;lt;text x=&amp;quot;40&amp;quot; y=&amp;quot;55&amp;quot;&amp;gt;32&amp;lt;/text&amp;gt;&lt;br /&gt;
         &amp;lt;text x=&amp;quot;40&amp;quot; y=&amp;quot;5&amp;quot;&amp;gt;120&amp;lt;/text&amp;gt;&lt;br /&gt;
         &amp;lt;text x=&amp;quot;50&amp;quot; y=&amp;quot;110&amp;quot;&amp;gt;F&amp;lt;/text&amp;gt;&lt;br /&gt;
         &amp;lt;text x=&amp;quot;30&amp;quot; y=&amp;quot;130&amp;quot; style=&amp;quot;text-anchor: middle;&amp;quot;&amp;gt;Temp.&amp;lt;/text&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
         &amp;lt;text x=&amp;quot;30&amp;quot; y=&amp;quot;145&amp;quot; style=&amp;quot;text-anchor: middle;&amp;quot;&amp;gt;     '''[5]'''&lt;br /&gt;
             &amp;lt;xsl:value-of select=&amp;quot;$t&amp;quot;/&amp;gt; /&lt;br /&gt;
             &amp;lt;xsl:value-of select=&amp;quot;round($t div 5 * 9 + 32)&amp;quot;/&amp;gt;&lt;br /&gt;
         &amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;/g&amp;gt;&lt;br /&gt;
 &amp;lt;/g&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[1]'''&amp;lt;/tt&amp;gt; You can specify the default value for a parameter if none is passed in.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[2]'''&amp;lt;/tt&amp;gt; XSLT lets you declare variables for use within a template. These are actually semi-variables; every time the template gets called, the variable will get set to an initial value, but for the duration of the template, it cannot be changed further. Note that XSLT can also do simple calculations such as the one shown in the &amp;lt;tt&amp;gt;select&amp;lt;/tt&amp;gt; attribute, which figures out the height to which the thermometer should be filled. When referring to a variable or parameter in an expression, precede its name with a &amp;lt;tt&amp;gt;$&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[3]'''&amp;lt;/tt&amp;gt; We must set the &amp;lt;tt&amp;gt;tint&amp;lt;/tt&amp;gt; variable conditionally. This is done with the &amp;lt;tt&amp;gt;&amp;lt;xsl:choose&amp;gt;&amp;lt;/tt&amp;gt; element, which contains one or more &amp;lt;tt&amp;gt;&amp;lt;xsl:when&amp;gt;&amp;lt;/tt&amp;gt; elements. The first one whose &amp;lt;tt&amp;gt;test&amp;lt;/tt&amp;gt; succeeds is the one whose output goes into the final document. The &amp;lt;tt&amp;gt;&amp;lt;xsl:otherwise&amp;gt;&amp;lt;/tt&amp;gt; element is a catch-all in case all the preceding tests fail.&lt;br /&gt;
&lt;br /&gt;
In the &amp;lt;tt&amp;gt;test&amp;lt;/tt&amp;gt;, we used the entity reference &amp;lt;tt&amp;gt;&amp;amp;amp;gt;&amp;lt;/tt&amp;gt; for a greater than symbol to avoid problems with some XSLT processors; if you ever use a less than it ''must'' be written as &amp;lt;tt&amp;gt;&amp;amp;amp;lt;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[4]'''&amp;lt;/tt&amp;gt; When referring to parameters or variables in the values of attributes of the output document, you must enclose them within curly braces. This particular &amp;lt;tt&amp;gt;&amp;lt;path&amp;gt;&amp;lt;/tt&amp;gt; draws the thermometer, filled to the proper height.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[5]'''&amp;lt;/tt&amp;gt; The &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;&amp;lt;/tt&amp;gt; elements preceding this one are all fixed; this one outputs the temperature in both degrees Celsius and degrees Fahrenheit. Note the use of &amp;lt;tt&amp;gt;div&amp;lt;/tt&amp;gt; for division in the formula; this is because the forward slash is already used in XPath to separate levels of element nesting.&lt;br /&gt;
&lt;br /&gt;
This would be a good time to test what we've done so far. Before we can test, we have to add four items to the stylesheet. The first two are empty templates to draw the wind compass and visibility bar; they'll be completed later. The third is an empty template to handle text nodes. XSLT processors are set up with default templates to ensure that they will visit all the elements and text in the source document. The default behavior is to send the text within elements directly to the destination document. In this transformation we want to throw away the text, so we construct an empty template for text nodes; they will not appear in the SVG file. Finally, we need the closing &amp;lt;tt&amp;gt;&amp;lt;/xsl:stylesheet&amp;gt;&amp;lt;/tt&amp;gt; tag.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:template name=&amp;quot;draw-wind&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;amp;lt;!-- watch this space --&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;xsl:template name=&amp;quot;draw-visibility&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;amp;lt;!-- to be determined --&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;xsl:template match=&amp;quot;text()&amp;quot;/&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:stylesheet&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On a Unix system, we invoke the Xalan processor from the command line with the following shell script. Xalan is the XSLT processor and Xerces is the XML parser. The resulting graphic, [[SVG Essentials/Generating SVG#svgess-CHP-12-FIG-4|Figure 12-4]], shows the station name and the thermometer.&lt;br /&gt;
&lt;br /&gt;
 java -cp /usr/local/xmljar/xalan.jar:\&lt;br /&gt;
 /usr/local/xmljar/xerces.jar\&lt;br /&gt;
 org.apache.xalan.xslt.Process&lt;br /&gt;
   -IN weather.xml -XSL omf.xsl -OUT weather.svg&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;svgess-CHP-12-FIG-4&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 12-4. XSL-generated SVG file showing thermometer'''&lt;br /&gt;
&lt;br /&gt;
[[Image:SVG Essentials/I_12_tt304.png|XSL-generated SVG file showing thermometer]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You have seen that XSLT can do simple arithmetic; it can also do a reasonable amount of string manipulation. Here is the XSLT to handle the drawing of the wind compass. It uses the &amp;lt;tt&amp;gt;substring-before&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;substring-after&amp;lt;/tt&amp;gt; functions to split the wind information into the parts that are needed for the drawing.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:template name=&amp;quot;draw-wind&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:param name=&amp;quot;w&amp;quot; select=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
     &lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;dir&amp;quot;      '''[1]'''&lt;br /&gt;
         select=&amp;quot;substring-before($w, ',')&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;speed&amp;quot;&lt;br /&gt;
         select=&amp;quot;substring-after($w, ',')&amp;quot;/&amp;gt;&lt;br /&gt;
         &lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;dir1&amp;quot;&amp;gt;     '''[2]'''&lt;br /&gt;
         &amp;lt;xsl:choose&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:when test=&amp;quot;contains($dir, '-')&amp;quot;&amp;gt;&lt;br /&gt;
             &amp;lt;xsl:value-of select=&amp;quot;number(substring-before($dir, &lt;br /&gt;
                 '-' ))-90&amp;quot;/&amp;gt;&lt;br /&gt;
         &amp;lt;/xsl:when&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:otherwise&amp;gt;&lt;br /&gt;
             &amp;lt;xsl:value-of select=&amp;quot;number($dir) - 90&amp;quot;/&amp;gt;&lt;br /&gt;
         &amp;lt;/xsl:otherwise&amp;gt;&lt;br /&gt;
         &amp;lt;/xsl:choose&amp;gt;&lt;br /&gt;
     &amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;dir2&amp;quot;&amp;gt;     '''[3]'''&lt;br /&gt;
         &amp;lt;xsl:choose&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:when test=&amp;quot;contains($dir, '-')&amp;quot;&amp;gt;&lt;br /&gt;
             &amp;lt;xsl:value-of select=&amp;quot;number(substring-after($dir, &lt;br /&gt;
                 '-' ))-90&amp;quot;/&amp;gt;&lt;br /&gt;
         &amp;lt;/xsl:when&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:otherwise&amp;gt;&lt;br /&gt;
             &amp;lt;xsl:value-of select=&amp;quot;number($dir) - 90&amp;quot;/&amp;gt;&lt;br /&gt;
         &amp;lt;/xsl:otherwise&amp;gt;&lt;br /&gt;
         &amp;lt;/xsl:choose&amp;gt;&lt;br /&gt;
     &amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;g id=&amp;quot;compass&amp;quot; font-size=&amp;quot;8pt&amp;quot; font-family=&amp;quot;sans-serif&amp;quot;&lt;br /&gt;
     transform=&amp;quot;translate(110, 70)&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;circle cx=&amp;quot;40&amp;quot; cy=&amp;quot;40&amp;quot; r=&amp;quot;30&amp;quot; style=&amp;quot;stroke: black; fill: none;&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;path&lt;br /&gt;
         d= &amp;quot;M 40 10 L 40 14&lt;br /&gt;
             M 70 40 L 66 40&lt;br /&gt;
             M 40 70 L 40 66&lt;br /&gt;
             M 10 40 L 14 40&amp;quot;&lt;br /&gt;
         style=&amp;quot;stroke: black; fill: none;&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;use transform=&amp;quot;rotate({$dir1},40,40)&amp;quot; xlink:href=&amp;quot;#wind-line&amp;quot;&amp;gt;     '''[4]'''&lt;br /&gt;
         &amp;lt;xsl:if test=&amp;quot;$dir1 != $dir2&amp;quot;&amp;gt;&lt;br /&gt;
             &amp;lt;xsl:attribute name=&amp;quot;stroke-dasharray&amp;quot;&amp;gt;3 3&amp;lt;/xsl:attribute&amp;gt;&lt;br /&gt;
         &amp;lt;/xsl:if&amp;gt;&lt;br /&gt;
     &amp;lt;/use&amp;gt;&lt;br /&gt;
     &amp;lt;use transform=&amp;quot;rotate({$dir2},40,40)&amp;quot; xlink:href=&amp;quot;#wind-line&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:if test=&amp;quot;$dir1 != $dir2&amp;quot;&amp;gt;&lt;br /&gt;
             &amp;lt;xsl:attribute name=&amp;quot;stroke-dasharray&amp;quot;&amp;gt;3 3&amp;lt;/xsl:attribute&amp;gt;&lt;br /&gt;
         &amp;lt;/xsl:if&amp;gt;&lt;br /&gt;
     &amp;lt;/use&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;40&amp;quot; y=&amp;quot;9&amp;quot; text-anchor=&amp;quot;middle&amp;quot;&amp;gt;N&amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;73&amp;quot; y=&amp;quot;44&amp;quot;&amp;gt;E&amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;40&amp;quot; y=&amp;quot;80&amp;quot; text-anchor=&amp;quot;middle&amp;quot;&amp;gt;S&amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;8&amp;quot; y=&amp;quot;44&amp;quot; text-anchor=&amp;quot;end&amp;quot;&amp;gt;W&amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;40&amp;quot; y=&amp;quot;100&amp;quot; text-anchor=&amp;quot;middle&amp;quot;&amp;gt;Wind (m/sec)&amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;40&amp;quot; y=&amp;quot;115&amp;quot; text-anchor=&amp;quot;middle&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:value-of select=&amp;quot;$speed&amp;quot;/&amp;gt;     '''[5]'''&lt;br /&gt;
     &amp;lt;/text&amp;gt;&lt;br /&gt;
 &amp;lt;/g&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[1]'''&amp;lt;/tt&amp;gt; This splits the wind information into a direction and speed by grabbing the substring before and after the separating comma.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[2]'''&amp;lt;/tt&amp;gt; If there is a hyphen in the direction, it must be split into two portions. This sets the first number, subtracting 90 degrees, since &amp;quot;north&amp;quot; is -90 degrees in SVG. If there's no hyphen, the first direction is simply offset by -90 degrees. The &amp;lt;tt&amp;gt;number&amp;lt;/tt&amp;gt; function ensures string data is converted to numeric form after stripping leading and trailing whitespace.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[3]'''&amp;lt;/tt&amp;gt; Similar code sets the second direction. You may wonder why we didn't use simpler code like this:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:choose&amp;gt;&lt;br /&gt;
 &amp;lt;xsl:when test=&amp;quot;contains($dir,'-')&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;dir1&amp;quot;&amp;gt; ... &amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;dir2&amp;quot;&amp;gt; ... &amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:when&amp;gt;&lt;br /&gt;
 &amp;lt;xsl:otherwise&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;dir1&amp;quot;&amp;gt; ... &amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;dir2&amp;quot;&amp;gt; ... &amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:otherwise&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:choose&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Because a variable exists only within its enclosing block, this code won't work — the starting &amp;lt;tt&amp;gt;&amp;lt;xsl:when&amp;gt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;lt;xsl:otherwise&amp;gt;&amp;lt;/tt&amp;gt; would create the variables, which would disppear immediately upon encountering the ending &amp;lt;tt&amp;gt;&amp;lt;/xsl:when&amp;gt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;lt;/xsl:otherwise&amp;gt;&amp;lt;/tt&amp;gt;. This is why we have to repeat all the choice code within the variable declarations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[4]'''&amp;lt;/tt&amp;gt; After the boilerplate that creates the circle and the hash marks, we draw both wind direction lines. If a range of wind directions was specified in the source file, in which case variables &amp;lt;tt&amp;gt;$dir1&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;$dir2&amp;lt;/tt&amp;gt; will be different, we want the direction lines to be dashed. We use an &amp;lt;tt&amp;gt;&amp;lt;xsl:if&amp;gt;&amp;lt;/tt&amp;gt; element to test if the directions are unequal. If so, the &amp;lt;tt&amp;gt;&amp;lt;xsl:attribute&amp;gt;&amp;lt;/tt&amp;gt; will add the named attribute, &amp;lt;tt&amp;gt;stroke-dasharray&amp;lt;/tt&amp;gt;, to the current element, and the &amp;lt;tt&amp;gt;&amp;lt;xsl:attribute&amp;gt;&amp;lt;/tt&amp;gt;'s content will become the value of that attribute. In this case, we'll add a &amp;lt;tt&amp;gt;stroke-dasharray&amp;lt;/tt&amp;gt; to the currently open &amp;lt;tt&amp;gt;&amp;lt;use&amp;gt;&amp;lt;/tt&amp;gt; element and give it a value of &amp;lt;tt&amp;gt;3 3&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
If the directions are the same, the &amp;lt;tt&amp;gt;&amp;lt;xsl:if&amp;gt;&amp;lt;/tt&amp;gt; element does nothing, and we get the same solid line drawn twice.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[5]'''&amp;lt;/tt&amp;gt; After the boilerplate text, we insert the wind speed.&lt;br /&gt;
&lt;br /&gt;
Now we construct the XSLT commands to draw the visibility bar. We want to treat numbers greater than 40,000 as infinity, and we must also handle the special case of the word &amp;lt;tt&amp;gt;INF&amp;lt;/tt&amp;gt; as a value for the visibility. This requires a three-way choice for an &amp;lt;tt&amp;gt;&amp;lt;xsl:choose&amp;gt;&amp;lt;/tt&amp;gt; element to set the value of the &amp;lt;tt&amp;gt;width&amp;lt;/tt&amp;gt; for the rectangle that will be drawn in green.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:template name=&amp;quot;draw-visibility&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:param name=&amp;quot;v&amp;quot;&amp;gt;0&amp;lt;/xsl:param&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;width&amp;quot;&amp;gt;     '''[1]'''&lt;br /&gt;
         &amp;lt;xsl:choose&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:when test=&amp;quot;$v = 'INF'&amp;quot;&amp;gt;100&amp;lt;/xsl:when&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:when test=&amp;quot;$v &amp;amp;amp;gt; 40000&amp;quot;&amp;gt;100&amp;lt;/xsl:when&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:otherwise&amp;gt;&lt;br /&gt;
             &amp;lt;xsl:value-of select=&amp;quot;$v * 100.0 div 40000.0&amp;quot;/&amp;gt;&lt;br /&gt;
         &amp;lt;/xsl:otherwise&amp;gt;&lt;br /&gt;
         &amp;lt;/xsl:choose&amp;gt;&lt;br /&gt;
     &amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;
 &amp;lt;g id=&amp;quot;visbar&amp;quot; transform=&amp;quot;translate(220,110)&amp;quot; &lt;br /&gt;
     font-size=&amp;quot;8pt&amp;quot; text-anchor=&amp;quot;middle&amp;quot;&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
     &lt;br /&gt;
     &amp;lt;rect fill=&amp;quot;green&amp;quot; stroke=&amp;quot;none&amp;quot;&lt;br /&gt;
         x=&amp;quot;0&amp;quot; y=&amp;quot;0&amp;quot; width=&amp;quot;{$width}&amp;quot; height=&amp;quot;20&amp;quot;/&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
     &lt;br /&gt;
     &amp;lt;rect x=&amp;quot;0&amp;quot; y=&amp;quot;0&amp;quot; width=&amp;quot;100&amp;quot; height=&amp;quot;20&amp;quot; stroke=&amp;quot;black&amp;quot; fill=&amp;quot;none&amp;quot;/&amp;gt;&lt;br /&gt;
     &lt;br /&gt;
     &amp;lt;path fill=&amp;quot;none&amp;quot; stroke=&amp;quot;black&amp;quot;&lt;br /&gt;
         d=&amp;quot;M 25 20 L 25 25 M 50 20 L 50 25 M 75 20 L 75 25&amp;quot;/&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
     &amp;lt;text x=&amp;quot;0&amp;quot; y=&amp;quot;35&amp;quot;&amp;gt;0&amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;25&amp;quot; y=&amp;quot;35&amp;quot;&amp;gt;10&amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;50&amp;quot; y=&amp;quot;35&amp;quot;&amp;gt;20&amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;75&amp;quot; y=&amp;quot;35&amp;quot;&amp;gt;30&amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;100&amp;quot; y=&amp;quot;35&amp;quot;&amp;gt;40+&amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;50&amp;quot; y=&amp;quot;60&amp;quot;&amp;gt;&lt;br /&gt;
         Visibility (km)&lt;br /&gt;
     &amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;text x=&amp;quot;50&amp;quot; y=&amp;quot;75&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:value-of select=&amp;quot;format-number($v div 1000.0,'0.###')&amp;quot;/&amp;gt;     '''[2]'''&lt;br /&gt;
     &amp;lt;/text&amp;gt;&lt;br /&gt;
 &amp;lt;/g&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[1]'''&amp;lt;/tt&amp;gt; Setting the width of the area to be filled requires a three-way choice; the visibility could be the literal &amp;lt;tt&amp;gt;INF&amp;lt;/tt&amp;gt;, a number greater than 40,000, or some other number. This &amp;lt;tt&amp;gt;&amp;lt;xsl:choose&amp;gt;&amp;lt;/tt&amp;gt; scales the visibility to a maximum width of 100 for the fill.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;'''[2]'''&amp;lt;/tt&amp;gt; The visibility is in meters, but we want to show it in kilometers. To show it cleanly, we use the &amp;lt;tt&amp;gt;format-number&amp;lt;/tt&amp;gt; function, which takes two parameters: the number to format and the formatting string. The formatting string used here says to print the integer part, even if it is zero, followed by at most three decimal places. Trailing zeroes will not be displayed.&lt;br /&gt;
&lt;br /&gt;
Given these specifications, the weather report in [[SVG Essentials/Generating SVG#svgess-CHP-12-FIG-5|Figure 12-5]] is taking shape nicely, but it is still missing the date and time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;svgess-CHP-12-FIG-5&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 12-5. XSLT-generated SVG file without time data'''&lt;br /&gt;
&lt;br /&gt;
[[Image:SVG Essentials/I_12_tt308.png|XSLT-generated SVG file without time data]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Extending XSLT in Java ===&lt;br /&gt;
&lt;br /&gt;
While XSLT contains some arithmetic operations and string functions, they are nowhere near powerful enough to handle timestamp conversion into the hour and minute of the day, much less a nicely formatted date string. Luckily, it is possible to write extensions to XSLT to handle such tasks. You may write extensions in Java, JavaScript, NetRexx, JPython (the Java version of Python), PerlScript, or any other language that supports the Bean Scripting Framework. For full details, see ''http://xml.apache.org/xalan-j/extensions.html''. Since Xalan is our tool of choice, and it is written in Java, we'll write this extension in Java.&lt;br /&gt;
&lt;br /&gt;
To use an extension written in Java, you must add the text shown in boldface to the root element of the XSLT stylesheet. The first line associates the &amp;lt;tt&amp;gt;java&amp;lt;/tt&amp;gt; namespace with calls to Java extensions. The second line says that XSLT doesn't have to attach that namespace to any tags it generates.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
&amp;lt;xsl:stylesheet version=&amp;quot;1.0&amp;quot;&lt;br /&gt;
   xmlns:xsl=&amp;quot;http://www.w3.org/1999/XSL/Transform&amp;quot;  &lt;br /&gt;
   &amp;lt;/nowiki&amp;gt;'''&amp;lt;nowiki&amp;gt;xmlns:java=&amp;quot;http://xml.apache.org/xslt/java&amp;quot;&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
 '''   exclude-result-prefixes=&amp;quot;java&amp;quot;'''&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We then write a class with static methods that take a timestamp as input and return the information we need. Since the hour and minute will only be used in a numeric context, we return them as &amp;lt;tt&amp;gt;Double&amp;lt;/tt&amp;gt;. The following code is totally unsurprising; the only &amp;quot;gotcha&amp;quot; is that the OMF timestamp is measured in seconds since 1 January 1970, and Java's time and date methods are designed to work with time measured in ''milliseconds'' since 1 January 1970.&lt;br /&gt;
&lt;br /&gt;
If you want to put your functions into a package, you may do so. You are not restricted to static methods, either. An extension may create an instance of a Java object and return it to be stored in an XSLT variable.&lt;br /&gt;
&lt;br /&gt;
 import java.util.Calendar;&lt;br /&gt;
 import java.util.Date;&lt;br /&gt;
 import java.text.DateFormat;&lt;br /&gt;
 &lt;br /&gt;
 public class TimeStampUtils&lt;br /&gt;
 {&lt;br /&gt;
     public static String getDate(String timeStampString)&lt;br /&gt;
     {&lt;br /&gt;
         DateFormat d = DateFormat.getDateInstance();&lt;br /&gt;
         long milliseconds = Long.parseLong( timeStampString ) * 1000;&lt;br /&gt;
         return &lt;br /&gt;
             d.format(new Date(milliseconds));&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     public static Double getHour(String timeStampString)&lt;br /&gt;
     {&lt;br /&gt;
         long milliseconds = Long.parseLong( timeStampString ) * 1000;&lt;br /&gt;
         Calendar c = Calendar.getInstance();&lt;br /&gt;
         c.setTime( new Date( milliseconds ) );&lt;br /&gt;
         return new Double( c.get( Calendar.HOUR_OF_DAY ) );&lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     public static Double getMinute(String timeStampString)&lt;br /&gt;
     {&lt;br /&gt;
         long milliseconds = Long.parseLong( timeStampString ) * 1000;&lt;br /&gt;
         Calendar c = Calendar.getInstance();&lt;br /&gt;
         c.setTime( new Date( milliseconds ) );&lt;br /&gt;
         return new Double( c.get( Calendar.MINUTE ) );&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
To call one of these methods from XSLT, you give the namespace — in this case &amp;lt;tt&amp;gt;java:&amp;lt;/tt&amp;gt; — followed by the fully qualified name of the method you wish to call. To retrieve the date string associated with the timestamp, we add the code in boldface to the definition of the &amp;lt;tt&amp;gt;&amp;lt;SYN&amp;gt;&amp;lt;/tt&amp;gt; template. We also retrieve the hour and minute, and pass them to a template that will display the time as text and also draw an analog clock face.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:template match=&amp;quot;SYN&amp;quot;&amp;gt;&lt;br /&gt;
     '''&amp;lt;xsl:variable name=&amp;quot;tstamp&amp;quot; select=&amp;quot;@TStamp&amp;quot;/&amp;gt;'''&lt;br /&gt;
     &amp;lt;text font-size=&amp;quot;10pt&amp;quot; x=&amp;quot;10&amp;quot; y=&amp;quot;20&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:value-of select=&amp;quot;@SName&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;/text&amp;gt;&lt;br /&gt;
     &amp;lt;text font-size=&amp;quot;10pt&amp;quot; x=&amp;quot;345&amp;quot; y=&amp;quot;20&amp;quot; text-anchor=&amp;quot;end&amp;quot;&amp;gt;&lt;br /&gt;
         '''&amp;lt;xsl:value-of select=&amp;quot;java:TimeStampUtils.getDate( $tstamp )&amp;quot;/&amp;gt;'''&lt;br /&gt;
     &amp;lt;/text&amp;gt;&lt;br /&gt;
     &lt;br /&gt;
     '''&amp;lt;xsl:call-template name=&amp;quot;draw-time-and-clock&amp;quot;&amp;gt;'''&lt;br /&gt;
 '''        &amp;lt;xsl:with-param name=&amp;quot;hour&amp;quot;'''&lt;br /&gt;
 '''            select=&amp;quot;java:TimeStampUtils.getHour( $tstamp )&amp;quot;/&amp;gt;'''&lt;br /&gt;
 '''        &amp;lt;xsl:with-param name=&amp;quot;minute&amp;quot;'''&lt;br /&gt;
 '''            select=&amp;quot;java:TimeStampUtils.getMinute( $tstamp )&amp;quot;/&amp;gt;'''&lt;br /&gt;
 '''    &amp;lt;/xsl:call-template&amp;gt;'''&lt;br /&gt;
     &lt;br /&gt;
     &amp;lt;xsl:apply-templates select=&amp;quot;SYG&amp;quot;/&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, here is the template for drawing the time and clock. The only new item here is the &amp;lt;tt&amp;gt;&amp;lt;xsl:text&amp;gt;&amp;lt;/tt&amp;gt; element. Its contents, which must be pure text, are placed into the output document verbatim. We're using it here to avoid problems with whitespace. If the boldface line in the following listing had been simply the colon that separates the minutes and hours, the leading tab on that line and the next one would have made their way into the resultant SVG &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;&amp;lt;/tt&amp;gt; element, which would have produced extra space around the colon in the final graphic.&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;xsl:template name=&amp;quot;draw-time-and-clock&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:param name=&amp;quot;hour&amp;quot;&amp;gt;0&amp;lt;/xsl:param&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:param name=&amp;quot;minute&amp;quot;&amp;gt;0&amp;lt;/xsl:param&amp;gt;&lt;br /&gt;
     &lt;br /&gt;
     &amp;amp;lt;!-- clock face is light yellow from 6 AM to 6 PM, otherwise light &lt;br /&gt;
         blue --&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;tint&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:choose&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:when test=&amp;quot;$hour &amp;amp;amp;gt; 6 and $hour &amp;amp;amp;lt; 18&amp;quot;&amp;gt;#ffffcc&amp;lt;/xsl:when&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:otherwise&amp;gt;#ccccff&amp;lt;/xsl:otherwise&amp;gt;&lt;br /&gt;
         &amp;lt;/xsl:choose&amp;gt;&lt;br /&gt;
     &amp;lt;/xsl:variable&amp;gt;&lt;br /&gt;
     &lt;br /&gt;
     &amp;amp;lt;!-- calculate angles for hour and minute hand of analog clock --&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;hourAngle&amp;quot;&lt;br /&gt;
         select=&amp;quot;(30 * ($hour mod 12 + $minute div 60)) - 90&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;xsl:variable name=&amp;quot;minuteAngle&amp;quot;&lt;br /&gt;
         select=&amp;quot;($minute * 6) - 90&amp;quot;/&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 &amp;lt;text x=&amp;quot;345&amp;quot; y=&amp;quot;40&amp;quot; style=&amp;quot;font-size: 10pt; text-anchor: end;&amp;quot;&amp;gt;&lt;br /&gt;
         &amp;lt;xsl:value-of select=&amp;quot;$hour&amp;quot;/&amp;gt;&lt;br /&gt;
         '''&amp;lt;xsl:text&amp;gt;:&amp;lt;/xsl:text&amp;gt;'''&lt;br /&gt;
         &amp;lt;xsl:value-of select=&amp;quot;format-number($minute,'00')&amp;quot;/&amp;gt;&lt;br /&gt;
 &amp;lt;/text&amp;gt;&lt;br /&gt;
 &amp;lt;text font-size=&amp;quot;10pt&amp;quot; x=&amp;quot;345&amp;quot; y=&amp;quot;60&amp;quot; text-anchor=&amp;quot;end&amp;quot;&amp;gt;&lt;br /&gt;
 GMT&lt;br /&gt;
 &amp;lt;/text&amp;gt;&lt;br /&gt;
 &amp;lt;g id=&amp;quot;clock&amp;quot; transform=&amp;quot;translate(255, 30)&amp;quot;&amp;gt;&lt;br /&gt;
     &amp;lt;circle cx=&amp;quot;20&amp;quot; cy=&amp;quot;20&amp;quot; r=&amp;quot;20&amp;quot;&lt;br /&gt;
         style=&amp;quot;fill: {$tint}; stroke: black;&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;line transform=&amp;quot;rotate({$minuteAngle}, 20, 20)&amp;quot;&lt;br /&gt;
         x1=&amp;quot;20&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;38&amp;quot; y2=&amp;quot;20&amp;quot; style=&amp;quot;stroke: black;&amp;quot;/&amp;gt;&lt;br /&gt;
     &amp;lt;line transform=&amp;quot;rotate({$hourAngle}, 20, 20)&amp;quot;&lt;br /&gt;
         x1=&amp;quot;20&amp;quot; y1=&amp;quot;20&amp;quot; x2=&amp;quot;33&amp;quot; y2=&amp;quot;20&amp;quot; style=&amp;quot;stroke: black;&amp;quot;/&amp;gt;&lt;br /&gt;
 &amp;lt;/g&amp;gt;&lt;br /&gt;
 &amp;lt;/xsl:template&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When you run this transformation, the classpath that you give to Xalan must include the directory where your class file lives. In this case, it's in the same directory as the OMF file and XSL file, so we changed the script to include &amp;lt;tt&amp;gt;.&amp;lt;/tt&amp;gt; in the classpath:&lt;br /&gt;
&lt;br /&gt;
 java -cp /usr/local/xmljar/xalan.jar:\&lt;br /&gt;
 /usr/local/xmljar/xerces.jar:\&lt;br /&gt;
 .\&lt;br /&gt;
 org.apache.xalan.xslt.Process\&lt;br /&gt;
   -IN weather.xml -XSL omf.xsl -OUT weather.svg&lt;br /&gt;
&lt;br /&gt;
Putting this all together produces [[SVG Essentials/Generating SVG#svgess-CHP-12-FIG-6|Figure 12-6]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;svgess-CHP-12-FIG-6&amp;quot;&amp;gt;&lt;br /&gt;
'''Figure 12-6. XSLT-generated SVG file showing complete data'''&lt;br /&gt;
&lt;br /&gt;
[[Image:SVG Essentials/I_12_tt314.png|XSLT-generated SVG file showing complete data]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There is room for improvement in this XSLT file. Few people are interested in the four-letter station code that precedes the station name; it should be eliminated. If the temperatures are outside the range of -40 to 50 degrees Celsius, as frequently happens in desert areas or in Antarctica, the thermometer will be filled improperly. If any of the attributes is missing from the original OMF file, bad things will happen. Numeric operations on the null string result in a value called &amp;quot;not a number,&amp;quot; which displays as &amp;lt;tt&amp;gt;NaN&amp;lt;/tt&amp;gt; in text, and will cause SVG errors if inserted into a path's description. Finally, if there is more than one &amp;lt;tt&amp;gt;&amp;lt;SYN&amp;gt;&amp;lt;/tt&amp;gt; element in the document, the XSLT will generate multiple SVG descriptions of thermometers, compasses, and visibility bars one on top of the other.&lt;br /&gt;
&lt;br /&gt;
These corrections and any improvements to the output are left for the astute reader, who has been sufficiently astute to purchase ''XSLT'' by Doug Tidwell, published by O'Reilly &amp;amp; Associates. Chapter 8 of that marvelous book also contains an example of using XSLT to generate SVG from an XML file that is far better-behaved than the one we've used here. If you're serious about XML, you would be well advised to have this book on your shelf.&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references/&amp;gt;&lt;/div&gt;</description>
			<pubDate>Tue, 04 Mar 2008 22:37:00 GMT</pubDate>			<dc:creator>Docbook2Wiki</dc:creator>			<comments>http://commons.oreilly.com/wiki/index.php/Talk:SVG_Essentials/Generating_SVG</comments>		</item>
	</channel>
</rss>