| File: XmlTransform.cs | Web Access |
| Project: src\xdt\src\Microsoft.Web.XmlTransform\Microsoft.Web.XmlTransform.csproj (Microsoft.Web.XmlTransform) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; using System.Text; using System.Xml; using System.Diagnostics; using Microsoft.Web.XmlTransform.Properties; namespace Microsoft.Web.XmlTransform { public enum MissingTargetMessage { None, Information, Warning, Error, } [Flags] public enum TransformFlags { None = 0, ApplyTransformToAllTargetNodes = 1, UseParentAsTargetNode = 2, } public abstract class Transform { #region private data members private MissingTargetMessage missingTargetMessage; private bool applyTransformToAllTargetNodes; private bool useParentAsTargetNode; private XmlTransformationLogger logger = null; private XmlElementContext context = null; private XmlNode currentTransformNode = null; private XmlNode currentTargetNode = null; private string argumentString = null; private IList<string> arguments = null; #endregion protected Transform() : this(TransformFlags.None) { } protected Transform(TransformFlags flags) : this(flags, MissingTargetMessage.Warning) { } protected Transform(TransformFlags flags, MissingTargetMessage message) { this.missingTargetMessage = message; this.applyTransformToAllTargetNodes = (flags & TransformFlags.ApplyTransformToAllTargetNodes) == TransformFlags.ApplyTransformToAllTargetNodes; this.useParentAsTargetNode = (flags & TransformFlags.UseParentAsTargetNode) == TransformFlags.UseParentAsTargetNode; } protected bool ApplyTransformToAllTargetNodes { get { return applyTransformToAllTargetNodes; } set { applyTransformToAllTargetNodes = value; } } protected bool UseParentAsTargetNode { get { return useParentAsTargetNode; } set { useParentAsTargetNode = value; } } protected MissingTargetMessage MissingTargetMessage { get { return missingTargetMessage; } set { missingTargetMessage = value; } } protected abstract void Apply(); protected XmlNode TransformNode { get { if (currentTransformNode == null) { return context.TransformNode; } else { return currentTransformNode; } } } protected XmlNode TargetNode { get { if (currentTargetNode == null) { foreach (XmlNode targetNode in TargetNodes) { return targetNode; } } return currentTargetNode; } } protected XmlNodeList TargetNodes { get { if (UseParentAsTargetNode) { return context.TargetParents; } else { return context.TargetNodes; } } } protected XmlNodeList TargetChildNodes { get { return context.TargetNodes; } } protected XmlTransformationLogger Log { get { if (logger == null) { logger = context.GetService<XmlTransformationLogger>(); if (logger != null) { logger.CurrentReferenceNode = context.TransformAttribute; } } return logger; } } protected T GetService<T>() where T : class { return context.GetService<T>(); } protected string ArgumentString { get { return argumentString; } } protected IList<string> Arguments { get { if (arguments == null && argumentString != null) { arguments = XmlArgumentUtility.SplitArguments(argumentString); } return arguments; } } private string TransformNameLong { get { if (context.HasLineInfo) { return string.Format(System.Globalization.CultureInfo.CurrentCulture,Resources.XMLTRANSFORMATION_TransformNameFormatLong, TransformName, context.TransformLineNumber, context.TransformLinePosition); } else { return TransformNameShort; } } } internal string TransformNameShort { get { return string.Format(System.Globalization.CultureInfo.CurrentCulture,Resources.XMLTRANSFORMATION_TransformNameFormatShort, TransformName); } } private string TransformName { get { return GetType().Name; } } internal void Execute(XmlElementContext context, string argumentString) { Debug.Assert(this.context == null && this.argumentString == null, "Don't call Execute recursively"); Debug.Assert(this.logger == null, "Logger wasn't released from previous execution"); if (this.context == null && this.argumentString == null) { bool error = false; bool startedSection = false; try { this.context = context; this.argumentString = argumentString; this.arguments = null; if (ShouldExecuteTransform()) { startedSection = true; Log.StartSection(MessageType.Verbose, Resources.XMLTRANSFORMATION_TransformBeginExecutingMessage, TransformNameLong); Log.LogMessage(MessageType.Verbose, Resources.XMLTRANSFORMATION_TransformStatusXPath, context.XPath); if (ApplyTransformToAllTargetNodes) { ApplyOnAllTargetNodes(); } else { ApplyOnce(); } } } catch (Exception ex) { error = true; if (context.TransformAttribute != null) { Log.LogErrorFromException(XmlNodeException.Wrap(ex, context.TransformAttribute)); } else { Log.LogErrorFromException(ex); } } finally { if (startedSection) { if (error) { Log.EndSection(MessageType.Verbose, Resources.XMLTRANSFORMATION_TransformErrorExecutingMessage, TransformNameShort); } else { Log.EndSection(MessageType.Verbose, Resources.XMLTRANSFORMATION_TransformEndExecutingMessage, TransformNameShort); } } else { Log.LogMessage(MessageType.Normal, Resources.XMLTRANSFORMATION_TransformNotExecutingMessage, TransformNameLong); } this.context = null; this.argumentString = null; this.arguments = null; ReleaseLogger(); } } } private void ReleaseLogger() { if (logger != null) { logger.CurrentReferenceNode = null; logger = null; } } private bool ApplyOnAllTargetNodes() { bool error = false; XmlNode originalTransformNode = TransformNode; foreach (XmlNode node in TargetNodes) { try { currentTargetNode = node; currentTransformNode = originalTransformNode.Clone(); ApplyOnce(); } catch (Exception ex) { Log.LogErrorFromException(ex); error = true; } } currentTargetNode = null; return error; } private void ApplyOnce() { WriteApplyMessage(TargetNode); Apply(); } private void WriteApplyMessage(XmlNode targetNode) { IXmlLineInfo lineInfo = targetNode as IXmlLineInfo; if (lineInfo != null) { Log.LogMessage(MessageType.Verbose, Resources.XMLTRANSFORMATION_TransformStatusApplyTarget, targetNode.Name, lineInfo.LineNumber, lineInfo.LinePosition); } else { Log.LogMessage(MessageType.Verbose, Resources.XMLTRANSFORMATION_TransformStatusApplyTargetNoLineInfo, targetNode.Name); } } private bool ShouldExecuteTransform() { return HasRequiredTarget(); } private bool HasRequiredTarget() { bool hasRequiredTarget = false; bool existedInOriginal = false; XmlElementContext matchFailureContext; if (UseParentAsTargetNode) { hasRequiredTarget = context.HasTargetParent(out matchFailureContext, out existedInOriginal); } else { hasRequiredTarget = context.HasTargetNode(out matchFailureContext, out existedInOriginal); } if (!hasRequiredTarget) { HandleMissingTarget(matchFailureContext, existedInOriginal); return false; } return true; } private void HandleMissingTarget(XmlElementContext matchFailureContext, bool existedInOriginal) { string messageFormat = existedInOriginal ? Resources.XMLTRANSFORMATION_TransformSourceMatchWasRemoved : Resources.XMLTRANSFORMATION_TransformNoMatchingTargetNodes; string message = string.Format(System.Globalization.CultureInfo.CurrentCulture,messageFormat, matchFailureContext.XPath); switch(MissingTargetMessage) { case MissingTargetMessage.None: Log.LogMessage(MessageType.Verbose, message); break; case MissingTargetMessage.Information: Log.LogMessage(MessageType.Normal, message); break; case MissingTargetMessage.Warning: Log.LogWarning(matchFailureContext.Node, message); break; case MissingTargetMessage.Error: throw new XmlNodeException(message, matchFailureContext.Node); } } } }