Monday, December 1, 2014

Execute XSLT from pipeline component

In few cases we don't have to actually create a map for transforming the message and this custom pipeline component used to transform an XML message using XSLT.

Sample for suppress the blank nodes before message going to final destination.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:template match="@*|node()"><xsl:if test=". != ''"><xsl:copy><xsl:apply-templates select="@*|node()"/></xsl:copy></xsl:if></xsl:template></xsl:stylesheet>

Pipeline component:
[ComponentCategory(CategoryTypes.CATID_PipelineComponent)]
    [System.Runtime.InteropServices.Guid("34b2fdfe-0c6f-4e6a-992a-511058a2c467")]
    [ComponentCategory(CategoryTypes.CATID_Encoder)]
    public class TransformMessage : IBaseComponent, Microsoft.BizTalk.Component.Interop.IComponent, IComponentUI, IPersistPropertyBag
    {
        #region Private Variables

        private ResourceManager resourceManager = null;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="Class1"/> class.
        /// </summary>
        public TransformMessage()
        {
            resourceManager = new ResourceManager("My.Common.BizTalk.PipelineComponent.XSLTtransform.TransformMessage", Assembly.GetExecutingAssembly());
        }

        #endregion

        #region Public properties

        /// <summary>
        /// Gets or sets the custom XSLT.
        /// </summary>
        /// <value>
        /// The custom XSLT.
        /// </value>
        [DisplayName("CustomXSLT")]
        public string CustomXSLT
        {
            get;
            set;
        }

        #endregion

        #region IBaseComponent

        /// <summary>
        /// Description of the Component
        /// </summary>
        public string Description
        {
            get { return resourceManager.GetString("COMPONENTDESCRIPTION", CultureInfo.InvariantCulture); }
        }

        /// <summary>
        /// Name of the Component
        /// </summary>
        public string Name
        {
            get { return resourceManager.GetString("COMPONENTNAME", CultureInfo.InvariantCulture); }
        }

        /// <summary>
        /// Version of the Component
        /// </summary>
        public string Version
        {
            get { return resourceManager.GetString("COMPONENTVERSION", CultureInfo.InvariantCulture); }
        }

        #endregion

        #region IPersistPropertyBag

        /// <summary>
        /// GetClassID of component for usage from unmanaged code.
        /// </summary>
        /// <param name="classID"></param>
        public void GetClassID(out Guid classID)
        {
            classID = new Guid("00b3e605-1cbe-41ff-bb43-4bad07f2f3ef");
        }

        /// <summary>
        /// InitNew
        /// </summary>
        public void InitNew()
        {
        }

        /// <summary>
        /// Loads configuration properties for the component
        /// </summary>
        /// <param name="propertyBag"></param>
        /// <param name="errorLog"></param>
        public void Load(IPropertyBag propertyBag, int errorLog)
        {
            try
            {
                CustomXSLT = ReadPropertyBag<string>(propertyBag, "CustomXSLT");
            }
            catch (NullReferenceException ex)
            {
                System.Diagnostics.EventLog.WriteEntry("Error in reading property bag", ex.Message);
                throw ex;
            }
        }

        /// <summary>
        /// Saves the current component configuration into the property bag
        /// </summary>
        /// <param name="pb">Configuration property bag</param>
        /// <param name="fClearDirty">not used</param>
        /// <param name="fSaveAllProperties">not used</param>
        public virtual void Save(Microsoft.BizTalk.Component.Interop.IPropertyBag pb, bool fClearDirty, bool fSaveAllProperties)
        {
            WritePropertyBag(pb, "CustomXSLT", this.CustomXSLT);
        }

        #endregion

        #region IComponentUI

        /// <summary>
        /// Component icon to use in BizTalk Editor
        /// </summary>
        [System.ComponentModel.Browsable(false)]
        public IntPtr Icon
        {
            get
            {
                return ((System.Drawing.Bitmap)(this.resourceManager.GetObject("COMPONENTICON", System.Globalization.CultureInfo.InvariantCulture))).GetHicon();
            }
        }

        /// <summary>
        /// The Validate method is called by the BizTalk Editor during the build of a BizTalk project.
        /// </summary>
        /// <param name="projectSystem"></param>
        /// <returns></returns>
        public System.Collections.IEnumerator Validate(object projectSystem)
        {
            return null;
        }

        #endregion

        #region IComponent

        /// <summary>
        /// Execute Method
        /// </summary>
        /// <param name="pContext"></param>
        /// <param name="pInMsg"></param>
        /// <returns></returns>
        public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(IPipelineContext pContext, Microsoft.BizTalk.Message.Interop.IBaseMessage pInMsg)
        {
            Stream vStream = new VirtualStream(pInMsg.BodyPart.GetOriginalDataStream());
            ReadOnlySeekableStream message = new ReadOnlySeekableStream(vStream);
            MemoryStream memoryStream = new MemoryStream();
            message.CopyTo(memoryStream);
            message.Position = 0;

            XPathDocument xPathDoc = new XPathDocument(message);
            XslCompiledTransform transform = new XslCompiledTransform();
            MemoryStream xslStream = new MemoryStream();
            byte[] outBytes = System.Text.Encoding.ASCII.GetBytes(CustomXSLT);

            xslStream.Write(outBytes, 0, outBytes.Length);
            xslStream.Position = 0;
            XPathDocument xsltDoc = new XPathDocument((Stream)xslStream);
            transform.Load(xsltDoc);

            //transform.Load(
            memoryStream = new MemoryStream();
            transform.Transform(xPathDoc, null, memoryStream);
            memoryStream.Seek(0, SeekOrigin.Begin);

            pInMsg.BodyPart.Data = memoryStream;
            return pInMsg;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Reads the property bag.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="propertyBag">The property bag.</param>
        /// <param name="propName">Name of the property.</param>
        /// <returns></returns>
        private T ReadPropertyBag<T>(IPropertyBag propertyBag, string propName)
        {
            T returnValue = default(T);
            object val = null;
            try
            {
                propertyBag.Read(propName, out val, 0);
                returnValue = (T)Convert.ChangeType(val, typeof(T));
            }
            catch (System.ArgumentException)
            {
                return returnValue;
            }
            catch (System.Exception ex)
            {
                System.Diagnostics.EventLog.WriteEntry("XMLDebatch", string.Concat("Error in reading into property bag", ex.Message));
                throw new ApplicationException(string.Concat("Error in reading into property bag: ", ex.Message));
            }
            return returnValue;
        }

        /// <summary>
        /// Writes the property bag.
        /// </summary>
        /// <param name="propertyBag">The property bag.</param>
        /// <param name="propName">Name of the property.</param>
        /// <param name="val">The value.</param>
        private void WritePropertyBag(IPropertyBag propertyBag, string propName, object val)
        {
            try
            {
                propertyBag.Write(propName, ref val);
            }
            catch (Exception ex)
            {
                System.Diagnostics.EventLog.WriteEntry("Error in writing into property bag", ex.Message);
                throw new ApplicationException(string.Concat("Error in writing into property bag: ", ex.Message));
            }
        }

        #endregion
    }

No comments:

Post a Comment