// 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()); } }
public override void Apply(XmlDocument document, string key) { // Run through all conceptual nodes, make sure the target is a valid GUID, attempt to resolve the target // to a link using one of the TargetSet definitions, and then replace the node with the result. Errors // will be dealt with as follows: 1) bad target (GUID) -> output invalidLinkFormat; 2) broken link (cannot // resolve target or the URL is empty) -> output brokenLinkFormat; 3) missing text -> just delete the node // and don't output anything (presumably there's no point in creating a link that nobody can see). In all // three cases we'll log the problem as a warning. string docBaseUrl = baseUrl == null ? null : BuildComponentUtilities.EvalXPathExpr(document, baseUrl, "key", key); XPathNavigator[] linkNodes = BuildComponentUtilities.ConvertNodeIteratorToArray(document.CreateNavigator().Select(conceptualLinks)); foreach (XPathNavigator node in linkNodes) { string targetGuid = node.GetAttribute("target", String.Empty); string url = targetGuid; string text = node.ToString(); string format; if (validGuid.IsMatch(url)) { format = brokenLinkFormat; Target t = targetSets.Lookup(targetGuid); if (t == null) { WriteMessage(MessageLevel.Warn, String.Format("Conceptual link not found in target sets; target={0}", targetGuid)); } else { if (!String.IsNullOrEmpty(t.Url)) { format = t.TargetSet.Format; url = (docBaseUrl != null && t.TargetSet.RelativeUrl) ? BuildComponentUtilities.GetRelativePath(t.Url, docBaseUrl) : t.Url; if (!String.IsNullOrEmpty(t.Text)) { text = t.Text; } } else { WriteMessage(MessageLevel.Warn, String.Format("Conceptual link found in target set, but meta data does not specify a url; target={0}", targetGuid)); } } } else { format = invalidLinkFormat; } if (String.IsNullOrEmpty(text)) { node.DeleteSelf(); WriteMessage(MessageLevel.Warn, String.Format("Skipping conceptual link without text; target={0}", url)); } else { node.OuterXml = String.Format(format, url, text); } } }
/// <summary> /// This is used to create a <see cref="TargetDictionary"/> used to store reference link targets /// </summary> /// <param name="configuration">The configuration element for the target dictionary</param> /// <returns>A default <see cref="InMemoryTargetDictionary"/> instance containing the reference link /// targets</returns> /// <remarks>This can be overridden in derived classes to provide persistent caches with backing stores /// other than the default <see cref="Dictionary{TKey, TValue}"/></remarks>. public virtual TargetDictionary CreateTargetDictionary(XPathNavigator configuration) { TargetDictionary d = null; try { d = new InMemoryTargetDictionary(this, configuration); } catch (Exception ex) { base.WriteMessage(MessageLevel.Error, BuildComponentUtilities.GetExceptionMessage(ex)); } return(d); }
public override void Apply(XmlDocument document, string key) { // set the evaluation context context["key"] = key; XPathExpression path_xpath = path_expression.Clone(); path_xpath.SetContext(context); // evaluate the path string path = document.CreateNavigator().Evaluate(path_xpath).ToString(); string file = Path.GetFileName(path); string fileLinkPath = Path.Combine(linkPath, file); if (basePath != null) { path = Path.Combine(basePath, path); } // *SECURIY* The path name may be derived from user entered meta data in Doc Studio and as such // it is not trustworthy. To pass, the path must be inside the directory tree base_directory // (which is the current directory if a path is not specified). // This test is causing problems /* * string absoluteBasePath = (basePath == null) ? Directory.GetCurrentDirectory() : Path.GetFullPath(basePath); * string targetPath = Path.GetDirectoryName(path); * if (!targetPath.StartsWith(absoluteBasePath, StringComparison.CurrentCultureIgnoreCase)) { * WriteMessage(MessageLevel.Error, string.Format("Cannot save document outside of base directory: {0}", targetPath)); * return; * } */ string targetDirectory = Path.GetDirectoryName(path); if (!Directory.Exists(targetDirectory)) { Directory.CreateDirectory(targetDirectory); } // save the document // select_expression determines which nodes get saved. If there is no select_expression // we simply save the root node as before. If there is a select_expression, we evaluate the // xpath expression and save the resulting node set. The select expression also enables the // "literal-text" processing instruction, which outputs its content as unescaped text. if (select_expression == null) { XmlNode doctype = document.DocumentType; try { //Console.WriteLine("path = '{0}'", path); //document.Save(path); using (XmlWriter writer = XmlWriter.Create(path, settings)) { document.Save(writer); } } catch (IOException e) { WriteMessage(MessageLevel.Error, String.Format("An access error occured while attempting to save to the file '{0}'. The error message is: {1}", path, BuildComponentUtilities.GetExceptionMessage(e))); } catch (XmlException e) { WriteMessage(MessageLevel.Error, String.Format("Invalid XML was written to the output file '{0}'. The error message is: '{1}'", path, BuildComponentUtilities.GetExceptionMessage(e))); } // Get the relative html path for HXF generation. int index = fileLinkPath.IndexOf('/'); string htmlPath = fileLinkPath.Substring(index + 1, fileLinkPath.Length - (index + 1)); FileCreatedEventArgs fe = new FileCreatedEventArgs(htmlPath, Path.GetDirectoryName(targetDirectory)); OnComponentEvent(fe); } else { // IMPLEMENTATION NOTE: The separate StreamWriter is used to maintain XML indenting. // Without it the XmlWriter won't honor our indent settings after plain text nodes have been // written. settings.ConformanceLevel = ConformanceLevel.Auto; using (StreamWriter output = File.CreateText(path)) { using (XmlWriter writer = XmlWriter.Create(output, settings)) { XPathExpression select_xpath = select_expression.Clone(); select_xpath.SetContext(context); XPathNodeIterator ni = document.CreateNavigator().Select(select_expression); while (ni.MoveNext()) { if (ni.Current.NodeType == XPathNodeType.ProcessingInstruction && ni.Current.Name.Equals("literal-text")) { writer.Flush(); output.Write(ni.Current.Value); } else { ni.Current.WriteSubtree(writer); } } } } } }
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()); } } } }
// component logic public override void Apply(XmlDocument document, string key) { // XmlNodeList link_nodes = document.SelectNodes("//referenceLink"); XPathNodeIterator linkIterator = document.CreateNavigator().Select(referenceLinkExpression); XPathNavigator[] linkNodes = BuildComponentUtilities.ConvertNodeIteratorToArray(linkIterator); foreach (XPathNavigator linkNode in linkNodes) { // extract link information ReferenceLinkInfo2 link = ReferenceLinkInfo2.Create(linkNode); if (link == null) { WriteMessage(MessageLevel.Warn, "Invalid referenceLink element."); } else { // determine target, link type, and display options string targetId = link.Target; DisplayOptions options = link.DisplayOptions; LinkType2 type = LinkType2.None; Target target = GetTarget(targetId); if (target == null) { // no such target known; set link type to none and warn type = LinkType2.None; WriteMessage(MessageLevel.Warn, String.Format("Unknown reference link target '{0}'.", targetId)); } else { // if overload is prefered and found, change targetId and make link options hide parameters if (link.PreferOverload) { bool isConversionOperator = false; MethodTarget method = target as MethodTarget; if (method != null) { isConversionOperator = method.conversionOperator; } MemberTarget member = target as MemberTarget; // if conversion operator is found, always link to individual topic. if ((member != null) && (!String.IsNullOrEmpty(member.OverloadId)) && !isConversionOperator) { Target overloadTarget = targets[member.OverloadId]; if (overloadTarget != null) { target = overloadTarget; targetId = overloadTarget.Id; } } // if individual conversion operator is found, always display parameters. if (isConversionOperator && member != null && (!string.IsNullOrEmpty(member.OverloadId))) { options = options | DisplayOptions.ShowParameters; } else { options = options & ~DisplayOptions.ShowParameters; } } // get stored link type type = target.DefaultLinkType; // if link type is local or index, determine which if (type == LinkType2.LocalOrIndex) { if ((key != null) && targets.Contains(key) && (target.Container == targets[key].Container)) { type = LinkType2.Local; } else { type = LinkType2.Index; } } } // links to this page are not live if (targetId == key) { type = LinkType2.Self; } else if ((target != null) && (key != null) && targets.Contains(key) && (target.File == targets[key].File)) { type = LinkType2.Self; } // get msdn or external endpoint, if needed string externalUrl = null; if (type == LinkType2.Msdn || type == LinkType2.External) { externalUrl = ResolveExternalUrl(targetId, type); if (String.IsNullOrEmpty(externalUrl)) { type = LinkType2.None; } } // write opening link tag and target info XmlWriter writer = linkNode.InsertAfter(); switch (type) { case LinkType2.None: writer.WriteStartElement("span"); writer.WriteAttributeString("class", "nolink"); break; case LinkType2.Self: writer.WriteStartElement("span"); writer.WriteAttributeString("class", "selflink"); break; case LinkType2.Local: // format link with prefix and/or postfix string href = String.Format(hrefFormat, target.File); // make link relative, if we have a baseUrl if (baseUrl != null) { href = BuildComponentUtilities.GetRelativePath(href, BuildComponentUtilities.EvalXPathExpr(document, baseUrl, "key", key)); } writer.WriteStartElement("a"); writer.WriteAttributeString("href", href); break; case LinkType2.Index: writer.WriteStartElement("mshelp", "link", "http://msdn.microsoft.com/mshelp"); writer.WriteAttributeString("keywords", targetId); writer.WriteAttributeString("tabindex", "0"); break; case LinkType2.Msdn: case LinkType2.External: writer.WriteStartElement("a"); writer.WriteAttributeString("href", externalUrl); writer.WriteAttributeString("target", linkTarget); break; } // write the link text if (String.IsNullOrEmpty(link.DisplayTarget)) { if (link.Contents == null) { if (target != null) { resolver.WriteTarget(target, options, writer); } else { //Console.WriteLine("Attemting to create reference"); Reference reference = TextReferenceUtilities.CreateReference(targetId); //Console.WriteLine("Returned"); if (reference is InvalidReference) { WriteMessage(MessageLevel.Warn, String.Format("Invalid reference link target '{0}'.", targetId)); } resolver.WriteReference(reference, options, writer); } } else { // write contents to writer link.Contents.WriteSubtree(writer); } } else { //Console.WriteLine("Display target = {0}", link.DisplayTarget); if ((String.Compare(link.DisplayTarget, "content", true) == 0) && (link.Contents != null)) { // Use the contents as an XML representation of the display target //Console.WriteLine(link.Contents.NodeType); Reference reference = XmlTargetCollectionUtilities.CreateReference(link.Contents); //Console.WriteLine(reference.GetType().FullName); resolver.WriteReference(reference, options, writer); } if ((String.Compare(link.DisplayTarget, "format", true) == 0) && (link.Contents != null)) { // Use the contents as a format string for the display target string format = link.Contents.OuterXml; //Console.WriteLine("format = {0}", format); string input = null; StringWriter textStore = new StringWriter(); try { XmlWriterSettings settings = new XmlWriterSettings(); settings.ConformanceLevel = ConformanceLevel.Fragment; XmlWriter xmlStore = XmlWriter.Create(textStore, settings); try { if (target != null) { resolver.WriteTarget(target, options, xmlStore); } else { Reference reference = TextReferenceUtilities.CreateReference(targetId); resolver.WriteReference(reference, options, xmlStore); } } finally { xmlStore.Close(); } input = textStore.ToString(); } finally { textStore.Close(); } //Console.WriteLine("input = {0}", input); string output = String.Format(format, input); //Console.WriteLine("output = {0}", output); XmlDocumentFragment fragment = document.CreateDocumentFragment(); fragment.InnerXml = output; fragment.WriteTo(writer); //writer.WriteRaw(output); } else if ((String.Compare(link.DisplayTarget, "extension", true) == 0) && (link.Contents != null)) { Reference extMethodReference = XmlTargetCollectionUtilities.CreateExtensionMethodReference(link.Contents); resolver.WriteReference(extMethodReference, options, writer); } else { // Use the display target value as a CER for the display target TextReferenceUtilities.SetGenericContext(key); Reference reference = TextReferenceUtilities.CreateReference(link.DisplayTarget); //Console.WriteLine("Reference is {0}", reference.GetType().FullName); resolver.WriteReference(reference, options, writer); } } // write the closing link tag writer.WriteEndElement(); writer.Close(); } // delete the original tag linkNode.DeleteSelf(); } }
private void ResolveConceptualLinks(XmlDocument document, string key) { // find links XPathNodeIterator linkIterator = document.CreateNavigator().Select(conceptualLinks); // copy them to an array, because enumerating through an XPathNodeIterator // fails when the nodes in it are altered XPathNavigator[] linkNodes = BuildComponentUtilities.ConvertNodeIteratorToArray(linkIterator); foreach (XPathNavigator linkNode in linkNodes) { ConceptualLinkInfo link = ConceptualLinkInfo.Create(linkNode); // determine url, text, and link type string url = null; string text = null; LinkType type = LinkType.None; bool isValidLink = validGuid.IsMatch(link.Target); if (isValidLink) { // a valid link; try to fetch target info TargetInfo target = GetTargetInfoFromCache(link.Target.ToLower()); if (target == null) { // no target found; issue warning, set link style to none, and text to in-source fall-back //type = LinkType.None; type = LinkType.Index; text = BrokenLinkDisplayText(link.Target, link.Text); WriteMessage(MessageLevel.Warn, String.Format("Unknown conceptual link target '{0}'.", link.Target)); } else { // found target; get url, text, and type from stored info url = target.Url; text = target.Text; type = target.Type; } } else { // not a valid link; issue warning, set link style to none, and text to invalid target //type = LinkType.None; type = LinkType.Index; text = BrokenLinkDisplayText(link.Target, link.Text); WriteMessage(MessageLevel.Warn, String.Format("Invalid conceptual link target '{0}'.", link.Target)); } // write opening link tag and target info XmlWriter writer = linkNode.InsertAfter(); switch (type) { case LinkType.None: writer.WriteStartElement("span"); writer.WriteAttributeString("class", "nolink"); break; case LinkType.Local: writer.WriteStartElement("a"); writer.WriteAttributeString("href", url); WriteHtmlAttributes(writer, link); break; case LinkType.Index: writer.WriteStartElement("mshelp", "link", "http://msdn.microsoft.com/mshelp"); writer.WriteAttributeString("keywords", link.Target.ToLower()); writer.WriteAttributeString("tabindex", "0"); break; case LinkType.Id: string xhelp = String.Format("ms-xhelp://?Id={0}", link.Target); writer.WriteStartElement("a"); writer.WriteAttributeString("href", xhelp); break; } // write the link text writer.WriteString(text); // write the closing link tag writer.WriteEndElement(); writer.Close(); // delete the original tag linkNode.DeleteSelf(); } }
private void AddTargets(string file, LinkType2 type) { try { XPathDocument document = new XPathDocument(file); XmlTargetCollectionUtilities.AddTargets(targets, document.CreateNavigator(), type); } catch (XmlSchemaException e) { WriteMessage(MessageLevel.Error, String.Format("The reference targets file '{0}' is not valid. The error message is: {1}", file, BuildComponentUtilities.GetExceptionMessage(e))); } catch (XmlException e) { WriteMessage(MessageLevel.Error, String.Format("The reference targets file '{0}' is not well-formed XML. The error message is: {1}", file, BuildComponentUtilities.GetExceptionMessage(e))); } catch (IOException e) { WriteMessage(MessageLevel.Error, String.Format("An access error occured while opening the reference targets file '{0}'. The error message is: {1}", file, BuildComponentUtilities.GetExceptionMessage(e))); } }
private void ResolveContent(XmlDocument document, XPathNavigator start) { // for each kind of shared content element foreach (SharedContentElement element in elements) { // find all such elements XPathNodeIterator nodeIterator = start.Select(element.Path); // Console.WriteLine("Found {0} shared content elements.", nodeIterator.Count); // convert to an array so as not to cause an error when manipulating the document XPathNavigator[] nodes = ConvertIteratorToArray(nodeIterator); // process each element foreach (XPathNavigator node in nodes) { // Console.WriteLine(node.LocalName); // get the key string item = node.Evaluate(element.Item).ToString().ToLower(); // check for missing key if (String.IsNullOrEmpty(item)) { WriteMessage(MessageLevel.Warn, "A shared content element did not specify an item."); } else { // Console.WriteLine("node={0}", node.OuterXml); // extract parameters List <string> parameters = new List <string>(); XPathNodeIterator parameter_nodes = node.Select(element.Parameters); foreach (XPathNavigator parameter_node in parameter_nodes) { string parameter = BuildComponentUtilities.GetInnerXml(parameter_node); // Console.WriteLine("parameter={0}", parameter); parameters.Add(parameter); } // get the content string content = GetContent(item, parameters.ToArray()); // check for missing content if (content == null) { WriteMessage(MessageLevel.Warn, String.Format("Missing shared content item. Tag:'{0}'; Id:'{1}'.", node.LocalName, item)); } else { // store the content in a document fragment XmlDocumentFragment fragment = document.CreateDocumentFragment(); fragment.InnerXml = content; // resolve any shared content in the fragment ResolveContent(document, fragment.CreateNavigator()); //string resolvedContent = fragment.InnerXml; //Console.WriteLine("value = '{0}'", resolvedContent); // look for an attribute name string attribute = node.Evaluate(element.Attribute).ToString(); // insert the resolved content if (String.IsNullOrEmpty(attribute)) { // as mixed content // node.InsertAfter(resolvedContent); XmlWriter writer = node.InsertAfter(); fragment.WriteTo(writer); writer.Close(); } else { // as an attribute XPathNavigator parent = node.CreateNavigator(); parent.MoveToParent(); parent.CreateAttribute(String.Empty, attribute, String.Empty, fragment.InnerText); } } } // keep a reference to the parent element XPathNavigator parentElement = node.CreateNavigator(); parentElement.MoveToParent(); // remove the node node.DeleteSelf(); // if there is no content left in the parent element, make sure it is self-closing if (!parentElement.HasChildren && !parentElement.IsEmptyElement) { //If 'node' was already the root then we will have a blank node now and //doing an InsertAfter() will throw an exception. if (parentElement.Name.Length > 0) { // create a new element XmlWriter attributeWriter = parentElement.InsertAfter(); attributeWriter.WriteStartElement(parentElement.Prefix, parentElement.LocalName, parentElement.NamespaceURI); // copy attributes to it XmlReader attributeReader = parentElement.ReadSubtree(); attributeReader.Read(); attributeWriter.WriteAttributes(attributeReader, false); attributeReader.Close(); // close it attributeWriter.WriteEndElement(); attributeWriter.Close(); // delete the old element parentElement.DeleteSelf(); } else { //if we are inside a tag such as title, removing the content will make it in the //form of <title /> which is not allowed in html. //Since this usually means there is a problem with the shared content or the transforms //leading up to this we will just report the error here. WriteMessage(MessageLevel.Error, "Error replacing item."); } } } } }
private void LoadContent(string file) { WriteMessage(MessageLevel.Info, String.Format("Loading shared content file '{0}'.", file)); try { XmlReader reader = XmlReader.Create(file); try { reader.MoveToContent(); while (!reader.EOF) { if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "item")) { string key = reader.GetAttribute("id").ToLower(); string value = reader.ReadInnerXml(); if (content.ContainsKey(key)) { WriteMessage(MessageLevel.Info, String.Format("Overriding shared content item '{0}' with value in file '{1}'.", key, file)); } content[key] = value; // content.Add(key, value); } else { reader.Read(); } } } finally { reader.Close(); } } catch (IOException e) { WriteMessage(MessageLevel.Error, String.Format("The shared content file '{0}' could not be opened. The error message is: {1}", file, BuildComponentUtilities.GetExceptionMessage(e))); } catch (XmlException e) { WriteMessage(MessageLevel.Error, String.Format("The shared content file '{0}' is not well-formed. The error message is: {1}", file, BuildComponentUtilities.GetExceptionMessage(e))); } catch (XmlSchemaException e) { WriteMessage(MessageLevel.Error, String.Format("The shared content file '{0}' is not valid. The error message is: {1}", file, BuildComponentUtilities.GetExceptionMessage(e))); } }
// the actual work of the component public override void Apply(XmlDocument document, string key) { XPathNodeIterator nodesIterator = document.CreateNavigator().Select(selector); XPathNavigator[] nodes = BuildComponentUtilities.ConvertNodeIteratorToArray(nodesIterator); foreach (XPathNavigator node in nodes) { string reference = node.Value; // check for validity of reference if (validSnippetReference.IsMatch(reference)) { SnippetIdentifier[] identifiers = SnippetIdentifier.ParseReference(reference); if (identifiers.Length == 1) { // one snippet referenced SnippetIdentifier identifier = identifiers[0]; List <StoredSnippet> values; if (snippets.TryGetValue(identifier, out values)) { XmlWriter writer = node.InsertAfter(); writer.WriteStartElement("snippets"); writer.WriteAttributeString("reference", reference); foreach (StoredSnippet value in values) { writer.WriteStartElement("snippet"); writer.WriteAttributeString("language", value.Language); if (colorization.ContainsKey(value.Language)) { WriteColorizedSnippet(ColorizeSnippet(value.Text, colorization[value.Language]), writer); } else { writer.WriteString(value.Text); //writer.WriteString(System.Web.HttpUtility.HtmlDecode(value.Text)); } writer.WriteEndElement(); } writer.WriteEndElement(); writer.Close(); } else { WriteMessage(MessageLevel.Warn, String.Format("No snippet with identifier '{0}' was found.", identifier)); } } else { // multiple snippets referenced // create structure that maps language -> snippets Dictionary <string, List <StoredSnippet> > map = new Dictionary <string, List <StoredSnippet> >(); foreach (SnippetIdentifier identifier in identifiers) { List <StoredSnippet> values; if (snippets.TryGetValue(identifier, out values)) { foreach (StoredSnippet value in values) { List <StoredSnippet> pieces; if (!map.TryGetValue(value.Language, out pieces)) { pieces = new List <StoredSnippet>(); map.Add(value.Language, pieces); } pieces.Add(value); } } } XmlWriter writer = node.InsertAfter(); writer.WriteStartElement("snippets"); writer.WriteAttributeString("reference", reference); foreach (KeyValuePair <string, List <StoredSnippet> > entry in map) { writer.WriteStartElement("snippet"); writer.WriteAttributeString("language", entry.Key); List <StoredSnippet> values = entry.Value; for (int i = 0; i < values.Count; i++) { if (i > 0) { writer.WriteString("\n...\n\n\n"); } writer.WriteString(values[i].Text); // writer.WriteString(System.Web.HttpUtility.HtmlDecode(values[i].Text)); } writer.WriteEndElement(); } writer.WriteEndElement(); writer.Close(); } } else { WriteMessage(MessageLevel.Warn, String.Format("The code reference '{0}' is not well-formed", reference)); } node.DeleteSelf(); } }
public override void Apply(XmlDocument document, string id) { XPathNodeIterator artLinkIterator = document.CreateNavigator().Select(artLinkExpression); XPathNavigator[] artLinks = BuildComponentUtilities.ConvertNodeIteratorToArray(artLinkIterator); foreach (XPathNavigator artLink in artLinks) { string name = artLink.GetAttribute("target", String.Empty).ToLower(); if (targets.ContainsKey(name)) { ArtTarget target = targets[name]; // evaluate the path string path = document.CreateNavigator().Evaluate(target.OutputXPath).ToString(); if (target.baseOutputPath != null) { path = Path.Combine(target.baseOutputPath, path); } string outputPath = Path.Combine(path, target.Name); string targetDirectory = Path.GetDirectoryName(outputPath); if (!Directory.Exists(targetDirectory)) { Directory.CreateDirectory(targetDirectory); } if (File.Exists(target.InputPath)) { if (File.Exists(outputPath)) { File.SetAttributes(outputPath, FileAttributes.Normal); } File.Copy(target.InputPath, outputPath, true); } else { WriteMessage(MessageLevel.Warn, String.Format("The file '{0}' for the art target '{1}' was not found.", target.InputPath, name)); } // Get the relative art path for HXF generation. int index = target.LinkPath.IndexOf('/'); string artPath = target.LinkPath.Substring(index + 1, target.LinkPath.Length - (index + 1)); FileCreatedEventArgs fe = new FileCreatedEventArgs(artPath, Path.GetDirectoryName(path)); OnComponentEvent(fe); XmlWriter writer = artLink.InsertAfter(); writer.WriteStartElement("img"); if (!String.IsNullOrEmpty(target.Text)) { writer.WriteAttributeString("alt", target.Text); } if (target.FormatXPath == null) { writer.WriteAttributeString("src", target.LinkPath); } else { // WebDocs way, which uses the 'format' xpath expression to calculate the target path // and then makes it relative to the current page if the 'relative-to' attribute is // used. string src = BuildComponentUtilities.EvalXPathExpr(document, target.FormatXPath, "key", Path.GetFileName(outputPath)); if (target.RelativeToXPath != null) { src = BuildComponentUtilities.GetRelativePath(src, BuildComponentUtilities.EvalXPathExpr(document, target.RelativeToXPath, "key", id)); } writer.WriteAttributeString("src", src); } writer.WriteEndElement(); writer.Close(); artLink.DeleteSelf(); } else { WriteMessage(MessageLevel.Warn, String.Format("Unknown art target '{0}'", name)); } } }