// NAnt - A .NET build tool
// Copyright (C) 2001-2003 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
//
// Ian McLean (ianm@activestate.com)
// Mitch Denny (mitch.denny@monash.net)
using System;
using System.Globalization;
using System.IO;
using System.Xml;
using NAnt.Core;
using NAnt.Core.Attributes;
using NAnt.Core.Types;
using NAnt.Core.Util;
namespace NAnt.Core.Tasks {
///
/// Extracts text from an XML file at the location specified by an XPath
/// expression.
///
///
///
/// If the XPath expression specifies multiple nodes the node index is used
/// to determine which of the nodes' text is returned.
///
///
///
///
/// The example provided assumes that the following XML file (App.config)
/// exists in the current build directory.
///
///
///
///
///
///
///
///
/// ]]>
///
///
///
///
/// The example will read the server value from the above
/// configuration file.
///
///
///
///
///
///
///
/// ]]>
///
///
[TaskName("xmlpeek")]
public class XmlPeekTask : Task {
#region Private Instance Fields
private FileInfo _xmlFile;
private int _nodeIndex = 0;
private string _property;
private string _xPath;
private XmlNamespaceCollection _namespaces = new XmlNamespaceCollection();
#endregion Private Instance Fields
#region Public Instance Properties
///
/// The name of the file that contains the XML document
/// that is going to be peeked at.
///
[TaskAttribute("file", Required=true)]
public FileInfo XmlFile {
get { return _xmlFile; }
set { _xmlFile = value; }
}
///
/// The index of the node that gets its text returned when the query
/// returns multiple nodes.
///
[TaskAttribute("nodeindex", Required=false)]
[Int32Validator(0, Int32.MaxValue)]
public int NodeIndex {
get { return _nodeIndex; }
set { _nodeIndex = value; }
}
///
/// The property that receives the text representation of the XML inside
/// the node returned from the XPath expression.
///
[TaskAttribute("property", Required=true)]
[StringValidator(AllowEmpty=false)]
public string Property {
get { return _property; }
set { _property = value; }
}
///
/// The XPath expression used to select which node to read.
///
[TaskAttribute("xpath", Required=true)]
[StringValidator(AllowEmpty=false)]
public string XPath {
get { return _xPath; }
set { _xPath = value; }
}
///
/// Namespace definitions to resolve prefixes in the XPath expression.
///
[BuildElementCollection("namespaces", "namespace")]
public XmlNamespaceCollection Namespaces {
get { return _namespaces; }
set { _namespaces = value; }
}
#endregion Public Instance Properties
#region Override implementation of Task
///
/// Executes the XML peek task.
///
protected override void ExecuteTask() {
Log(Level.Info, "Peeking at '{0}' with XPath expression '{1}'.",
XmlFile.FullName, XPath);
// ensure the specified xml file exists
if (!XmlFile.Exists) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA1154"), XmlFile.FullName), Location);
}
try {
XmlDocument document = LoadDocument(XmlFile.FullName);
Properties[Property] = GetNodeContents(XPath, document, NodeIndex);
} catch (BuildException ex) {
throw ex; // Just re-throw the build exceptions.
} catch (Exception ex) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA1153"), XmlFile.FullName),
Location, ex);
}
}
#endregion Override implementation of Task
#region private Instance Methods
///
/// Loads an XML document from a file on disk.
///
/// The file name of the file to load the XML document from.
///
/// A document containing
/// the document object representing the file.
///
private XmlDocument LoadDocument(string fileName) {
XmlDocument document = null;
try {
document = new XmlDocument();
document.Load(fileName);
return document;
} catch (Exception ex) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA1158"), fileName), Location,
ex);
}
}
///
/// Gets the contents of the node specified by the XPath expression.
///
/// The XPath expression used to determine which nodes to choose from.
/// The XML document to select the nodes from.
/// The node index in the case where multiple nodes satisfy the expression.
///
/// The contents of the node specified by the XPath expression.
///
private string GetNodeContents(string xpath, XmlDocument document, int nodeIndex ) {
string contents = null;
XmlNodeList nodes;
try {
XmlNamespaceManager nsMgr = new XmlNamespaceManager(document.NameTable);
foreach (XmlNamespace xmlNamespace in Namespaces) {
if (xmlNamespace.IfDefined && !xmlNamespace.UnlessDefined) {
nsMgr.AddNamespace(xmlNamespace.Prefix, xmlNamespace.Uri);
}
}
nodes = document.SelectNodes(xpath, nsMgr);
} catch (Exception ex) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA1155"), xpath),
Location, ex);
}
if (nodes == null || nodes.Count == 0) {
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA1156"), xpath),
Location);
}
Log(Level.Info, "Found '{0}' nodes with the XPath expression '{1}'.",
nodes.Count, xpath);
if (nodeIndex >= nodes.Count){
throw new BuildException(string.Format(CultureInfo.InvariantCulture,
ResourceUtils.GetString("NA1157"), nodeIndex), Location);
}
XmlNode selectedNode = nodes[nodeIndex];
contents = selectedNode.InnerXml;
return contents;
}
#endregion private Instance Methods
}
}