diff --git a/src/Cake.Common.Tests/Properties/Resources.Designer.cs b/src/Cake.Common.Tests/Properties/Resources.Designer.cs index e820ea1240..c82f75cde0 100644 --- a/src/Cake.Common.Tests/Properties/Resources.Designer.cs +++ b/src/Cake.Common.Tests/Properties/Resources.Designer.cs @@ -973,5 +973,44 @@ public static string XmlTransformation_Xsl { return ResourceManager.GetString("XmlTransformation_Xsl", resourceCulture); } } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?> + ///<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + ///<xsl:output method="html" encoding="utf-8"/> + ///<xsl:param name="BackgroundColor"></xsl:param> + ///<xsl:param name="Color"></xsl:param> + /// + ///<xsl:template match="/"> + ///<html> + /// <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE"> + /// <xsl:for-each select="breakfast_menu/food"> + /// <div style="background-color:{$BackgroundColor};color:{$Color};padding:4px"> + /// [rest of string was truncated]";. + /// + public static string XmlTransformationWithArguments_Xsl { + get { + return ResourceManager.GetString("XmlTransformationWithArguments_Xsl", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to <?xml version="1.0" encoding="UTF-8"?> + ///<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:input="http://example.com" exclude-result-prefixes="input" version="1.0"> + ///<xsl:output method="html" encoding="utf-8"/> + ///<xsl:param name="input:BackgroundColor"></xsl:param> + ///<xsl:param name="input:Color"></xsl:param> + /// + ///<xsl:template match="/"> + ///<html> + /// <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE"> + /// <xsl:for-each select="breakfast_menu/food"> + /// <di [rest of string was truncated]";. + /// + public static string XmlTransformationWithArgumentsAndNamespace_Xsl { + get { + return ResourceManager.GetString("XmlTransformationWithArgumentsAndNamespace_Xsl", resourceCulture); + } + } } } diff --git a/src/Cake.Common.Tests/Properties/Resources.resx b/src/Cake.Common.Tests/Properties/Resources.resx index 2789d22b81..69d086648b 100644 --- a/src/Cake.Common.Tests/Properties/Resources.resx +++ b/src/Cake.Common.Tests/Properties/Resources.resx @@ -1433,4 +1433,72 @@ Global EndGlobalSection EndGlobal + + <?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> +<xsl:output method="html" encoding="utf-8"/> +<xsl:param name="BackgroundColor"></xsl:param> +<xsl:param name="Color"></xsl:param> + +<xsl:template match="/"> +<html> + <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE"> + <xsl:for-each select="breakfast_menu/food"> + <div style="background-color:{$BackgroundColor};color:{$Color};padding:4px"> + <span style="font-weight:bold"> + <xsl:value-of select="name" /> + - + </span> + <xsl:value-of select="price" /> + </div> + <div style="margin-left:20px;margin-bottom:1em;font-size:10pt"> + <p> + <xsl:value-of select="description" /> + <span style="font-style:italic"> + ( + <xsl:value-of select="calories" /> + calories per serving) + </span> + </p> + </div> + </xsl:for-each> + </body> +</html> +</xsl:template> +</xsl:stylesheet> + + + <?xml version="1.0" encoding="UTF-8"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:input="http://example.com" exclude-result-prefixes="input" version="1.0"> +<xsl:output method="html" encoding="utf-8"/> +<xsl:param name="input:BackgroundColor"></xsl:param> +<xsl:param name="input:Color"></xsl:param> + +<xsl:template match="/"> +<html> + <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE"> + <xsl:for-each select="breakfast_menu/food"> + <div style="background-color:{$input:BackgroundColor};color:{$input:Color};padding:4px"> + <span style="font-weight:bold"> + <xsl:value-of select="name" /> + - + </span> + <xsl:value-of select="price" /> + </div> + <div style="margin-left:20px;margin-bottom:1em;font-size:10pt"> + <p> + <xsl:value-of select="description" /> + <span style="font-style:italic"> + ( + <xsl:value-of select="calories" /> + calories per serving) + </span> + </p> + </div> + </xsl:for-each> + </body> +</html> +</xsl:template> +</xsl:stylesheet> + \ No newline at end of file diff --git a/src/Cake.Common.Tests/Unit/XML/XmlTransformationTests.cs b/src/Cake.Common.Tests/Unit/XML/XmlTransformationTests.cs index 3953659f56..72cf41db80 100644 --- a/src/Cake.Common.Tests/Unit/XML/XmlTransformationTests.cs +++ b/src/Cake.Common.Tests/Unit/XML/XmlTransformationTests.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Text; +using System.Xml.Xsl; using Cake.Common.Tests.Fixtures; using Cake.Common.Tests.Properties; using Cake.Common.Xml; @@ -88,7 +89,7 @@ public void Should_Throw_If_Xml_Not_Exists() var result = Record.Exception(() => fixture.Transform()); // Then - AssertEx.IsExceptionWithMessage(result, "XML File not found."); + AssertEx.IsExceptionWithMessage(result, "XML file not found."); } [Fact] @@ -104,7 +105,7 @@ public void Should_Throw_If_Xsl_Not_Exists() var result = Record.Exception(() => fixture.Transform()); // Then - AssertEx.IsExceptionWithMessage(result, "Xsl File not found."); + AssertEx.IsExceptionWithMessage(result, "XSL file not found."); } [Fact] @@ -209,7 +210,7 @@ public void Should_Throw_If_Xsl_Was_Null() } [Fact] - public void Should_Throw_If_String_Settings_Was_Null() + public void Should_Throw_If_Xml_Transformation_Settings_Was_Null() { // Given var xml = Resources.XmlTransformation_Xml; @@ -221,6 +222,70 @@ public void Should_Throw_If_String_Settings_Was_Null() // Then AssertEx.IsArgumentNullException(result, "settings"); } + + [Fact] + public void Should_Not_Throw_If_Xsl_Argument_List_Was_Null() + { + // Given + var xml = Resources.XmlTransformation_Xml; + var xsl = Resources.XmlTransformation_Xsl; + XmlTransformationSettings xmlTransformationSettings = new XmlTransformationSettings + { + XsltArgumentList = null + }; + + // When + var result = Record.Exception(() => XmlTransformation.Transform(xsl, xml, xmlTransformationSettings)); + + // Then + Assert.Null(result); + } + + [Fact] + public void Should_Transform_Xml_String_And_Xsl_String_WithArguments_To_Result_String() + { + // Given + var xml = Resources.XmlTransformation_Xml; + var xsl = Resources.XmlTransformationWithArguments_Xsl; + var htm = Resources.XmlTransformation_Htm_NoXmlDeclaration; + XmlTransformationSettings xmlTransformationSettings = new XmlTransformationSettings + { + OmitXmlDeclaration = true, + Encoding = new UTF8Encoding(false), + XsltArgumentList = new XsltArgumentList() + }; + xmlTransformationSettings.XsltArgumentList.AddParam("BackgroundColor", string.Empty, "teal"); + xmlTransformationSettings.XsltArgumentList.AddParam("Color", string.Empty, "white"); + + // When + var result = XmlTransformation.Transform(xsl, xml, xmlTransformationSettings); + + // Then + Assert.Equal(htm, result, ignoreLineEndingDifferences: true); + } + + [Fact] + public void Should_Transform_Xml_String_And_Xsl_String_WithArgumentsAndNamespace_To_Result_String() + { + // Given + var xml = Resources.XmlTransformation_Xml; + var xsl = Resources.XmlTransformationWithArgumentsAndNamespace_Xsl; + var htm = Resources.XmlTransformation_Htm_NoXmlDeclaration; + XmlTransformationSettings xmlTransformationSettings = new XmlTransformationSettings + { + OmitXmlDeclaration = true, + Encoding = new UTF8Encoding(false), + XsltArgumentList = new XsltArgumentList() + }; + xmlTransformationSettings.XsltArgumentList.AddParam("BackgroundColor", "http://example.com", "teal"); + xmlTransformationSettings.XsltArgumentList.AddParam("Color", "http://example.com", "white"); + + // When + var result = XmlTransformation.Transform(xsl, xml, xmlTransformationSettings); + + // Then + Assert.Equal(htm, result, ignoreLineEndingDifferences: true); + } } } } \ No newline at end of file diff --git a/src/Cake.Common/Polyfill/XmlTransformationHelper.cs b/src/Cake.Common/Polyfill/XmlTransformationHelper.cs index f86654f431..a5cdd787bf 100644 --- a/src/Cake.Common/Polyfill/XmlTransformationHelper.cs +++ b/src/Cake.Common/Polyfill/XmlTransformationHelper.cs @@ -9,11 +9,11 @@ namespace Cake.Common.Polyfill { internal static class XmlTransformationHelper { - public static void Transform(XmlReader xsl, XmlReader xml, XmlWriter result) + public static void Transform(XmlReader xsl, XsltArgumentList arguments, XmlReader xml, XmlWriter result) { var xslTransform = new XslCompiledTransform(); xslTransform.Load(xsl); - xslTransform.Transform(xml, result); + xslTransform.Transform(xml, arguments, result); } } } diff --git a/src/Cake.Common/Xml/XmlTransformation.cs b/src/Cake.Common/Xml/XmlTransformation.cs index 1cc1d726b9..be2b69dc5e 100644 --- a/src/Cake.Common/Xml/XmlTransformation.cs +++ b/src/Cake.Common/Xml/XmlTransformation.cs @@ -6,6 +6,7 @@ using System.IO; using System.Text; using System.Xml; +using System.Xml.Xsl; using Cake.Common.Polyfill; using Cake.Core; using Cake.Core.IO; @@ -39,7 +40,7 @@ public static string Transform(string xsl, string xml) /// /// XML style sheet. /// XML data. - /// Settings for result file xml transformation. + /// Settings for result file XML transformation. /// Transformed XML string. public static string Transform(string xsl, string xml, XmlTransformationSettings settings) { @@ -64,7 +65,7 @@ public static string Transform(string xsl, string xml, XmlTransformationSettings { using (var result = new MemoryStream()) { - Transform(xslReader, xmlReader, result, settings.XmlWriterSettings); + Transform(xslReader, settings.XsltArgumentList, xmlReader, result, settings.XmlWriterSettings); result.Position = 0; return settings.Encoding.GetString(result.ToArray()); } @@ -75,8 +76,8 @@ public static string Transform(string xsl, string xml, XmlTransformationSettings /// Performs XML XSL transformation. /// /// The file system. - /// Path to xml style sheet. - /// Path xml data. + /// Path to XML style sheet. + /// Path XML data. /// Transformation result path. public static void Transform(IFileSystem fileSystem, FilePath xslPath, FilePath xmlPath, FilePath resultPath) { @@ -88,10 +89,10 @@ public static void Transform(IFileSystem fileSystem, FilePath xslPath, FilePath /// Performs XML XSL transformation. /// /// The file system. - /// Path to xml style sheet. - /// Path xml data. + /// Path to XML style sheet. + /// Path XML data. /// Transformation result path. - /// Settings for result file xml transformation. + /// Settings for result file XML transformation. public static void Transform(IFileSystem fileSystem, FilePath xslPath, FilePath xmlPath, FilePath resultPath, XmlTransformationSettings settings) { if (fileSystem == null) @@ -126,12 +127,12 @@ public static void Transform(IFileSystem fileSystem, FilePath xslPath, FilePath if (!xslFile.Exists) { - throw new FileNotFoundException("Xsl File not found.", xslFile.Path.FullPath); + throw new FileNotFoundException("XSL file not found.", xslFile.Path.FullPath); } if (!xmlFile.Exists) { - throw new FileNotFoundException("XML File not found.", xmlFile.Path.FullPath); + throw new FileNotFoundException("XML file not found.", xmlFile.Path.FullPath); } if (!settings.Overwrite && resultFile.Exists) @@ -149,8 +150,7 @@ public static void Transform(IFileSystem fileSystem, FilePath xslPath, FilePath xmlReader = XmlReader.Create(xmlStream); var resultWriter = XmlWriter.Create(resultStream, settings.XmlWriterSettings); - - Transform(xslReader, xmlReader, resultWriter); + Transform(xslReader, settings.XsltArgumentList, xmlReader, resultWriter); } } @@ -158,10 +158,11 @@ public static void Transform(IFileSystem fileSystem, FilePath xslPath, FilePath /// Performs XML XSL transformation. /// /// XML style sheet. + /// XSLT argument list. /// XML data. /// Transformation result. - /// Optional settings for result file xml writer. - private static void Transform(TextReader xsl, TextReader xml, Stream result, XmlWriterSettings settings = null) + /// Optional settings for result file XML writer. + private static void Transform(TextReader xsl, XsltArgumentList arguments, TextReader xml, Stream result, XmlWriterSettings settings = null) { if (xsl == null) { @@ -186,16 +187,17 @@ private static void Transform(TextReader xsl, TextReader xml, Stream result, Xml var xslXmlReader = XmlReader.Create(xsl); var xmlXmlReader = XmlReader.Create(xml); var resultXmlTextWriter = XmlWriter.Create(result, settings); - Transform(xslXmlReader, xmlXmlReader, resultXmlTextWriter); + Transform(xslXmlReader, arguments, xmlXmlReader, resultXmlTextWriter); } /// /// Performs XML XSL transformation. /// /// XML style sheet. + /// XSLT argument list. /// XML data. /// Transformation result. - private static void Transform(XmlReader xsl, XmlReader xml, XmlWriter result) + private static void Transform(XmlReader xsl, XsltArgumentList arguments, XmlReader xml, XmlWriter result) { if (xsl == null) { @@ -212,7 +214,7 @@ private static void Transform(XmlReader xsl, XmlReader xml, XmlWriter result) throw new ArgumentNullException(nameof(result), "Null result supplied."); } - XmlTransformationHelper.Transform(xsl, xml, result); + XmlTransformationHelper.Transform(xsl, arguments, xml, result); } } } \ No newline at end of file diff --git a/src/Cake.Common/Xml/XmlTransformationSettings.cs b/src/Cake.Common/Xml/XmlTransformationSettings.cs index fe1f91d0b4..aa5542d1c7 100644 --- a/src/Cake.Common/Xml/XmlTransformationSettings.cs +++ b/src/Cake.Common/Xml/XmlTransformationSettings.cs @@ -4,6 +4,7 @@ using System.Text; using System.Xml; +using System.Xml.Xsl; using Cake.Common.Polyfill; namespace Cake.Common.Xml @@ -128,6 +129,11 @@ public bool WriteEndDocumentOnClose set { XmlWriterSettings.WriteEndDocumentOnClose = value; } } + /// + /// Gets or sets an argument list for XSL transformation. + /// + public XsltArgumentList XsltArgumentList { get; set; } + /// /// Initializes a new instance of the class. ///