// 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 } }