// NAnt - A .NET build tool
// Copyright (C) 2001 Gerry Shaw
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// Serge (serge@wildwestsoftware.com)
// Gerry Shaw (gerry_shaw@yahoo.com)
using System;
using System.IO;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;
using System.Collections;
using System.Text.RegularExpressions;
using SourceForge.NAnt.Attributes;
namespace SourceForge.NAnt.Tasks {
///
/// Process a document via XSLT.
/// This is useful for building views of XML based documentation, or in generating code.
///
///
/// Create a report in HTML.
/// <style style="report.xsl" in="data.xml" out="report.html" />
///
[TaskName("style")]
public class StyleTask : Task {
string _baseDir = null;
string _destDir = null;
string _extension = "html";
string _xsltFile = null;
string _srcFile = null;
string _outputFile = null;
Hashtable _params = new Hashtable(); // TODO sort this out with an attribute
/// Where to find the source XML file, default is the project's basedir.
[TaskAttribute("basedir", Required=false)]
public string BaseDir { get { return _baseDir; } set { _baseDir = value; } }
/// Directory in which to store the results.
[TaskAttribute("destdir", Required=false)]
public string DestDir { get { return _destDir; } set { _destDir = value; } }
/// Desired file extension to be used for the targets. The default is "html".
[TaskAttribute("extension", Required=false)]
public string Extension { get { return _extension; } set { _extension = value; } }
/// Name of the stylesheet to use - given either relative to the project's basedir or as an absolute path.
[TaskAttribute("style", Required=true)]
public string StyleSheet { get { return _xsltFile; } set { _xsltFile = value; } }
/// Specifies a single XML document to be styled. Should be used with the out attribute.
[TaskAttribute("in", Required=true)]
public string SrcFile { get { return _srcFile; } set { _srcFile = value; } }
/// Specifies the output name for the styled result from the in attribute.
[TaskAttribute("out", Required=false)]
public string OutputFile { get { return _outputFile; } set { _outputFile = value; } }
XmlReader CreateXmlReader(string file) {
XmlTextReader xmlReader = new XmlTextReader(new FileStream(file, FileMode.Open));
return xmlReader;
}
TextWriter CreateWriter(string filepath) {
string xmlPath = filepath;
TextWriter writer = null;
string targetDir = Path.GetDirectoryName(Path.GetFullPath(xmlPath));
if (targetDir != null && targetDir != "" && !Directory.Exists(targetDir)) {
Directory.CreateDirectory(targetDir);
}
// UTF-8 encoding will be used
//xmlWriter = new XmlTextWriter(xmlPath, null);
// Create text writer first
writer = new StreamWriter(xmlPath);
return writer;
}
/// taskNode used to define this task instance
protected override void InitializeTask(XmlNode taskNode) {
// Load parameters
foreach (XmlNode node in taskNode) {
if(node.Name.Equals("param")) {
string paramname = node.Attributes["name"].Value;
string paramval = node.Attributes["expression"].Value;
_params[paramname] = paramval;
}
}
}
protected override void ExecuteTask() {
string destFile = OutputFile;
// TODO handle filesets
if (destFile == null || destFile == "") {
// TODO: use System.IO.Path (gs)
// append extension if necessary
string ext = Extension[0]=='.'
? Extension
: "." + Extension;
int extPos = SrcFile.LastIndexOf('.');
if (extPos == -1) {
destFile = SrcFile + ext;
} else {
destFile = SrcFile.Substring(0, extPos) + ext;
}
}
string basedirPath = Project.GetFullPath(BaseDir);
string destdirPath = Project.GetFullPath(DestDir);
string srcPath = Path.GetFullPath(Path.Combine(basedirPath, SrcFile));
string xsltPath = Path.GetFullPath(Path.Combine(basedirPath, StyleSheet));
string destPath = Path.GetFullPath(Path.Combine(destdirPath, destFile));
FileInfo srcInfo = new FileInfo(srcPath);
FileInfo destInfo = new FileInfo(destPath);
FileInfo xsltInfo = new FileInfo(xsltPath);
if (!srcInfo.Exists) {
string msg = String.Format("Unable to find source XML file {0}", srcPath);
throw new BuildException(msg, Location);
}
if (!xsltInfo.Exists) {
string msg = String.Format("Unable to find stylesheet file {0}", xsltPath);
throw new BuildException(msg, Location);
}
bool destOutdated = !destInfo.Exists
|| srcInfo.LastWriteTime > destInfo.LastWriteTime
|| xsltInfo.LastWriteTime > destInfo.LastWriteTime;
if (destOutdated) {
XmlReader xmlReader = null;
XmlReader xslReader = null;
TextWriter writer = null;
try {
xmlReader = CreateXmlReader(srcPath);
xslReader = CreateXmlReader(xsltPath);
writer = CreateWriter(destPath);
if (Verbose) {
Log.WriteLine(LogPrefix + "Transforming into " + destdirPath );
}
XslTransform xslt = new XslTransform();
XPathDocument xml = new XPathDocument(xmlReader);
XsltArgumentList scriptargs = new XsltArgumentList();
if (Verbose) {
Log.WriteLine(LogPrefix + "Loading stylesheet " + Path.GetFullPath(xsltPath));
}
xslt.Load(xslReader);
// Load paramaters
foreach (string key in _params.Keys) {
scriptargs.AddParam(key, "", (string) _params[key]);
}
Log.WriteLine(LogPrefix + "Processing " + Path.GetFullPath(srcPath) + " to " + Path.GetFullPath(destPath));
xslt.Transform(xml, scriptargs, writer);
} catch (Exception e) {
throw new BuildException("Could not perform XSLT transformation.", Location, e);
} finally {
// Ensure file handles are closed
if (xmlReader != null) { xmlReader.Close(); }
if (xslReader != null) { xslReader.Close(); }
if (writer != null) { writer.Close(); }
}
}
}
}
}