// Copyright © Microsoft Corporation. // This source file is subject to the Microsoft Permissive License. // See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx. // All other rights reserved. using System; using System.Collections.Generic; using System.Configuration; using System.Xml; using System.Xml.XPath; namespace Microsoft.Ddue.Tools { public class ForEachComponent : BuildComponent { public ForEachComponent (BuildAssembler assembler, XPathNavigator configuration) : base(assembler, configuration) { // set up the context XPathNodeIterator context_nodes = configuration.Select("context"); foreach (XPathNavigator context_node in context_nodes) { string prefix = context_node.GetAttribute("prefix", String.Empty); string name = context_node.GetAttribute("name", String.Empty); context.AddNamespace(prefix, name); } // load the expression format XPathNavigator variable_node = configuration.SelectSingleNode("variable"); if (variable_node == null) throw new ConfigurationErrorsException("When instantiating a ForEach component, you must specify a variable using the element."); string xpath_format = variable_node.GetAttribute("expression", String.Empty); if ((xpath_format == null) || (xpath_format.Length == 0)) throw new ConfigurationErrorsException("When instantiating a ForEach component, you must specify a variable expression using the expression attribute"); xpath = XPathExpression.Compile(xpath_format); // load the subcomponents WriteMessage(MessageLevel.Info, "Loading subcomponents."); XPathNavigator components_node = configuration.SelectSingleNode("components"); if (components_node == null) throw new ConfigurationErrorsException("When instantiating a ForEach component, you must specify subcomponents using the element."); components = BuildAssembler.LoadComponents(components_node); WriteMessage(MessageLevel.Info, String.Format("Loaded {0} subcomponents.", components.Count)); } // the format string for the variable expression private XPathExpression xpath; // the xpath context private CustomContext context = new CustomContext(); // the subcomponents private ICollection components; // the work of the component public override void Apply (XmlDocument document, string key) { // adjust the context context["key"] = key; // evaluate the condition XPathExpression xpath_local = xpath.Clone(); xpath_local.SetContext(context); Object result = document.CreateNavigator().Evaluate(xpath_local); // try to intrepret the result as a node set XPathNodeIterator result_node_iterator = result as XPathNodeIterator; if (result_node_iterator != null) { XPathNavigator[] result_nodes = BuildComponentUtilities.ConvertNodeIteratorToArray(result_node_iterator); //Console.WriteLine("{0} node-set result", result_nodes.Length); // if it is, apply the child components to each node value foreach (XPathNavigator result_node in result_nodes) { // Console.WriteLine(result_node.Value); ApplyComponents(document, result_node.Value); } } else { //Console.WriteLine("non-node-set result"); // if it isn't, apply the child components to the string value of the result ApplyComponents(document, result.ToString()); } } private void ApplyComponents (XmlDocument document, string key) { foreach (BuildComponent component in components) { component.Apply(document, key); } } protected override void Dispose(bool disposing) { if (disposing) { foreach (BuildComponent component in components) { component.Dispose(); } } base.Dispose(disposing); } } }