// EFW - Removed unused properties #region Constructor //===================================================================== /// <summary> /// Constructor /// </summary> /// <param name="targetDir">The target directory</param> /// <param name="urlExp">The URL expression</param> /// <param name="textExp">The text (title) expression</param> /// <param name="linkTextExp">The alternate link text expression</param> /// <param name="typeOfLink">The link type</param> /// <exception cref="ArgumentNullException">This is thrown if the directory, URL expression, or either /// text expression is null.</exception> public TargetDirectory(string targetDir, XPathExpression urlExp, XPathExpression textExp, XPathExpression linkTextExp, ConceptualLinkType typeOfLink) { if (targetDir == null) { throw new ArgumentNullException("targetDir"); } if (urlExp == null) { throw new ArgumentNullException("urlExp"); } if (textExp == null) { throw new ArgumentNullException("textExp"); } // EFW - Added support for alternate link text expression if (linkTextExp == null) { throw new ArgumentNullException("linkTextExp"); } directory = targetDir; urlExpression = urlExp; textExpression = textExp; linkTextExpression = linkTextExp; linkType = typeOfLink; }
// EFW - Removed unused properties #region Constructor //===================================================================== /// <summary> /// Constructor /// </summary> /// <param name="targetDir">The target directory</param> /// <param name="urlExp">The URL expression</param> /// <param name="textExp">The text (title) expression</param> /// <param name="linkTextExp">The alternate link text expression</param> /// <param name="typeOfLink">The link type</param> /// <exception cref="ArgumentNullException">This is thrown if the directory, URL expression, or either /// text expression is null.</exception> public TargetDirectory(string targetDir, XPathExpression urlExp, XPathExpression textExp, XPathExpression linkTextExp, ConceptualLinkType typeOfLink) { // EFW - Added support for alternate link text expression directory = targetDir ?? throw new ArgumentNullException(nameof(targetDir)); urlExpression = urlExp ?? throw new ArgumentNullException(nameof(urlExp)); textExpression = textExp ?? throw new ArgumentNullException(nameof(textExp)); linkTextExpression = linkTextExp ?? throw new ArgumentNullException(nameof(linkTextExp)); linkType = typeOfLink; }
//===================================================================== /// <summary> /// Constructor /// </summary> /// <param name="targetUrl">The target URL</param> /// <param name="targetText">The target's link text</param> /// <param name="typeOfLink">The type of link</param> /// <exception cref="ArgumentNullException">This is thrown if the target URL or text is null</exception> public TargetInfo(string targetUrl, string targetText, ConceptualLinkType typeOfLink) { if (targetText == null) { throw new ArgumentNullException(nameof(targetText)); } this.Url = targetUrl ?? throw new ArgumentNullException(nameof(targetUrl)); this.Text = targetText.Trim(); this.LinkType = typeOfLink; }
public TargetInfo(string url, string text, ConceptualLinkType type) { if (url == null) { throw new ArgumentNullException("url"); } if (text == null) { throw new ArgumentNullException("url"); } this._url = url; this._text = text; this._type = type; }
//===================================================================== /// <summary> /// Constructor /// </summary> /// <param name="targetUrl">The target URL</param> /// <param name="targetText">The target's link text</param> /// <param name="typeOfLink">The type of link</param> /// <exception cref="ArgumentNullException">This is thrown if the target URL or text is null</exception> public TargetInfo(string targetUrl, string targetText, ConceptualLinkType typeOfLink) { if(targetUrl == null) throw new ArgumentNullException("targetUrl"); if(targetText == null) throw new ArgumentNullException("targetText"); this.Url = targetUrl; // EFW - Use String.Empty or trim off unwanted whitespace this.Text = String.IsNullOrEmpty(targetText) ? String.Empty : targetText.Trim(); this.LinkType = typeOfLink; }
public ConceptualTargetDirectory(string directory, XPathExpression urlExpression, XPathExpression textExpression, ConceptualLinkType type) : this(directory, type) { if (urlExpression == null) { throw new ArgumentNullException("urlExpression"); } if (textExpression == null) { throw new ArgumentNullException("textExpression"); } this._urlExpression = urlExpression; this._textExpression = textExpression; }
public ReferenceLinkComponent(BuildAssembler assembler, XPathNavigator configuration) : base(assembler, configuration) { _hasMsdnStorage = false; _hasTopicLinks = false; _linkTarget = "_blank"; _hrefFormat = "{0}.htm"; _baseLinkType = ConceptualLinkType.Null; _buildController = BuildComponentController.Controller; this.ParseReferenceConfiguration(configuration); this.ParseConceptualConfiguration(configuration); }
//===================================================================== /// <summary> /// Constructor /// </summary> /// <param name="targetUrl">The target URL</param> /// <param name="targetText">The target's link text</param> /// <param name="typeOfLink">The type of link</param> /// <exception cref="ArgumentNullException">This is thrown if the target URL or text is null</exception> public TargetInfo(string targetUrl, string targetText, ConceptualLinkType typeOfLink) { if (targetUrl == null) { throw new ArgumentNullException("targetUrl"); } if (targetText == null) { throw new ArgumentNullException("targetText"); } this.Url = targetUrl; // EFW - Use String.Empty or trim off unwanted whitespace this.Text = String.IsNullOrEmpty(targetText) ? String.Empty : targetText.Trim(); this.LinkType = typeOfLink; }
public ConceptualTargetDirectory(string directory, ConceptualLinkType type) { if (directory == null) { throw new ArgumentNullException("directory"); } this._directory = directory; this._type = type; _fileExpression = XPathExpression.Compile( "concat($target,'.cmp.htm')"); _urlExpression = XPathExpression.Compile( "concat(/metadata/topic/@id,'.htm')"); _textExpression = XPathExpression.Compile( "string(/metadata/topic/title)"); }
// EFW - Removed unused properties #region Constructor //===================================================================== /// <summary> /// Constructor /// </summary> /// <param name="targetDir">The target directory</param> /// <param name="urlExp">The URL expression</param> /// <param name="textExp">The text (title) expression</param> /// <param name="linkTextExp">The alternate link text expression</param> /// <param name="typeOfLink">The link type</param> /// <exception cref="ArgumentNullException">This is thrown if the directory, URL expression, or either /// text expression is null.</exception> public TargetDirectory(string targetDir, XPathExpression urlExp, XPathExpression textExp, XPathExpression linkTextExp, ConceptualLinkType typeOfLink) { if(targetDir == null) throw new ArgumentNullException("targetDir"); if(urlExp == null) throw new ArgumentNullException("urlExp"); if(textExp == null) throw new ArgumentNullException("textExp"); // EFW - Added support for alternate link text expression if(linkTextExp == null) throw new ArgumentNullException("linkTextExp"); directory = targetDir; urlExpression = urlExp; textExpression = textExp; linkTextExpression = linkTextExp; linkType = typeOfLink; }
public ConceptualLinkComponent(BuildAssembler assembler, XPathNavigator configuration) : base(assembler, configuration) { _baseLinkType = ConceptualLinkType.Null; _targetController = ConceptualTargetController.GetInstance("conceptual"); XPathNavigator optionsNode = configuration.SelectSingleNode("options"); if (optionsNode != null) { string showBrokenLinkTextValue = configuration.GetAttribute( "showBrokenLinkText", String.Empty); if (!String.IsNullOrEmpty(showBrokenLinkTextValue)) { _showBrokenLinkText = Convert.ToBoolean(showBrokenLinkTextValue); } string tempText = optionsNode.GetAttribute("type", String.Empty); if (!String.IsNullOrEmpty(tempText)) { try { // convert the link type to an enumeration member _baseLinkType = (ConceptualLinkType)Enum.Parse(typeof(ConceptualLinkType), tempText, true); } catch (ArgumentException) { this.WriteMessage(MessageLevel.Error, String.Format( "'{0}' is not a valid link type.", tempText)); } } tempText = optionsNode.GetAttribute("showText", String.Empty); if (!String.IsNullOrEmpty(tempText)) { _showText = tempText.Equals("true", StringComparison.OrdinalIgnoreCase); } } XPathNodeIterator targetsNodes = configuration.Select("targets"); foreach (XPathNavigator targetsNode in targetsNodes) { // the base directory containing target; required string baseValue = targetsNode.GetAttribute("base", String.Empty); if (String.IsNullOrEmpty(baseValue)) { this.WriteMessage(MessageLevel.Error, "Every targets element must have a base attribute that specifies the path to a directory of target metadata files."); } baseValue = Environment.ExpandEnvironmentVariables(baseValue); if (!Directory.Exists(baseValue)) { this.WriteMessage(MessageLevel.Error, String.Format( "The specified target metadata directory '{0}' does not exist.", baseValue)); } // an xpath expression to construct a file name // (not currently used; pattern is hard-coded to $target.cmp.xml string filesValue = targetsNode.GetAttribute("files", String.Empty); // an xpath expression to construct a url string urlValue = targetsNode.GetAttribute("url", String.Empty); XPathExpression urlExpression; if (String.IsNullOrEmpty(urlValue)) { urlExpression = XPathExpression.Compile( "concat(/metadata/topic/@id,'.htm')"); } else { urlExpression = CompileXPathExpression(urlValue); } // an xpath expression to construct link text string textValue = targetsNode.GetAttribute("text", String.Empty); XPathExpression textExpression; if (String.IsNullOrEmpty(textValue)) { textExpression = XPathExpression.Compile( "string(/metadata/topic/title)"); } else { textExpression = CompileXPathExpression(textValue); } // the type of link to create to targets found in the directory; required string typeValue = targetsNode.GetAttribute("type", String.Empty); if (String.IsNullOrEmpty(typeValue)) { WriteMessage(MessageLevel.Error, "Every targets element must have a type attribute that specifies what kind of link to create to targets found in that directory."); } // convert the link type to an enumeration member ConceptualLinkType type = ConceptualLinkType.None; try { type = (ConceptualLinkType)Enum.Parse(typeof(ConceptualLinkType), typeValue, true); } catch (ArgumentException) { this.WriteMessage(MessageLevel.Error, String.Format( "'{0}' is not a valid link type.", typeValue)); } // We have all the required information; create a TargetDirectory // and add it to our collection ConceptualTargetDirectory targetDirectory = new ConceptualTargetDirectory(baseValue, urlExpression, textExpression, type); _targetController.Add(targetDirectory); } this.WriteMessage(MessageLevel.Info, String.Format( "Collected {0} targets directories.", _targetController.Count)); }
public override void Apply(XmlDocument document, string key) { // find links XPathNodeIterator linkIterator = document.CreateNavigator().Select(conceptualLinks); if (linkIterator == null || linkIterator.Count == 0) { return; } // 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; ConceptualLinkType type = ConceptualLinkType.None; bool isValidLink = validGuid.IsMatch(link.Target); if (isValidLink) { // a valid link; try to fetch target info TargetInfo target = _targetController[link.Target]; 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; if (link.IsAnchored) { url += link.Anchor; } if (_showText && !String.IsNullOrEmpty(link.Text)) { text = link.Text; } else { 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; text = BrokenLinkDisplayText(link.Target, link.Text); WriteMessage(MessageLevel.Warn, String.Format( "Invalid conceptual link target '{0}'.", link.Target)); } // Override the type, if valid... if (_baseLinkType != ConceptualLinkType.Null && type != ConceptualLinkType.None) { type = _baseLinkType; } // write opening link tag and target info XmlWriter writer = linkNode.InsertAfter(); switch (type) { case ConceptualLinkType.None: writer.WriteStartElement("span"); writer.WriteAttributeString("class", "nolink"); break; case ConceptualLinkType.Local: writer.WriteStartElement("a"); writer.WriteAttributeString("href", url); break; case ConceptualLinkType.Index: writer.WriteStartElement("mshelp", "link", "http://msdn.microsoft.com/mshelp"); writer.WriteAttributeString("keywords", link.Target.ToLower()); writer.WriteAttributeString("tabindex", "0"); break; case ConceptualLinkType.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(); } }
//===================================================================== /// <inheritdoc /> public override void Initialize(XPathNavigator configuration) { TargetDirectory targetDirectory; XPathExpression urlExp, textExp, linkTextExp; ConceptualLinkType linkType = ConceptualLinkType.None; string attribute, basePath; targetDirectories = new TargetDirectoryCollection(); // This is a simple cache. If the cache size limit is reached, it clears the cache and starts over cache = new Dictionary <string, TargetInfo>(CacheSize); attribute = (string)configuration.Evaluate("string(showBrokenLinkText/@value)"); if (!String.IsNullOrWhiteSpace(attribute)) { showBrokenLinkText = Convert.ToBoolean(attribute, CultureInfo.InvariantCulture); } foreach (XPathNavigator navigator in configuration.Select("targets")) { basePath = navigator.GetAttribute("base", String.Empty); if (String.IsNullOrEmpty(basePath)) { base.WriteMessage(MessageLevel.Error, "Every targets element must have a base attribute " + "that specifies the path to a directory of target metadata files."); } basePath = Environment.ExpandEnvironmentVariables(basePath); if (!Directory.Exists(basePath)) { base.WriteMessage(MessageLevel.Error, "The specified target metadata directory '{0}' " + "does not exist.", basePath); } attribute = navigator.GetAttribute("url", String.Empty); if (String.IsNullOrEmpty(attribute)) { urlExp = XPathExpression.Compile("concat(/metadata/topic/@id,'.htm')"); } else { urlExp = this.CompileXPathExpression(attribute); } attribute = navigator.GetAttribute("text", String.Empty); if (String.IsNullOrEmpty(attribute)) { textExp = XPathExpression.Compile("string(/metadata/topic/title)"); } else { textExp = this.CompileXPathExpression(attribute); } // EFW - Added support for linkText option attribute = navigator.GetAttribute("linkText", String.Empty); if (String.IsNullOrEmpty(attribute)) { linkTextExp = XPathExpression.Compile("string(/metadata/topic/linkText)"); } else { linkTextExp = this.CompileXPathExpression(attribute); } attribute = navigator.GetAttribute("type", String.Empty); if (String.IsNullOrEmpty(attribute)) { base.WriteMessage(MessageLevel.Error, "Every targets element must have a type attribute " + "that specifies what kind of link to create to targets found in that directory."); } if (!Enum.TryParse <ConceptualLinkType>(attribute, true, out linkType)) { base.WriteMessage(MessageLevel.Error, "'{0}' is not a valid link type.", attribute); } targetDirectory = new TargetDirectory(basePath, urlExp, textExp, linkTextExp, linkType); targetDirectories.Add(targetDirectory); } base.WriteMessage(MessageLevel.Info, "Collected {0} targets directories.", targetDirectories.Count); }
private void ProcessConceptualLink(XPathNavigator linkNode, string key) { // extract link information ConceptualLinkInfo link = ConceptualLinkInfo.Create(linkNode); if (link == null) { this.WriteMessage(MessageLevel.Warn, "Invalid conceptualLink element."); #if DEBUG this.WriteMessage(MessageLevel.Warn, linkNode.OuterXml); #endif } else { // determine url, text, and link type string url = null; string text = null; ConceptualLinkType type = ConceptualLinkType.None; bool isValidLink = validGuid.IsMatch(link.Target); if (isValidLink) { // a valid link; try to fetch target info TargetInfo target = _targetController[link.Target]; 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; if (link.IsAnchored) { url += link.Anchor; } if (_showText && !String.IsNullOrEmpty(link.Text)) { text = link.Text; } else { 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; text = BrokenLinkDisplayText(link.Target, link.Text); WriteMessage(MessageLevel.Warn, String.Format( "Invalid conceptual link target '{0}'.", link.Target)); } // Override the type, if valid... if (_baseLinkType != ConceptualLinkType.Null && type != ConceptualLinkType.None) { type = _baseLinkType; } // write opening link tag and target info XmlWriter writer = linkNode.InsertAfter(); switch (type) { case ConceptualLinkType.None: writer.WriteStartElement("span"); writer.WriteAttributeString("class", "nolink"); break; case ConceptualLinkType.Local: writer.WriteStartElement("a"); writer.WriteAttributeString("href", url); break; case ConceptualLinkType.Index: writer.WriteStartElement("mshelp", "link", "http://msdn.microsoft.com/mshelp"); writer.WriteAttributeString("keywords", link.Target.ToLower()); writer.WriteAttributeString("tabindex", "0"); break; case ConceptualLinkType.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(); } }