Esempio n. 1
0
        public bool Convert(DitaElement bodyElement, List <DitaPageSectionJson> sections, string fileName, out string body)
        {
            StringBuilder bodyStringBuilder = new StringBuilder();

            Sections = sections;
            FileName = fileName;

            if (bodyElement != null)
            {
                if (bodyElement.IsContainer)
                {
                    foreach (DitaElement childElement in bodyElement?.Children)
                    {
                        bodyStringBuilder.Append(Convert(childElement));
                    }
                }
                else
                {
                    bodyStringBuilder.Append(bodyElement.InnerText);
                }
            }

            body = bodyStringBuilder.ToString();

            return(true);
        }
Esempio n. 2
0
        // Parse the title from the book map
        private void ParseBookMapTitle()
        {
            DitaElement titleElement = RootMap.RootElement.FindOnlyChild("booktitle");

            AddChildDitaElementTextToDictionary(titleElement, "mainbooktitle", BookTitle);
            AddChildDitaElementTextToDictionary(titleElement, "booktitlealt", BookTitle);
        }
Esempio n. 3
0
        // Build a dictionary of elements in the document, by id
        private void ParseElementIds(DitaElement parentElement)
        {
            if (parentElement != null)
            {
                // Does this element have an id?
                string id = parentElement.AttributeValueOrDefault("id", string.Empty);
                if (!string.IsNullOrEmpty(id))
                {
                    if (!ElementsById.ContainsKey(id))
                    {
                        ElementsById.Add(id, parentElement);
                    }
                    else
                    {
                        Trace.TraceWarning($"Duplicate element id {id} found in {FileName}.");
                    }
                }

                // Parse the children
                if (parentElement.Children != null)
                {
                    foreach (DitaElement childElement in parentElement.Children)
                    {
                        ParseElementIds(childElement);
                    }
                }
            }
        }
Esempio n. 4
0
        protected List <DitaElement> FindChildren(string[] types, DitaElement parentElement)
        {
            List <DitaElement> result = null;

            if (IsContainer)
            {
                // Are any of our direct children of this type?
                result = parentElement?.Children?.Where(e => types.Contains(e.Type)).ToList();

                if (result?.Count == 0)
                {
                    // Try finding children of children
                    foreach (DitaElement childElement in parentElement.Children)
                    {
                        result = FindChildren(types, childElement);
                        if (result?.Count != 0)
                        {
                            break;
                        }
                    }
                }
            }

            return(result);
        }
Esempio n. 5
0
 private void ResolveKeywords(DitaElement parentElement, DitaCollection collection)
 {
     if (parentElement != null)
     {
         if (parentElement.Type == "keyword")
         {
             string keyref = parentElement.AttributeValueOrDefault("keyref", String.Empty);
             if (!string.IsNullOrWhiteSpace(keyref))
             {
                 // Try to find the referred to file
                 DitaKeyDef keyDef = collection.GetKeyDefByKey(keyref);
                 if (keyDef != null)
                 {
                     if (!string.IsNullOrWhiteSpace(keyDef.Keywords))
                     {
                         parentElement.SetInnerText(keyDef.Keywords);
                     }
                 }
             }
         }
         else
         {
             // Check the child elements
             if (parentElement.Children != null)
             {
                 foreach (DitaElement childElement in parentElement.Children)
                 {
                     ResolveKeywords(childElement, collection);
                 }
             }
         }
     }
 }
Esempio n. 6
0
 // Parse the metadata from the given element?
 private void ParseMetaCategories(DitaElement parentElement)
 {
     try
     {
         List <DitaElement> categoriesData = parentElement?.FindChildren("category");
         if (categoriesData != null)
         {
             foreach (DitaElement categoryData in categoriesData)
             {
                 foreach (DitaElement data in categoryData.Children)
                 {
                     if (data?.Attributes.ContainsKey("name") ?? false)
                     {
                         if (BookMeta.ContainsKey(data?.Attributes["name"]))
                         {
                             Trace.TraceWarning($"BookMeta already contains a value for {data?.Attributes["name"]}");
                         }
                         else
                         {
                             BookMeta.Add(data?.Attributes["name"], data?.Attributes["value"]);
                         }
                     }
                 }
             }
         }
     }
     catch (Exception ex)
     {
         Trace.TraceError(ex);
     }
 }
Esempio n. 7
0
 // Replaces the values in this element with those copied from another element
 public void Copy(DitaElement sourceElement)
 {
     Type        = sourceElement.Type;
     Attributes  = sourceElement.Attributes;
     IsContainer = sourceElement.IsContainer;
     Children    = sourceElement.Children;
     InnerText   = sourceElement.InnerText;
 }
Esempio n. 8
0
        // Parse the book meta data from the book map
        private void ParseBookMapBookMeta()
        {
            DitaElement bookMetaElement = RootMap.RootElement.FindOnlyChild("bookmeta");

            ParseBookMapVersion(bookMetaElement);
            ParseBookMapReleaseDate(bookMetaElement);

            // Everything in category
            ParseMetaCategories(bookMetaElement);
        }
Esempio n. 9
0
        // Construct from a single topic
        public DitaPageJson(DitaFile file, DitaCollection collection)
        {
            Collection = collection;

            // Get the title of the page
            Title = DitaFile.FixSpecialCharacters(file.Title);

            // Create the file name
            FileName = file.NewFileName ?? file.FileName;
            FileName = Path.ChangeExtension(FileName, ".json");

            OriginalFileName = file.FileName;

            // Find the body element
            string bodyElementName = null;

            if (DitaFile.DitaFileBodyElement.ContainsKey(file.GetType()))
            {
                bodyElementName = DitaFile.DitaFileBodyElement[file.GetType()]();
            }

            if (!string.IsNullOrEmpty(bodyElementName))
            {
                DitaElement bodyElement = file.RootElement.FindOnlyChild(bodyElementName);

                if (bodyElement != null)
                {
                    Sections = new List <DitaPageSectionJson>();

                    // Convert the body to html
                    DitaElementToHtmlConverter htmlConverter = new DitaElementToHtmlConverter(collection);
                    htmlConverter.Convert(bodyElement, Sections, file.FileName, out string bodyHtml);
                    BodyHtml = bodyHtml;

                    // Convert the body to text
                    DitaElementToTextConverter textConverter = new DitaElementToTextConverter();
                    textConverter.Convert(bodyElement, out string bodyText);
                    BodyText = bodyText;
                }
                else
                {
                    Trace.TraceWarning($"Body element not found in {file.FileName}.");
                }
            }
            else
            {
                Trace.TraceWarning($"No body element identified in {file.FileName}.");
            }

            IsEmpty = string.IsNullOrEmpty(BodyText) || string.IsNullOrEmpty(Title);
        }
Esempio n. 10
0
        // Wraps a dita element in another dita element, if needed to output correct html
        // For instance, wrap tables, sections, figures, etc in an <a name="..."> for instance
        private DitaElement PrependDitaElementIfNeeded(DitaElement inputElement)
        {
            string id = inputElement.AttributeValueOrDefault("id", null);

            // If this object has an id, wrap it in an a, name
            if (!string.IsNullOrEmpty(id))
            {
                DitaElement outputElement = new DitaElement("a", false, null, inputElement.Parent, inputElement.PreviousSibling);
                outputElement.Attributes.Add("name", id);
                return(outputElement);
            }

            return(null);
        }
Esempio n. 11
0
 // Default constructor
 public DitaElement(string type, bool isContainer = false, string innerText = null, DitaElement parent = null, DitaElement previousSibling = null)
 {
     Type            = type;
     IsContainer     = isContainer;
     Parent          = parent;
     PreviousSibling = previousSibling;
     if (IsContainer)
     {
         Children = new List <DitaElement>();
     }
     else
     {
         InnerText = innerText;
     }
 }
        private string Convert(DitaElement element)
        {
            if (element.IsContainer)
            {
                StringBuilder elementStringBuilder = new StringBuilder();

                foreach (DitaElement childElement in element.Children)
                {
                    elementStringBuilder.AppendLine(Convert(childElement));
                }

                return(elementStringBuilder.ToString());
            }
            else
            {
                return($"{element}");
            }
        }
Esempio n. 13
0
        // Tries to add the text of the given element to the dictionary
        private bool AddChildDitaElementTextToDictionary(DitaElement parentElement, string type,
                                                         Dictionary <string, string> dictionary)
        {
            // Try to find the child elements that match the type
            List <DitaElement> childElements = parentElement.FindChildren(type);

            if (childElements?.Count > 0)
            {
                foreach (DitaElement childElement in childElements)
                {
                    dictionary.Add(type, childElement.InnerText);
                }

                return(true);
            }

            return(false);
        }
Esempio n. 14
0
        // Does a given image element refer to SVG?
        private bool IsImageElementSvg(DitaElement imageElement)
        {
            if (imageElement != null)
            {
                if (imageElement.Type == "image")
                {
                    string extension = Path.GetExtension(imageElement.AttributeValueOrDefault("href", ""));

                    if ((extension?.Equals(".svg", StringComparison.OrdinalIgnoreCase) ?? false) ||
                        (extension?.Equals(".image", StringComparison.OrdinalIgnoreCase) ?? false))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        // Ingest an XmlNode and recursively parse it to create a group of DitaElements
        public DitaElement Convert(XmlNode inputNode, DitaElement parentElement = null, DitaElement previousSiblingElement = null)
        {
            // What type of element are we creating
            string type = inputNode?.Name;

            // Does this node/element have children
            bool isContainer = !IsNodeOnlyText(inputNode, out string innerText);

            if (!isContainer)
            {
                innerText = CleanInnerText(innerText);
            }

            // Create the new DITA element
            DitaElement outputElement = new DitaElement(type, isContainer, innerText, parentElement, previousSiblingElement);

            // Add the attributes
            if (inputNode?.Attributes != null)
            {
                foreach (XmlAttribute attribute in inputNode?.Attributes)
                {
                    outputElement.Attributes.Add(attribute.Name, attribute.InnerText);
                }
            }

            // Add the children of this node/element, if any
            // ReSharper disable once InvertIf
            if (isContainer && inputNode?.ChildNodes != null)
            {
                DitaElement previousElement = null;
                foreach (XmlNode childNode in inputNode.ChildNodes)
                {
                    DitaElement childElement = Convert(childNode, outputElement, previousElement);
                    outputElement.Children.Add(childElement);
                    previousElement = childElement;
                }
            }

            return(outputElement);
        }
Esempio n. 16
0
        // Parse the version of the document
        private void ParseBookMapVersion(DitaElement bookMetaElement)
        {
            // Try checking the publisher information section
            DitaElement publisherInformationElement = bookMetaElement?.FindOnlyChild("publisherinformation");
            DitaElement publishedElement            = publisherInformationElement?.FindChildren("published")?.Last();
            DitaElement revisionIdElement           = publishedElement?.FindOnlyChild("revisionid");
            string      version = revisionIdElement?.ToString();

            // Try checking the prodinfo section
            if (string.IsNullOrWhiteSpace(version) || version == "ProductVersionNumber")
            {
                DitaElement prodinfoElement = bookMetaElement?.FindOnlyChild("prodinfo");
                DitaElement vrmlistElement  = prodinfoElement?.FindOnlyChild("vrmlist");
                DitaElement vrmElement      = vrmlistElement?.FindChildren("vrm")?[0];
                version = vrmElement?.Attributes?["version"];
            }

            if (!string.IsNullOrWhiteSpace(version))
            {
                BookMeta.Add("version", version);
            }
        }
        public bool Convert(DitaElement bodyElement, out string body)
        {
            StringBuilder bodyStringBuilder = new StringBuilder();

            if (bodyElement != null)
            {
                if (bodyElement.IsContainer)
                {
                    foreach (DitaElement childElement in bodyElement?.Children)
                    {
                        bodyStringBuilder.Append(Convert(childElement));
                    }
                }
                else
                {
                    bodyStringBuilder.Append(bodyElement);
                }
            }

            body = bodyStringBuilder.ToString();

            return(true);
        }
Esempio n. 18
0
        // Parse the date of the document
        private void ParseBookMapReleaseDate(DitaElement bookMetaElement)
        {
            DitaElement publisherInformationElement = bookMetaElement?.FindOnlyChild("publisherinformation");
            DitaElement publishedElement            = publisherInformationElement?.FindChildren("published")?.Last();
            DitaElement completedElement            = publishedElement?.FindOnlyChild("completed");
            string      year  = completedElement?.FindOnlyChild("year")?.ToString();
            string      month = completedElement?.FindOnlyChild("month")?.ToString();
            string      day   = completedElement?.FindOnlyChild("day")?.ToString();

            if (!string.IsNullOrWhiteSpace(year) && !string.IsNullOrWhiteSpace(month) && !string.IsNullOrWhiteSpace(day))
            {
                try
                {
                    // Is this a valid date?
                    DateTime publishDate = new DateTime(int.Parse(year), int.Parse(month), int.Parse(day));
                    BookMeta.Add("published date", $"{publishDate.Day}/{publishDate.Month}/{publishDate.Year} 00:00:00");
                }
                catch
                {
                    //
                }
            }
        }
Esempio n. 19
0
        private string Convert(DitaElement element)
        {
            StringBuilder elementStringBuilder = new StringBuilder();

            // Does this element need to be wrapped by another element?
            DitaElement prependElement = PrependDitaElementIfNeeded(element);

            if (prependElement != null)
            {
                elementStringBuilder.Append(Convert(prependElement));
            }

            // Determine the new html tag and attributes
            string htmlTag = ConvertDitaTagToHtmlTag(element);
            Dictionary <string, string> htmlAttributes = ConvertDitaTagAttributesToHtmlTagAttributes(element);

            AddHtmlTagAttributes(htmlAttributes, element);

            // If this is a parent, then add the children
            if (element.IsContainer)
            {
                elementStringBuilder.Append(HtmlOpeningTag(htmlTag, htmlAttributes));

                foreach (DitaElement childElement in element.Children)
                {
                    elementStringBuilder.Append(Convert(childElement));
                }

                elementStringBuilder.Append(HtmlClosingTag(htmlTag));
            }
            else
            {
                elementStringBuilder.Append($"{HtmlOpeningTag(htmlTag, htmlAttributes)}{element.InnerText}{HtmlClosingTag(htmlTag)}");
            }

            return(elementStringBuilder.ToString());
        }
Esempio n. 20
0
        // Parse the  meta date from the map
        private void ParseMapMeta()
        {
            DitaElement bookMetaElement = RootMap.RootElement.FindOnlyChild("topicmeta");

            ParseMetaCategories(bookMetaElement);
        }
Esempio n. 21
0
        // Takes a DITA "tag" and returns the corresponding HTML tag
        private string ConvertDitaTagToHtmlTag(DitaElement element)
        {
            switch (element.Type)
            {
            case "b": return("strong");

            case "colspec":
                TableColumnIndex++;
                FixUpTableColumnSpecs();
                _tableColumnSpecs[TableColumnIndex] = new DitaTableColumnSpec {
                    Number = (TableColumnIndex + 1)
                };

                return("");

            case "entry":
                TableRowColumnIndex++;
                if (element.Parent?.Parent?.Type == "thead" || element.AttributeValueOrDefault("class", "") == "th")
                {
                    return("th");
                }

                return("td");

            case "fig": return("figure");

            case "image":
                // Is this referring to an SVG or other type of image?
                if (IsImageElementSvg(element))
                {
                    return("object");
                }

                return("img");

            case "keyword": return("");

            case "row":
                TableRowColumnIndex = -1;
                return("tr");

            case "steps":
                return("ol");

            case "step":
                return("li");

            case "table":
                TableColumnIndex  = -1;
                _tableColumnSpecs = null;
                break;

            case "tgroup":
                TableColumnIndex  = -1;
                _tableColumnSpecs = null;
                return("");

            case "title":
                if (element.Parent?.Type == "section")
                {
                    // Create a reference to this section, if this is the title of the section
                    if (CurrentSection != null)
                    {
                        if (string.IsNullOrEmpty(CurrentSection.Title) && !string.IsNullOrEmpty(CurrentSection.Anchor))
                        {
                            CurrentSection.Title = element.ToString();
                            Sections.Add(CurrentSection);
                            CurrentSection = null;
                        }
                    }

                    return("h3");
                }

                return("h4");

            case "xref":
                return("a");

            case "#text": return("");
            }

            return(element.Type);
        }
Esempio n. 22
0
        // Converts DITA tag attributes to html tag attributes
        private Dictionary <string, string> ConvertDitaTagAttributesToHtmlTagAttributes(DitaElement element)
        {
            Dictionary <string, string> htmlAttributes = new Dictionary <string, string>();

            foreach (string ditaAttributeKey in element.Attributes.Keys)
            {
                (string newKey, string newValue) = ConvertDitaTagAttributeToHtmlTagAttribute(ditaAttributeKey, element.Attributes[ditaAttributeKey], element);
                if (!string.IsNullOrWhiteSpace(newKey))
                {
                    htmlAttributes.Add(newKey, newValue);
                }
            }

            return(htmlAttributes);
        }
Esempio n. 23
0
        // Resolves conrefs in this file
        private void ResolveConRefs(DitaElement parentElement, DitaCollection collection)
        {
            if (parentElement != null)
            {
                bool updated = false;

                // Does this element have a conref?
                string conref = parentElement.AttributeValueOrDefault("conref", String.Empty);
                if (!string.IsNullOrEmpty(conref))
                {
                    // We expect the conref to be in the form of filename.xml#fileid/elementid
                    Regex           conRefRegex           = new Regex("^(.*)#(.*)/(.*)$", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase);
                    MatchCollection conRefMatchCollection = conRefRegex.Matches(conref);
                    if (conRefMatchCollection?.Count > 0 && (conRefMatchCollection[0].Groups.Count == 4))
                    {
                        // Extract the components of the conref
                        string refFileName  = conRefMatchCollection[0].Groups[1].Value;
                        string refFileId    = conRefMatchCollection[0].Groups[2].Value;
                        string refElementId = conRefMatchCollection[0].Groups[3].Value;

                        if (Path.GetFileNameWithoutExtension(refFileName) != refFileId)
                        {
                            Trace.TraceWarning($"conref file name '{refFileName}' is not equal to file id '{refFileId}'.");
                        }

                        // Try to find the file that this conref refers to
                        DitaFile refFile = collection.GetFileByName(refFileName);
                        if (refFile != null)
                        {
                            // Does the references element exist in this file
                            if (refFile.ElementsById.ContainsKey(refElementId))
                            {
                                DitaElement refElement = refFile.ElementsById[refElementId];
                                // Copy the refernce element
                                parentElement.Copy(refElement);
                                updated = true;
                            }
                            else
                            {
                                Trace.TraceWarning($"Element '{refElementId}' not found in file '{refFileName}'.");
                            }
                        }
                        else
                        {
                            Trace.TraceWarning($"Can't find file '{refFileName}' referenced in file '{FileName}'.");
                        }
                    }
                    else
                    {
                        Trace.TraceWarning($"conref {conref} not in expected format.");
                    }
                }

                // Update child references
                if (!updated && parentElement.Children != null)
                {
                    foreach (DitaElement childElement in parentElement.Children)
                    {
                        ResolveConRefs(childElement, collection);
                    }
                }
            }
        }
Esempio n. 24
0
        // Converts a single dita tag attribute to an html attribute
        private (string newKey, string newValue) ConvertDitaTagAttributeToHtmlTagAttribute(string key, string value, DitaElement element)
        {
            switch (element.Type)
            {
            case "a":
                return(key, value);

            case "colspec":
                if (key == "colname")
                {
                    FixUpTableColumnSpecs();
                    _tableColumnSpecs[TableColumnIndex].Name = value;
                }

                if (key == "colwidth")
                {
                    FixUpTableColumnSpecs();
                    _tableColumnSpecs[TableColumnIndex].Width = value;
                }

                if (key == "colnum")
                {
                    if (int.TryParse(value, out int colnum))
                    {
                        FixUpTableColumnSpecs();
                        _tableColumnSpecs[TableColumnIndex].Number = colnum;
                    }
                }

                break;

            case "entry":
                if (key == "morerows")
                {
                    if (int.TryParse(value, out int rowspan))
                    {
                        return("rowspan", $"{rowspan + 1}");
                    }
                }

                if (key == "valign")
                {
                    return(key, value);
                }

                break;

            case "image":
                if (key == "href")
                {
                    if (IsImageElementSvg(element))
                    {
                        return("data", ImageUrlFromHref(value));
                    }

                    return("src", ImageUrlFromHref(value));
                }

                break;

            case "section":
                if (key == "id")
                {
                    CurrentSection = new DitaPageSectionJson {
                        Anchor = value
                    };
                    return(key, value);
                }

                break;

            case "tgroup":
                if (key == "cols")
                {
                    if (int.TryParse(value, out int columns))
                    {
                        _tableColumnSpecs = new DitaTableColumnSpec[columns];
                    }
                }

                break;

            case "xref":
                if (key == "href")
                {
                    string url = UrlFromXref(element, out string title);

                    // If we encounter an empty xref, we want to try to generate link text, based on what it links too
                    if (string.IsNullOrWhiteSpace(element.ToString()))
                    {
                        element.SetInnerText(title);
                    }

                    return(key, url);
                }

                break;
            }

            return("", "");
        }
Esempio n. 25
0
        // Add additional attributes to specific html tags
        private void AddHtmlTagAttributes(Dictionary <string, string> htmlAttributes, DitaElement element)
        {
            switch (element.Type)
            {
            case "image":
                if (IsImageElementSvg(element))
                {
                    // Add the type of embedded svg
                    if (!htmlAttributes.ContainsKey("type"))
                    {
                        htmlAttributes.Add("type", "image/svg+xml");
                    }
                }

                break;

            case "table":
                // Add the generic "table" class to all tables
                if (!htmlAttributes.ContainsKey("class"))
                {
                    htmlAttributes.Add("class", "table");
                }

                break;

            case "entry":
                // If there is a width defined, add it to the entry
                string colname = element.Attributes.ContainsKey("colname") ? element.Attributes["colname"] : null;
                if (!htmlAttributes.ContainsKey("width"))
                {
                    string widthAsPercent = ColumnWidthAsPercent(colname, TableRowColumnIndex);
                    if (!string.IsNullOrEmpty(widthAsPercent))
                    {
                        htmlAttributes.Add("width", widthAsPercent);
                    }
                }

                // If there is a colspan defined, add it to the entry
                if (element.Attributes.ContainsKey("namest") && element.Attributes.ContainsKey("nameend"))
                {
                    // Build the colspan
                    int startColumn = _tableColumnSpecs?.FirstOrDefault(o => o.Name == element.Attributes["namest"])?.Number ?? -1;
                    int endColumn   = _tableColumnSpecs?.FirstOrDefault(o => o.Name == element.Attributes["nameend"])?.Number ?? -1;

                    if (startColumn >= 0 && endColumn >= 0)
                    {
                        if (!htmlAttributes.ContainsKey("colspan"))
                        {
                            htmlAttributes.Add("colspan", $"{endColumn - startColumn + 1}");
                        }
                    }
                }

                break;
            }
        }
Esempio n. 26
0
        // Returns the relative or absolute url from a Dita XREF for use in an html A tag
        private string UrlFromXref(DitaElement xrefElement, out string title)
        {
            // What is the scope
            string scope  = xrefElement.AttributeValueOrDefault("scope", null);
            string format = xrefElement.AttributeValueOrDefault("format", null);
            string href   = xrefElement.AttributeValueOrDefault("href", null);

            title = null;

            if (scope == "external")
            {
                return(href);
            }

            if (!string.IsNullOrEmpty(href))
            {
                string result = null;
                if (href[0] == '#')
                {
                    // Link to the same page
                    if (href.Contains('/'))
                    {
                        string[] anchorSplit = href.Split('/');
                        if (anchorSplit.Length > 1)
                        {
                            result = $"#{anchorSplit[1]}";
                        }
                    }
                    else
                    {
                        result = href.Substring(1);
                    }
                }
                else if (href.ToLowerInvariant().StartsWith("http"))
                {
                    result = href;
                }
                else
                {
                    // Split by hash, if any
                    string[] hashSplit = href.Split('#');

                    // Try to find the topic it is linking to
                    DitaFile referenceFile = Collection?.GetFileByName(hashSplit[0]);
                    if (referenceFile != null)
                    {
                        result = $"%DOCUMENT_ROOT%/{Path.GetFileNameWithoutExtension(referenceFile.NewFileName)}";
                        if (hashSplit.Length > 1)
                        {
                            result += $"#{hashSplit[1]}";
                        }

                        title = referenceFile.Title;
                    }
                    else
                    {
                        Trace.TraceError($"Xref refers to unknown local file {hashSplit[0]} in {FileName}");
                    }
                }

                if (!string.IsNullOrEmpty(result))
                {
                    return(result);
                }
                else
                {
                    return("#");
                }
            }

            Trace.TraceWarning($"Unknown xref scope={scope}, format={format}, href={href} in {FileName}");
            return("#");
        }