Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDean Ellis <dellis1972@googlemail.com>2015-11-26 13:49:35 +0300
committerDean Ellis <dellis1972@googlemail.com>2015-11-26 14:29:30 +0300
commit86522f62f00587281dbb7a51aa44d3175f33d8b1 (patch)
tree9cbb7b960d2214fc3ad4f6981d43c000f11a43f7 /mcs/class/Microsoft.Build.Tasks
parent8327116c331f6dd9591f482766da2e9e877fec11 (diff)
[msbuild] Added XmlPeek
XmlPeek was missing from Mono. Adding it based on the open source msbuild implementation with a few minor changes because of missing support classes.
Diffstat (limited to 'mcs/class/Microsoft.Build.Tasks')
-rw-r--r--mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_5.csproj1
-rw-r--r--mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_x.csproj1
-rw-r--r--mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-xbuild_12.csproj1
-rw-r--r--mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks.dll.sources1
-rw-r--r--mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/XmlPeek.cs371
5 files changed, 375 insertions, 0 deletions
diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_5.csproj b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_5.csproj
index dac54afb509..9918829d3ad 100644
--- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_5.csproj
+++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_5.csproj
@@ -162,6 +162,7 @@
<Compile Include="Microsoft.Build.Tasks\Warning.cs" />
<Compile Include="Microsoft.Build.Tasks\WriteCodeFragment.cs" />
<Compile Include="Microsoft.Build.Tasks\WriteLinesToFile.cs" />
+ <Compile Include="Microsoft.Build.Tasks\XmlPeek.cs" />
<Compile Include="Mono.XBuild.Tasks.GenerateResourceInternal\PoResourceReader.cs" />
<Compile Include="Mono.XBuild.Tasks.GenerateResourceInternal\PoResourceWriter.cs" />
<Compile Include="Mono.XBuild.Tasks.GenerateResourceInternal\TxtResourceReader.cs" />
diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_x.csproj b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_x.csproj
index a3479d79693..9bd62c80a9d 100644
--- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_x.csproj
+++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-net_4_x.csproj
@@ -162,6 +162,7 @@
<Compile Include="Microsoft.Build.Tasks\Warning.cs" />
<Compile Include="Microsoft.Build.Tasks\WriteCodeFragment.cs" />
<Compile Include="Microsoft.Build.Tasks\WriteLinesToFile.cs" />
+ <Compile Include="Microsoft.Build.Tasks\XmlPeek.cs" />
<Compile Include="Mono.XBuild.Tasks.GenerateResourceInternal\PoResourceReader.cs" />
<Compile Include="Mono.XBuild.Tasks.GenerateResourceInternal\PoResourceWriter.cs" />
<Compile Include="Mono.XBuild.Tasks.GenerateResourceInternal\TxtResourceReader.cs" />
diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-xbuild_12.csproj b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-xbuild_12.csproj
index 92566e79f64..642da43767b 100644
--- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-xbuild_12.csproj
+++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks-xbuild_12.csproj
@@ -159,6 +159,7 @@
<Compile Include="Microsoft.Build.Tasks\VCBuild.cs" />
<Compile Include="Microsoft.Build.Tasks\Warning.cs" />
<Compile Include="Microsoft.Build.Tasks\WriteLinesToFile.cs" />
+ <Compile Include="Microsoft.Build.Tasks\XmlPeek.cs" />
<Compile Include="Mono.XBuild.Tasks.GenerateResourceInternal\PoResourceReader.cs" />
<Compile Include="Mono.XBuild.Tasks.GenerateResourceInternal\PoResourceWriter.cs" />
<Compile Include="Mono.XBuild.Tasks.GenerateResourceInternal\TxtResourceReader.cs" />
diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks.dll.sources b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks.dll.sources
index 2261d7af65e..8830df5151b 100644
--- a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks.dll.sources
+++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks.dll.sources
@@ -112,6 +112,7 @@ Microsoft.Build.Tasks/VCBuild.cs
Microsoft.Build.Tasks/Warning.cs
Microsoft.Build.Tasks/WriteCodeFragment.cs
Microsoft.Build.Tasks/WriteLinesToFile.cs
+Microsoft.Build.Tasks/XmlPeek.cs
Mono.XBuild.Tasks.GenerateResourceInternal/PoResourceReader.cs
Mono.XBuild.Tasks.GenerateResourceInternal/PoResourceWriter.cs
Mono.XBuild.Tasks.GenerateResourceInternal/TxtResourceReader.cs
diff --git a/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/XmlPeek.cs b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/XmlPeek.cs
new file mode 100644
index 00000000000..1e8cc21d4f3
--- /dev/null
+++ b/mcs/class/Microsoft.Build.Tasks/Microsoft.Build.Tasks/XmlPeek.cs
@@ -0,0 +1,371 @@
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//-----------------------------------------------------------------------
+// </copyright>
+// <summary>Returns the value specified by XPath.</summary>
+//-----------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Security;
+using System.Security.Permissions;
+using System.Text;
+using System.Xml;
+using System.Xml.Xsl;
+using System.Xml.XPath;
+
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+
+namespace Microsoft.Build.Tasks
+{
+ /// <summary>
+ /// A task that returns values as specified by XPath Query
+ /// from an XML file.
+ /// </summary>
+ public class XmlPeek : TaskExtension
+ {
+ #region Members
+
+ /// <summary>
+ /// The XML input as a file path.
+ /// </summary>
+ private ITaskItem _xmlInputPath;
+
+ /// <summary>
+ /// The XML input as a string.
+ /// </summary>
+ private string _xmlContent;
+
+ /// <summary>
+ /// The XPath Query.
+ /// </summary>
+ private string _query;
+
+ /// <summary>
+ /// The results that this task will return.
+ /// </summary>
+ private ITaskItem[] _result;
+
+ /// <summary>
+ /// The namespaces for XPath query's prefixes.
+ /// </summary>
+ private string _namespaces;
+
+ #endregion
+
+ #region Properties
+
+ /// <summary>
+ /// The XML input as a file path.
+ /// </summary>
+ public ITaskItem XmlInputPath {
+ get {
+ return _xmlInputPath;
+ }
+
+ set {
+ _xmlInputPath = value;
+ }
+ }
+
+ /// <summary>
+ /// The XML input as a string.
+ /// </summary>
+ public string XmlContent {
+ get {
+ return _xmlContent;
+ }
+
+ set {
+ _xmlContent = value;
+ }
+ }
+
+ /// <summary>
+ /// The XPath Query.
+ /// </summary>
+ public string Query {
+ get {
+ if (_query == null)
+ throw new ArgumentNullException ("Query");
+ return _query;
+ }
+
+ set {
+ _query = value;
+ }
+ }
+
+ /// <summary>
+ /// The results returned by this task.
+ /// </summary>
+ [Output]
+ public ITaskItem[] Result {
+ get {
+ return _result;
+ }
+ }
+
+ /// <summary>
+ /// The namespaces for XPath query's prefixes.
+ /// </summary>
+ public string Namespaces {
+ get {
+ return _namespaces;
+ }
+
+ set {
+ _namespaces = value;
+ }
+ }
+
+ #endregion
+
+
+ internal static bool IsCriticalException (Exception e)
+ {
+ if (e is StackOverflowException
+ || e is OutOfMemoryException
+ || e is AccessViolationException) {
+ return true;
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Executes the XMLPeek task.
+ /// </summary>
+ /// <returns>true if transformation succeeds.</returns>
+ public override bool Execute ()
+ {
+ XmlInput xmlinput;
+ if (_query == null)
+ throw new ArgumentNullException ("Query");
+
+ try {
+ xmlinput = new XmlInput (_xmlInputPath, _xmlContent);
+ } catch (Exception e) {
+ if (IsCriticalException (e)) {
+ throw;
+ }
+
+ Log.LogErrorWithCodeFromResources ("XmlPeek.ArgumentError", e.Message);
+ return false;
+ }
+
+ XPathDocument xpathdoc;
+ try {
+ // Load the XPath Document
+ using (XmlReader xr = xmlinput.CreateReader ()) {
+ xpathdoc = new XPathDocument (xr);
+ xr.Close ();
+ }
+ } catch (Exception e) {
+ if (IsCriticalException (e)) {
+ throw;
+ }
+
+ Log.LogErrorWithCodeFromResources ("XmlPeekPoke.InputFileError", _xmlInputPath.ItemSpec, e.Message);
+ return false;
+ } finally {
+ xmlinput.CloseReader ();
+ }
+
+ XPathNavigator nav = xpathdoc.CreateNavigator ();
+ XPathExpression expr = null;
+ try {
+ // Create the expression from query
+ expr = nav.Compile (_query);
+ } catch (Exception e) {
+ if (IsCriticalException (e)) {
+ throw;
+ }
+
+ Log.LogErrorWithCodeFromResources ("XmlPeekPoke.XPathError", _query, e.Message);
+ return false;
+ }
+
+ // Create the namespace manager and parse the input.
+ XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager (nav.NameTable);
+
+ try {
+ LoadNamespaces (ref xmlNamespaceManager, _namespaces);
+ } catch (Exception e) {
+ if (IsCriticalException (e)) {
+ throw;
+ }
+
+ Log.LogErrorWithCodeFromResources ("XmlPeek.NamespacesError", e.Message);
+ return false;
+ }
+
+ try {
+ expr.SetContext (xmlNamespaceManager);
+ } catch (XPathException e) {
+ Log.LogErrorWithCodeFromResources ("XmlPeek.XPathContextError", e.Message);
+ return false;
+ }
+
+ XPathNodeIterator iter = nav.Select (expr);
+
+ List<string> peekValues = new List<string> ();
+ while (iter.MoveNext ()) {
+ if (iter.Current.NodeType == XPathNodeType.Attribute
+ || iter.Current.NodeType == XPathNodeType.Text) {
+ peekValues.Add (iter.Current.Value);
+ } else {
+ peekValues.Add (iter.Current.OuterXml);
+ }
+ }
+
+ _result = new ITaskItem[peekValues.Count];
+ int i = 0;
+ foreach (string item in peekValues) {
+ _result [i++] = new TaskItem (item);
+
+ // This can be logged a lot, so low importance
+ Log.LogMessageFromResources (MessageImportance.Low, "XmlPeek.Found", item);
+ }
+
+ if (_result.Length == 0) {
+ // Logged no more than once per execute of this task
+ Log.LogMessageFromResources ("XmlPeek.NotFound");
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Loads the namespaces specified at Namespaces parameter to XmlNSManager.
+ /// </summary>
+ /// <param name="namespaceManager">The namespace manager to load namespaces to.</param>
+ /// <param name="namepaces">The namespaces as XML snippet.</param>
+ private void LoadNamespaces (ref XmlNamespaceManager namespaceManager, string namepaces)
+ {
+ XmlDocument doc = new XmlDocument ();
+ try {
+ XmlReaderSettings settings = new XmlReaderSettings ();
+ settings.DtdProcessing = DtdProcessing.Ignore;
+
+ using (XmlReader reader = XmlReader.Create (new StringReader ("<Namespaces>" + namepaces + "</Namespaces>"), settings)) {
+ doc.Load (reader);
+ }
+ } catch (XmlException xe) {
+ throw new ArgumentException ("The specified Namespaces attribute is not a well-formed XML fragment.", xe);
+ }
+
+ XmlNodeList xnl = doc.SelectNodes ("/Namespaces/*[local-name() = 'Namespace']");
+ for (int i = 0; i < xnl.Count; i++) {
+ XmlNode xn = xnl [i];
+
+ if (xn.Attributes ["Prefix"] == null) {
+ throw new ArgumentException (string.Format ("The specified Namespaces attribute doesn't have attribute \"{0}\".", "Name"));
+ }
+
+ if (xn.Attributes ["Uri"] == null) {
+ throw new ArgumentException (string.Format ("The specified Namespaces attribute doesn't have attribute \"{0}\".", "Uri"));
+ }
+
+ namespaceManager.AddNamespace (xn.Attributes ["Prefix"].Value, xn.Attributes ["Uri"].Value);
+ }
+ }
+
+ /// <summary>
+ /// This class prepares XML input from XMLInputPath and XMLContent parameters
+ /// </summary>
+ internal class XmlInput
+ {
+ /// <summary>
+ /// What XML input type are we at.
+ /// </summary>
+ private XmlModes _xmlMode;
+
+ /// <summary>
+ /// This either contains the raw Xml or the path to Xml file.
+ /// </summary>
+ private string _data;
+
+ /// <summary>
+ /// Filestream used to read XML.
+ /// </summary>
+ private FileStream _fs;
+
+ /// <summary>
+ /// Constructor.
+ /// Only one parameter should be non null or will throw ArgumentException.
+ /// </summary>
+ /// <param name="xmlInputPath">The path to XML file or null.</param>
+ /// <param name="xmlContent">The raw XML.</param>
+ public XmlInput (ITaskItem xmlInputPath, string xmlContent)
+ {
+ if (xmlInputPath != null && xmlContent != null) {
+ throw new ArgumentException ("Only one of XmlContent or XmlInputPaths arguments can be set.");
+ } else if (xmlInputPath == null && xmlContent == null) {
+ throw new ArgumentException ("One of XmlContent or XmlInputPaths arguments must be set.");
+ }
+
+ if (xmlInputPath != null) {
+ _xmlMode = XmlModes.XmlFile;
+ _data = xmlInputPath.ItemSpec;
+ } else {
+ _xmlMode = XmlModes.Xml;
+ _data = xmlContent;
+ }
+ }
+
+ /// <summary>
+ /// Possible accepted types of XML input.
+ /// </summary>
+ public enum XmlModes
+ {
+ /// <summary>
+ /// If the mode is a XML file.
+ /// </summary>
+ XmlFile,
+
+ /// <summary>
+ /// If the mode is a raw XML.
+ /// </summary>
+ Xml
+ }
+
+ /// <summary>
+ /// Returns the current mode of the XmlInput
+ /// </summary>
+ public XmlModes XmlMode {
+ get {
+ return _xmlMode;
+ }
+ }
+
+ /// <summary>
+ /// Creates correct reader based on the input type.
+ /// </summary>
+ /// <returns>The XmlReader object</returns>
+ public XmlReader CreateReader ()
+ {
+ if (_xmlMode == XmlModes.XmlFile) {
+ _fs = new FileStream (_data, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+ return XmlReader.Create (_fs);
+ } else { // xmlModes.Xml
+ return XmlReader.Create (new StringReader (_data));
+ }
+ }
+
+ /// <summary>
+ /// Closes the reader.
+ /// </summary>
+ public void CloseReader ()
+ {
+ if (_fs != null) {
+ _fs.Close ();
+ _fs = null;
+ }
+ }
+ }
+ }
+}