protected virtual ParsedTemplate PrepareTemplate(TemplateData templateData) { // clone orig doc XDocument workingDoc = new XDocument(this._templateDefinition); // start by loading any parameters as they are needed for meta-template evaluation Dictionary<string, XPathVariable> globalParams = new Dictionary<string, XPathVariable>(); XElement[] paramNodes = workingDoc.Root.Elements("parameter").ToArray(); foreach (XElement paramNode in paramNodes) { var tmplVar = new XPathVariable { Name = paramNode.Attribute("name").Value, ValueExpression = paramNode.Attribute("select") == null ? null : paramNode.Attribute("select").Value, }; globalParams.Add(tmplVar.Name, tmplVar); } CustomXsltContext customContext = new CustomXsltContext(); Func<string, object> onFailedResolve = s => { throw new InvalidOperationException( String.Format("Parameter '{0}' could not be resolved.", s)); }; customContext.OnResolveVariable += s => { XPathVariable var; // if it's defined if (globalParams.TryGetValue(s, out var)) { // see if the user provided a value object value; if (templateData.Arguments.TryGetValue(s, out value)) return value; // evaluate default value if (!String.IsNullOrWhiteSpace(var.ValueExpression)) return workingDoc.XPathEvaluate(var.ValueExpression, customContext); } return onFailedResolve(s); }; // check for meta-template directives and expand XElement metaNode = workingDoc.Root.Elements("meta-template").FirstOrDefault(); // we're going to need this later XmlFileProviderResolver fileResolver = new XmlFileProviderResolver(this._fileProvider, this._basePath); while (metaNode != null) { if (EvalCondition(customContext, metaNode, this.GetAttributeValueOrDefault(metaNode, "condition"))) { #region Debug conditional #if DEBUG const bool debugEnabled = true; #else const bool debugEnabled = false; #endif #endregion XslCompiledTransform metaTransform = this.LoadStylesheet(metaNode.Attribute("stylesheet").Value); XsltArgumentList xsltArgList = new XsltArgumentList(); // TODO this is a quick fix/hack xsltArgList.AddExtensionObject("urn:lostdoc-core", new TemplateXsltExtensions(null, null)); var metaParamNodes = metaNode.Elements("with-param"); foreach (XElement paramNode in metaParamNodes) { string pName = paramNode.Attribute("name").Value; string pExpr = paramNode.Attribute("select").Value; xsltArgList.AddParam(pName, string.Empty, workingDoc.XPathEvaluate(pExpr, customContext)); } XDocument outputDoc = new XDocument(); using (XmlWriter outputWriter = outputDoc.CreateWriter()) { metaTransform.Transform(workingDoc.CreateNavigator(), xsltArgList, outputWriter, fileResolver); } TraceSources.TemplateSource.TraceVerbose("Template after transformation by {0}", metaNode.Attribute("stylesheet").Value); TraceSources.TemplateSource.TraceData(TraceEventType.Verbose, 1, outputDoc.CreateNavigator()); workingDoc = outputDoc; } else { // didn't process, so remove it metaNode.Remove(); } // select next template metaNode = workingDoc.Root.Elements("meta-template").FirstOrDefault(); } // loading template List<Stylesheet> stylesheets = new List<Stylesheet>(); List<Resource> resources = new List<Resource>(); List<Index> indices = new List<Index>(); foreach (XElement elem in workingDoc.Root.Elements()) { // we alread proessed the parameters if (elem.Name.LocalName == "parameter") continue; if (elem.Name.LocalName == "apply-stylesheet") { stylesheets.Add(this.ParseStylesheet(stylesheets, elem)); } else if (elem.Name.LocalName == "index") { indices.Add(this.ParseIndex(elem)); } else if (elem.Name.LocalName == "include-resource") { resources.Add(new Resource { Path = elem.Attribute("path").Value, ConditionExpression = this.GetAttributeValueOrDefault(elem, "condition") }); } else { throw new Exception("Unknown element: " + elem.Name.LocalName); } } return new ParsedTemplate { Resources = resources.ToArray(), Stylesheets = stylesheets.ToArray(), Indices = indices.ToArray() }; }
/// <summary> /// The load stylesheet. /// </summary> /// <param name="name"> /// </param> /// <returns> /// </returns> private XslCompiledTransform LoadStylesheet(string name) { XslCompiledTransform ret = new XslCompiledTransform(true); using (Stream str = this._fileProvider.OpenFile(Path.Combine(this._basePath, name))) { XmlReader reader = XmlReader.Create(str, new XmlReaderSettings { CloseInput = true, }); XsltSettings settings = new XsltSettings(false, true); XmlResolver resolver = new XmlFileProviderResolver(this._fileProvider, this._basePath); ret.Load(reader, settings, resolver); } return ret; }