diff options
Diffstat (limited to 'tools/Sandcastle/Source/BuildAssembler/BuildComponents/TransformComponent.cs')
-rw-r--r-- | tools/Sandcastle/Source/BuildAssembler/BuildComponents/TransformComponent.cs | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/tools/Sandcastle/Source/BuildAssembler/BuildComponents/TransformComponent.cs b/tools/Sandcastle/Source/BuildAssembler/BuildComponents/TransformComponent.cs new file mode 100644 index 0000000..82b3241 --- /dev/null +++ b/tools/Sandcastle/Source/BuildAssembler/BuildComponents/TransformComponent.cs @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// +using System; +using System.Collections.Generic; +using System.Configuration; +using System.IO; +using System.Xml; +using System.Xml.XPath; +using System.Xml.Xsl; + +namespace Microsoft.Ddue.Tools { + + public class TransformComponent : BuildComponent { + + public TransformComponent (BuildAssembler assembler, XPathNavigator configuration) : base(assembler, configuration) { + + // load the transforms + XPathNodeIterator transform_nodes = configuration.Select("transform"); + foreach (XPathNavigator transform_node in transform_nodes) { + + // load the transform + string file = transform_node.GetAttribute("file", String.Empty); + if (String.IsNullOrEmpty(file)) WriteMessage(MessageLevel.Error, "Each transform element must specify a file attribute."); + file = Environment.ExpandEnvironmentVariables(file); + + Transform transform = null; + try { + transform = new Transform(file); + } catch (IOException e) { + WriteMessage(MessageLevel.Error, String.Format("The transform file '{0}' could not be loaded. The error message is: {1}", file, BuildComponentUtilities.GetExceptionMessage(e))); + } catch (XmlException e) { + WriteMessage(MessageLevel.Error, String.Format("The transform file '{0}' is not a valid XML file. The error message is: {1}", file, BuildComponentUtilities.GetExceptionMessage(e))); + } catch (XsltException e) { + WriteMessage(MessageLevel.Error, String.Format("The XSL transform '{0}' contains an error. The error message is: {1}", file, BuildComponentUtilities.GetExceptionMessage(e))); + } + + + transforms.Add(transform); + + + // load any arguments + XPathNodeIterator argument_nodes = transform_node.Select("argument"); + foreach (XPathNavigator argument_node in argument_nodes) { + string key = argument_node.GetAttribute("key", String.Empty); + if ((key == null) || (key.Length == 0)) WriteMessage(MessageLevel.Error, "When creating a transform argument, you must specify a key using the key attribute"); + + // set "expand-value" attribute to true to expand environment variables embedded in "value". + string expand_attr = argument_node.GetAttribute("expand-value", String.Empty); + bool expand_value = String.IsNullOrEmpty(expand_attr) ? false : Convert.ToBoolean(expand_attr); + + string value = argument_node.GetAttribute("value", String.Empty); + if ((value != null) && (value.Length > 0)) { + transform.Arguments.AddParam(key, String.Empty, expand_value ? Environment.ExpandEnvironmentVariables(value) : value); + } + else { + transform.Arguments.AddParam(key, String.Empty, argument_node.Clone()); + } + } + + } + + } + + // the stored transforms + + private List<Transform> transforms = new List<Transform>(); + + // the action of the component + + public override void Apply (XmlDocument document, string key) { + + // iterate over transforms + foreach (Transform transform in transforms) { + + // add the key as a parameter to the arguments + transform.Arguments.RemoveParam("key", String.Empty); + transform.Arguments.AddParam("key", String.Empty, key); + + // create a buffer into which output can be written + using (MemoryStream buffer = new MemoryStream()) { + + + // do the transform, routing output to the buffer + XmlWriterSettings settings = transform.Xslt.OutputSettings; + XmlWriter writer = XmlWriter.Create(buffer, settings); + try { + transform.Xslt.Transform(document, transform.Arguments, writer); + } catch (XsltException e) { + WriteMessage(MessageLevel.Error, String.Format("A error ocurred while executing the transform '{0}', on line {1}, at position {2}. The error message was: {3}", e.SourceUri, e.LineNumber, e.LinePosition, (e.InnerException == null) ? e.Message : e.InnerException.Message)); + } catch (XmlException e) { + WriteMessage(MessageLevel.Error, String.Format("A error ocurred while executing the transform '{0}', on line {1}, at position {2}. The error message was: {3}", e.SourceUri, e.LineNumber, e.LinePosition, (e.InnerException == null) ? e.Message : e.InnerException.Message)); + } finally { + writer.Close(); + } + + // replace the document by the contents of the buffer + buffer.Seek(0, SeekOrigin.Begin); + + // some settings to ensure that we don't try to go get, parse, and validate using any referenced schemas or DTDs + XmlReaderSettings readerSettings = new XmlReaderSettings(); + readerSettings.ProhibitDtd = false; + readerSettings.XmlResolver = null; + + XmlReader reader = XmlReader.Create(buffer, readerSettings); + try { + document.Load(reader); + } catch (XmlException e) { + WriteMessage(MessageLevel.Error, String.Format("A error ocurred while executing the transform '{0}', on line {1}, at position {2}. The error message was: {3}", e.SourceUri, e.LineNumber, e.LinePosition, (e.InnerException == null) ? e.Message : e.InnerException.Message)); + } finally { + reader.Close(); + } + + } + } + + } + + } + + + // a represenataion of a transform action + + internal class Transform { + + public Transform (string file) { + // The transforms presumably come from a trusted source, so there's no reason + // not to enable scripting and the document function. The latter is used to read topic + // info files for the conceptual WebDocs build. + xslt.Load(file, new XsltSettings(true, true), new XmlUrlResolver()); + } + + private XslCompiledTransform xslt = new XslCompiledTransform(); + + private XsltArgumentList arguments = new XsltArgumentList(); + + public XslCompiledTransform Xslt { + get { + return(xslt); + } + } + + public XsltArgumentList Arguments { + get { + return(arguments); + } + } + + } + +} |