Ejemplo n.º 1
0
        /// <inheritdoc />
        public override void Apply(XmlDocument document, string key)
        {
            // Set the context
            CustomContext context = new CustomContext(contextNamespaces);
            context["key"] = key;

            // Evaluate the condition
            XPathExpression xPathLocal = xPath.Clone();
            xPathLocal.SetContext(context);

            object result = document.CreateNavigator().Evaluate(xPathLocal);

            // Try to interpret the result as a node set
            XPathNodeIterator resultNodeIterator = result as XPathNodeIterator;

            if(resultNodeIterator != null)
            {
                // If it is, apply the child components to each node value
                foreach(XPathNavigator resultNode in resultNodeIterator.ToArray())
                    ApplyComponents(document, resultNode.Value);
            }
            else
            {
                // If it isn't, apply the child components to the string value of the result
                ApplyComponents(document, result.ToString());
            }
        }
Ejemplo n.º 2
0
        /// <inheritdoc />
        public override void Apply(XmlDocument document, string key)
        {
            // Set the key in the XPath context
            var context = new CustomContext();
            context["key"] = key;

            // Perform each copy command
            foreach(CopyFromFilesCommand copyCommand in copyCommands)
                copyCommand.Apply(document, context);
        }
Ejemplo n.º 3
0
        //=====================================================================

        /// <summary>
        /// This is used to write the document to its destination file
        /// </summary>
        private void WriteDocuments()
        {
            foreach(var kv in documentList.GetConsumingEnumerable())
            {
                var document = kv.Value;

                // Set the evaluation context
                CustomContext context = new CustomContext();
                context["key"] = kv.Key;

                XPathExpression xpath = pathExpression.Clone();
                xpath.SetContext(context);

                // Evaluate the path
                string path = document.CreateNavigator().Evaluate(xpath).ToString();

                if(basePath != null)
                    path = Path.Combine(basePath, path);

                string targetDirectory = Path.GetDirectoryName(path);

                if(!Directory.Exists(targetDirectory))
                    Directory.CreateDirectory(targetDirectory);

                if(writeXhtmlNamespace)
                {
                    document.DocumentElement.SetAttribute("xmlns", "http://www.w3.org/1999/xhtml");
                    document.LoadXml(document.OuterXml);
                }

                // Save the document
                try
                {
                    // selectExpression determines which nodes get saved. If there is no selectExpression we simply
                    // save the root node as before. If there is a selectExpression, 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(selectExpression == null)
                    {
                        using(XmlWriter writer = XmlWriter.Create(path, settings))
                        {
                            document.Save(writer);
                        }
                    }
                    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.
                        using(StreamWriter output = File.CreateText(path))
                        {
                            using(XmlWriter writer = XmlWriter.Create(output, settings))
                            {
                                XPathExpression selectXPath = selectExpression.Clone();
                                selectXPath.SetContext(context);

                                XPathNodeIterator ni = document.CreateNavigator().Select(selectExpression);

                                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);
                                }
                            }
                        }
                    }

                    // Raise an event to indicate that a file was created
                    this.OnComponentEvent(new FileCreatedEventArgs(path, true));
                }
                catch(IOException e)
                {
                    this.WriteMessage(kv.Key, MessageLevel.Error, "An access error occurred while attempting to " +
                        "save to the file '{0}'. The error message is '{1}'", path, e.GetExceptionMessage());
                }
                catch(XmlException e)
                {
                    this.WriteMessage(kv.Key, MessageLevel.Error, "Invalid XML was written to the output " +
                        "file '{0}'. The error message is '{1}'", path, e.GetExceptionMessage());
                }
            }
        }
Ejemplo n.º 4
0
        //=====================================================================

        /// <inheritdoc />
        public override void Initialize(XPathNavigator configuration)
        {
            MessageLevel level;
            bool isAttribute, ignoreCase;

            // Set up the context
            XPathNodeIterator contextNodes = configuration.Select("context");

            foreach(XPathNavigator contextNode in contextNodes)
                contextNamespaces[contextNode.GetAttribute("prefix", String.Empty)] =
                    contextNode.GetAttribute("name", String.Empty);

            // This is only used by the indices and won't change
            this.Context = new CustomContext(contextNamespaces);

            // Set up the indices
            XPathNodeIterator indexNodes = configuration.Select("index");

            foreach(XPathNavigator indexNode in indexNodes)
            {
                // Create the index
                IndexedCache index = this.CreateIndex(indexNode);
#if DEBUG
                this.WriteMessage(MessageLevel.Diagnostic, "Loading {0} index", index.Name);

                DateTime startLoad = DateTime.Now;
#endif
                // Search the data directories for entries
                XPathNodeIterator dataNodes = indexNode.Select("data");

                foreach(XPathNavigator dataNode in dataNodes)
                    index.AddDocuments(dataNode);

                // Getting the count from a database cache can be expensive so only report it if it will be seen
                if(this.BuildAssembler.VerbosityLevel == MessageLevel.Info)
                    this.WriteMessage(MessageLevel.Info, "Indexed {0} elements", index.Count);
#if DEBUG
                TimeSpan loadTime = (DateTime.Now - startLoad);
                this.WriteMessage(MessageLevel.Diagnostic, "Load time: {0} seconds", loadTime.TotalSeconds);
#endif
                BuildComponentCore.Data.Add(index.Name, index);
            }

            // Get the copy commands
            XPathNodeIterator copyNodes = configuration.Select("copy");

            foreach(XPathNavigator copyNode in copyNodes)
            {
                string sourceName = copyNode.GetAttribute("name", String.Empty);

                if(String.IsNullOrWhiteSpace(sourceName))
                    this.WriteMessage(MessageLevel.Error, "Each copy command must specify an index to copy from");

                string keyXPath = copyNode.GetAttribute("key", String.Empty);

                if(String.IsNullOrWhiteSpace(keyXPath))
                    keyXPath = "string($key)";

                string sourceXPath = copyNode.GetAttribute("source", String.Empty);

                if(String.IsNullOrWhiteSpace(sourceXPath))
                    this.WriteMessage(MessageLevel.Error, "When instantiating a CopyFromIndex component, you " +
                        "must specify a source XPath format using the source attribute");

                string targetXPath = copyNode.GetAttribute("target", String.Empty);

                if(String.IsNullOrWhiteSpace(targetXPath))
                    this.WriteMessage(MessageLevel.Error, "When instantiating a CopyFromIndex component, you " +
                        "must specify a target XPath format using the target attribute");

                isAttribute = ignoreCase = false;

                string boolValue = copyNode.GetAttribute("attribute", String.Empty);

                if(!String.IsNullOrWhiteSpace(boolValue) && !Boolean.TryParse(boolValue, out isAttribute))
                    this.WriteMessage(MessageLevel.Error, "The 'attribute' attribute value is not a valid Boolean");

                boolValue = copyNode.GetAttribute("ignoreCase", String.Empty);

                if(!String.IsNullOrWhiteSpace(boolValue) && !Boolean.TryParse(boolValue, out ignoreCase))
                    this.WriteMessage(MessageLevel.Error, "The ignoreCase attribute value is not a valid Boolean");

                IndexedCache index = (IndexedCache)BuildComponentCore.Data[sourceName];

                CopyFromIndexCommand copyCommand = new CopyFromIndexCommand(this, index, keyXPath, sourceXPath,
                    targetXPath, isAttribute, ignoreCase);

                string messageLevel = copyNode.GetAttribute("missing-entry", String.Empty);

                if(!String.IsNullOrWhiteSpace(messageLevel))
                    if(Enum.TryParse<MessageLevel>(messageLevel, true, out level))
                        copyCommand.MissingEntry = level;
                    else
                        this.WriteMessage(MessageLevel.Error, "'{0}' is not a message level.", messageLevel);

                messageLevel = copyNode.GetAttribute("missing-source", String.Empty);

                if(!String.IsNullOrWhiteSpace(messageLevel))
                    if(Enum.TryParse<MessageLevel>(messageLevel, true, out level))
                        copyCommand.MissingSource = level;
                    else
                        this.WriteMessage(MessageLevel.Error, "'{0}' is not a message level.", messageLevel);

                messageLevel = copyNode.GetAttribute("missing-target", String.Empty);

                if(!String.IsNullOrWhiteSpace(messageLevel))
                    if(Enum.TryParse<MessageLevel>(messageLevel, true, out level))
                        copyCommand.MissingTarget = level;
                    else
                        this.WriteMessage(MessageLevel.Error, "'{0}' is not a message level.", messageLevel);

                copyCommands.Add(copyCommand);
            }

            XPathNodeIterator componentNodes = configuration.Select("components/component");

            foreach(XPathNavigator componentNode in componentNodes)
            {
                // Get the ID of the copy component
                string id = componentNode.GetAttribute("id", String.Empty);

                if(String.IsNullOrWhiteSpace(id))
                    this.WriteMessage(MessageLevel.Error, "Each copy component element must have an id attribute");

                var copyComponentFactory = copyComponentFactories.FirstOrDefault(g => g.Metadata.Id == id);

                if(copyComponentFactory == null)
                    this.WriteMessage(MessageLevel.Error, "A copy component with the ID '{0}' could not be found", id);

                try
                {
                    var copyComponent = copyComponentFactory.Value.Create(this);

                    copyComponent.Initialize(componentNode.Clone(), BuildComponentCore.Data);
                    components.Add(copyComponent);
                }
                catch(Exception ex)
                {
                    this.WriteMessage(MessageLevel.Error, "An error occurred while attempting to instantiate " +
                        "the '{0}' copy component. The error message is: {1}{2}", id, ex.Message,
                        ex.InnerException != null ? "\r\n" + ex.InnerException.Message : String.Empty);
                }
            }

            if(components.Count != 0)
                this.WriteMessage(MessageLevel.Info, "Loaded {0} copy components", components.Count);
        }
Ejemplo n.º 5
0
        /// <inheritdoc />
        public override void Apply(XmlDocument document, string key)
        {
            // Set the key in the XPath context
            var context = new CustomContext(contextNamespaces);
            context["key"] = key;

            // Perform each copy command
            foreach(CopyFromIndexCommand copyCommand in copyCommands)
                copyCommand.Apply(document, context);

            // Apply changes for each sub-component, if any
            foreach(CopyComponentCore component in components)
                component.Apply(document, key);
        }
Ejemplo n.º 6
0
        /// <inheritdoc />
        public override void Apply(XmlDocument document, string key)
        {
            // Set up the test
            CustomContext context = new CustomContext(contextNamespaces);
            context["key"] = key;

            XPathExpression test = condition.Clone();
            test.SetContext(context);

            // Evaluate the condition
            bool result = (bool)document.CreateNavigator().Evaluate(test);

            // On the basis of the condition, execute either the true or the false branch
            if(result)
            {
                foreach(BuildComponentCore component in trueBranch)
                    component.Apply(document, key);
            }
            else
            {
                foreach(BuildComponentCore component in falseBranch)
                    component.Apply(document, key);
            }
        }
Ejemplo n.º 7
0
        //=====================================================================

        /// <inheritdoc />
        public override void Initialize(XPathNavigator configuration)
        {
            // Get the context.  This will contain namespaces that prefix the elements to find.
            var context = new CustomContext();

            XPathNodeIterator contextNodes = configuration.Select("context");

            foreach(XPathNavigator cn in contextNodes)
                context.AddNamespace(cn.GetAttribute("prefix", String.Empty),
                    cn.GetAttribute("name", String.Empty));

            // Item keys are compared case-insensitively
            content = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

            elements = new List<SharedContentElement>();

            // Get the elements to be resolved
            XPathNodeIterator resolve_nodes = configuration.Select("replace");

            foreach(XPathNavigator resolve_node in resolve_nodes)
            {
                // Get the XPath expression used to find the elements to replace
                string path = resolve_node.GetAttribute("elements", String.Empty);

                // If not defined, assume include and includeAttribute are to be replaced
                if(String.IsNullOrEmpty(path))
                    path = "//include | //includeAttribute";

                try
                {
                    XPathExpression path_expresion = XPathExpression.Compile(path, context);
                }
                catch(XPathException)
                {
                    this.WriteMessage(MessageLevel.Error, "The elements expression '{0}' is not a valid XPath",
                        path);
                }

                // Get the XPath expression used to get the item name to insert
                string item = resolve_node.GetAttribute("item", String.Empty);

                if(String.IsNullOrEmpty(item))
                    item = "string(@item)";
                try
                {
                    XPathExpression item_expression = XPathExpression.Compile(item, context);
                }
                catch(XPathException)
                {
                    this.WriteMessage(MessageLevel.Error, "The item expression '{0}' is not a valid XPath", item);
                }

                // Get the XPath expression used to find parameter elements
                string parameters = resolve_node.GetAttribute("parameters", String.Empty);

                if(String.IsNullOrEmpty(parameters))
                    parameters = "parameter";

                // Get the XPath expression used to get the attribute name for attribute items
                string attribute = resolve_node.GetAttribute("attribute", String.Empty);

                if(String.IsNullOrEmpty(attribute))
                    attribute = "string(@name)";

                elements.Add(new SharedContentElement(path, item, parameters, attribute, context));
            }

            // If not defined, assume include and includeAttribute are to be replaced using the default names
            if(elements.Count == 0)
                elements.Add(new SharedContentElement("//include | //includeAttribute", "string(@item)",
                    "parameter", "string(@name)", context));

            // Load the content item files
            XPathNodeIterator content_nodes = configuration.Select("content");

            foreach(XPathNavigator content_node in content_nodes)
            {
                string sharedContentFiles = content_node.GetAttribute("file", String.Empty);

                if(String.IsNullOrEmpty(sharedContentFiles))
                    this.WriteMessage(MessageLevel.Error, "The content/@file attribute must specify a path.");

                this.ParseDocuments(sharedContentFiles);
            }

            this.WriteMessage(MessageLevel.Info, "Loaded {0} shared content items.", content.Count);
        }
        /// <summary>
        /// This is used to get the string result from evaluating an XPath expression against the given document
        /// and a context created from a set of key/value pairs.
        /// </summary>
        /// <param name="document">The document to use</param>
        /// <param name="expression">The XPath expression to evaluate</param>
        /// <param name="keyValuePairs">A set of key/value pairs to use when creating the context</param>
        /// <returns>The evaluated expression result</returns>
        /// <example>
        /// <code language="cs">
        /// string result = document.EvalXPathExpr("concat($key, '.htm')", "key", "filename");
        /// </code>
        /// </example>
        /// <exception cref="ArgumentException">This is thrown if the <paramref name="keyValuePairs"/>
        /// parameter contains an odd number of parameters.</exception>
        public static string EvalXPathExpr(this IXPathNavigable document, XPathExpression expression,
          params string[] keyValuePairs)
        {
            if(keyValuePairs.Length % 2 != 0)
                throw new ArgumentException("There must be a value for every key name specified", "keyValuePairs");

            CustomContext cc = new CustomContext();

            for(int i = 0; i < keyValuePairs.Length; i += 2)
                cc[keyValuePairs[i]] = keyValuePairs[i + 1];

            return document.EvalXPathExpr(expression, cc);
        }
        /// <summary>
        /// This is used to get the string result from evaluating an XPath expression against the given
        /// document and context.
        /// </summary>
        /// <param name="document">The document to use</param>
        /// <param name="expression">The XPath expression to evaluate</param>
        /// <param name="context">The context to use</param>
        /// <returns>The evaluated expression result</returns>
        /// <overloads>There are two overloads for this method</overloads>
        public static string EvalXPathExpr(this IXPathNavigable document, XPathExpression expression,
          CustomContext context)
        {
            XPathExpression t = expression.Clone();
            t.SetContext(context);

            return document.CreateNavigator().Evaluate(t).ToString();
        }
Ejemplo n.º 10
0
        //=====================================================================

        /// <inheritdoc />
        /// <remarks>See the <see cref="CodeBlockComponent"/> class topic for an example of the configuration and
        /// usage.</remarks>
        /// <exception cref="ConfigurationErrorsException">This is thrown if an error is detected in the
        /// configuration.</exception>
        public override void Initialize(XPathNavigator configuration)
        {
            XPathNavigator nav;
            string value = null, syntaxFile, styleFile;
            bool allowMissingSource = false, useDefaultTitle = false;
            int defaultTabSize = 8;

            outputPaths = new List<string>();
            topicCodeBlocks = new Dictionary<string, Dictionary<string, XmlNode>>();

            Assembly asm = Assembly.GetExecutingAssembly();
            FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(asm.Location);

            base.WriteMessage(MessageLevel.Info, "[{0}, version {1}]\r\n    Code Block Component.  " +
                "{2}.\r\n    Portions copyright (c) 2003-2015, Jonathan de Halleux, All rights reserved.\r\n" +
                "    https://GitHub.com/EWSoftware/SHFB", fvi.ProductName, fvi.ProductVersion, fvi.LegalCopyright);

            // The <basePath> element is optional.  If not set, it will assume the current folder as the base
            // path for source references with relative paths.
            nav = configuration.SelectSingleNode("basePath");

            if(nav != null)
                basePath = nav.GetAttribute("value", String.Empty);

            if(String.IsNullOrEmpty(basePath))
                basePath = Directory.GetCurrentDirectory();

            if(basePath[basePath.Length - 1] != '\\')
                basePath += @"\";

            // Get the output paths
            foreach(XPathNavigator path in configuration.Select("outputPaths/path"))
            {
                value = path.GetAttribute("value", String.Empty);

                if(value[value.Length - 1] != '\\')
                    value += @"\";

                if(!Directory.Exists(value))
                    Directory.CreateDirectory(value);

                outputPaths.Add(value);

                // The Open XML format doesn't support all features and requires a custom transformation
                if(value.IndexOf("OpenXML", StringComparison.OrdinalIgnoreCase) != -1)
                    isOpenXml = true;

                // The Markdown format doesn't support any features
                if(value.IndexOf("Markdown", StringComparison.OrdinalIgnoreCase) != -1)
                    isMarkdown = true;
            }

            if(outputPaths.Count == 0)
                throw new ConfigurationErrorsException("You must specify at least one <path> element in the " +
                    "<outputPaths> element.  You may need to delete and re-add the component to the project " +
                    "to obtain updated configuration settings.");

            // The <allowMissingSource> element is optional.  If not set, missing source files generate an error.
            nav = configuration.SelectSingleNode("allowMissingSource");

            if(nav != null)
            {
                value = nav.GetAttribute("value", String.Empty);

                if(!String.IsNullOrEmpty(value) && !Boolean.TryParse(value, out allowMissingSource))
                    throw new ConfigurationErrorsException("You must specify a Boolean value for the " +
                        "<allowMissingSource> 'value' attribute.");
            }

            if(!allowMissingSource)
                messageLevel = MessageLevel.Error;
            else
                messageLevel = MessageLevel.Warn;

            // The <removeRegionMarkers> element is optional.  If not set, region markers in imported code are
            // left alone.
            nav = configuration.SelectSingleNode("removeRegionMarkers");

            if(nav != null)
            {
                value = nav.GetAttribute("value", String.Empty);

                if(!String.IsNullOrEmpty(value) && !Boolean.TryParse(value, out removeRegionMarkers))
                    throw new ConfigurationErrorsException("You must specify a Boolean value for the " +
                        "<removeRegionMarkers> 'value' attribute.");
            }

            // The <colorizer> element is required and defines the defaults for the code colorizer
            nav = configuration.SelectSingleNode("colorizer");

            if(nav == null)
                throw new ConfigurationErrorsException("You must specify a <colorizer> element to define " +
                    "the code colorizer options.");

            // The file and URL values are all required
            syntaxFile = nav.GetAttribute("syntaxFile", String.Empty);
            styleFile = nav.GetAttribute("styleFile", String.Empty);
            stylesheet = nav.GetAttribute("stylesheet", String.Empty);
            scriptFile = nav.GetAttribute("scriptFile", String.Empty);

            if(String.IsNullOrEmpty(syntaxFile))
                throw new ConfigurationErrorsException("You must specify a 'syntaxFile' attribute on the " +
                    "<colorizer> element.");

            if(String.IsNullOrEmpty(styleFile))
                throw new ConfigurationErrorsException("You must specify a 'styleFile' attribute on the " +
                    "<colorizer> element.");

            if(String.IsNullOrEmpty(stylesheet) && !isOpenXml && !isMarkdown)
                throw new ConfigurationErrorsException("You must specify a 'stylesheet' attribute on the " +
                    "<colorizer> element");

            if(String.IsNullOrEmpty(scriptFile) && !isOpenXml && !isMarkdown)
                throw new ConfigurationErrorsException("You must specify a 'scriptFile' attribute on the " +
                    "<colorizer> element");

            // The syntax and style files must also exist.  The "copy" image URL is just a location and it
            // doesn't have to exist yet.
            syntaxFile = Path.GetFullPath(syntaxFile);
            styleFile = Path.GetFullPath(styleFile);

            if(!File.Exists(syntaxFile))
                throw new ConfigurationErrorsException("The specified syntax file could not be found: " +
                    syntaxFile);

            if(!File.Exists(styleFile))
                throw new ConfigurationErrorsException("The specified style file could not be found: " +
                    styleFile);

            if(!isOpenXml && !isMarkdown)
            {
                stylesheet = Path.GetFullPath(stylesheet);
                scriptFile = Path.GetFullPath(scriptFile);

                if(!File.Exists(stylesheet))
                    throw new ConfigurationErrorsException("Could not find style sheet file: " + stylesheet);

                if(!File.Exists(scriptFile))
                    throw new ConfigurationErrorsException("Could not find script file: " + scriptFile);
            }

            // Optional attributes
            defaultLanguage = nav.GetAttribute("language", String.Empty);

            if(String.IsNullOrEmpty(defaultLanguage))
                defaultLanguage = "none";

            value = nav.GetAttribute("numberLines", String.Empty);

            if(!String.IsNullOrEmpty(value) && !Boolean.TryParse(value, out numberLines))
                throw new ConfigurationErrorsException("You must specify a Boolean value for the " +
                    "'numberLines' attribute.");

            value = nav.GetAttribute("outlining", String.Empty);

            if(!String.IsNullOrEmpty(value) && !Boolean.TryParse(value, out outliningEnabled))
                throw new ConfigurationErrorsException("You must specify a Boolean value for the " +
                    "'outlining' attribute.");

            value = nav.GetAttribute("keepSeeTags", String.Empty);

            if(!String.IsNullOrEmpty(value) && !Boolean.TryParse(value, out keepSeeTags))
                throw new ConfigurationErrorsException("You must specify a Boolean value for the " +
                    "'keepSeeTags' attribute.");

            value = nav.GetAttribute("tabSize", String.Empty);

            if(!String.IsNullOrEmpty(value) && !Int32.TryParse(value, out defaultTabSize))
                throw new ConfigurationErrorsException("You must specify an integer value for the 'tabSize' " +
                    "attribute.");

            value = nav.GetAttribute("defaultTitle", String.Empty);

            if(!String.IsNullOrEmpty(value) && !Boolean.TryParse(value, out useDefaultTitle))
                throw new ConfigurationErrorsException("You must specify a Boolean value for the " +
                    "'defaultTitle' attribute.");

            if(!isMarkdown)
            {
                value = nav.GetAttribute("disabled", String.Empty);

                if(!String.IsNullOrEmpty(value) && !Boolean.TryParse(value, out isDisabled))
                    throw new ConfigurationErrorsException("You must specify a Boolean value for the " +
                        "'disabled' attribute.");
            }
            else
                isDisabled = true;      // Markdown doesn't support anything so it is always disabled

            if(isOpenXml)
            {
                numberLines = outliningEnabled = false;

                // If the default transform is specified, switch to the Open XML version.  This can happen if
                // the user adds the code block component to their project to override the default settings.
                string defaultTransform = Path.Combine(Path.GetDirectoryName(asm.Location),
                    @"PresentationStyles\Colorizer\highlight.xsl");

                if(styleFile.Equals(defaultTransform, StringComparison.OrdinalIgnoreCase))
                {
                    styleFile = Path.Combine(Path.GetDirectoryName(defaultTransform), "highlight_openxml.xsl");

                    if(!File.Exists(styleFile))
                        throw new ConfigurationErrorsException("The specified style file could not be found: " +
                            styleFile);
                }
            }

            // Initialize the code colorizer
            colorizer = new CodeColorizer(syntaxFile, styleFile);
            colorizer.UseDefaultTitle = useDefaultTitle;
            colorizer.TabSize = defaultTabSize;

            // Create the XPath queries
            var context = new CustomContext();

            context.AddNamespace("ddue", "http://ddue.schemas.microsoft.com/authoring/2003/5");

            referenceRoot = XPathExpression.Compile("document/comments");
            referenceCode = XPathExpression.Compile("//code");
            nestedRefCode = XPathExpression.Compile("code");
            conceptualRoot = XPathExpression.Compile("document/topic");
            conceptualCode = XPathExpression.Compile("//ddue:code");
            conceptualCode.SetContext(context);
            nestedConceptCode = XPathExpression.Compile("ddue:code");
            nestedConceptCode.SetContext(context);

            // Hook up the event handler to complete the process after the topic is transformed to HTML
            base.BuildAssembler.ComponentEvent += TransformComponent_TopicTransformed;
        }
Ejemplo n.º 11
0
        //=====================================================================

        /// <inheritdoc />
        public override void Initialize(XPathNavigator configuration)
        {
            XPathNodeIterator contentNodes = configuration.Select("examples");

            foreach(XPathNavigator contentNode in contentNodes)
            {
                string file = contentNode.GetAttribute("file", String.Empty);
                file = Environment.ExpandEnvironmentVariables(file);

                if(String.IsNullOrEmpty(file))
                    WriteMessage(MessageLevel.Error, "Each examples element must contain a file attribute.");

                LoadContent(file);
            }

            WriteMessage(MessageLevel.Info, "Loaded {0} code snippets", snippets.Count);

            XPathNodeIterator colorsNodes = configuration.Select("colors");

            foreach(XPathNavigator colorsNode in colorsNodes)
            {
                string language = colorsNode.GetAttribute("language", String.Empty);
                List<ColorizationRule> rules = new List<ColorizationRule>();

                XPathNodeIterator colorNodes = colorsNode.Select("color");

                foreach(XPathNavigator colorNode in colorNodes)
                {
                    string pattern = colorNode.GetAttribute("pattern", String.Empty);
                    string region = colorNode.GetAttribute("region", String.Empty);
                    string name = colorNode.GetAttribute("class", String.Empty);

                    if(String.IsNullOrEmpty(region))
                        rules.Add(new ColorizationRule(pattern, name));
                    else
                        rules.Add(new ColorizationRule(pattern, region, name));
                }

                colorization[language] = rules;
                WriteMessage(MessageLevel.Info, "Loaded {0} colorization rules for the language '{1}'.", rules.Count, language);
            }

            CustomContext context = new CustomContext();
            context.AddNamespace("ddue", "http://ddue.schemas.microsoft.com/authoring/2003/5");

            selector = XPathExpression.Compile("//ddue:codeReference");
            selector.SetContext(context);
        }
Ejemplo n.º 12
0
        //=====================================================================

        /// <inheritdoc />
        public override void Initialize(XPathNavigator configuration)
        {
            XPathNavigator syntaxNode = configuration.SelectSingleNode("syntax");
            string syntaxInputXPath = syntaxNode.GetAttribute("input", String.Empty);

            if(String.IsNullOrEmpty(syntaxInputXPath))
                throw new ConfigurationErrorsException("You must specify an XPath for input in the syntax element");

            syntaxInput = XPathExpression.Compile(syntaxInputXPath);

            string syntaxOutputXPath = syntaxNode.GetAttribute("output", String.Empty);

            if(String.IsNullOrEmpty(syntaxOutputXPath))
                throw new ConfigurationErrorsException("You must specify an XPath for output in the syntax element");

            syntaxOutput = XPathExpression.Compile(syntaxOutputXPath);

            string attrValue = syntaxNode.GetAttribute("renderReferenceLinks", String.Empty);

            if(String.IsNullOrWhiteSpace(attrValue) || !Boolean.TryParse(attrValue, out renderReferenceLinks))
                renderReferenceLinks = false;

            XPathNodeIterator generatorNodes = configuration.Select("generators/generator");

            // Configuration changes are stored separately since the actual generators may be added to the
            // configuration file at build time.  Substitution of the edited configuration is easier to do here.
            var generatorConfigs = configuration.SelectSingleNode("configurations");

            // If we have configuration nodes, note the order of the syntax generators.  These will be used to
            // order the snippets.
            if(generatorConfigs != null)
            {
                int order = 1;

                foreach(XPathNavigator id in generatorConfigs.Select("generator/@id"))
                    languageOrder.Add(id.Value, order++);
            }

            foreach(XPathNavigator generatorNode in generatorNodes)
            {
                // Get the ID of the syntax generator
                string id = generatorNode.GetAttribute("id", String.Empty);

                if(String.IsNullOrWhiteSpace(id))
                    this.WriteMessage(MessageLevel.Error, "Each generator element must have an id attribute");

                var generatorFactory = generatorFactories.FirstOrDefault(g => g.Metadata.Id == id);

                if(generatorFactory == null)
                    this.WriteMessage(MessageLevel.Error, "A syntax generator with the ID '{0}' could not be found", id);

                // Track the languages for grouping
                generatorLanguages.Add(generatorFactory.Metadata.Id);
                languageSet.Add(generatorFactory.Metadata);

                foreach(string alternateId in (generatorFactory.Metadata.AlternateIds ?? String.Empty).Split(
                  new[] { ',', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries))
                    generatorLanguages.Add(alternateId);

                try
                {
                    var generator = generatorFactory.Value.Create();
                    var configNode = generatorNode.Clone();

                    if(generatorConfigs != null)
                    {
                        var alternateConfig = generatorConfigs.SelectSingleNode("generator[@id='" + id + "']");

                        if(alternateConfig != null && alternateConfig.HasChildren)
                        {
                            // Since there may be custom attributes on the generator node, we'll make a copy and
                            // substitute the child elements that make up the configuration.
                            var alternate = XElement.Parse(alternateConfig.OuterXml);
                            var genNode = XElement.Parse(configNode.OuterXml);

                            genNode.RemoveNodes();
                            genNode.Add(alternate.Elements());

                            configNode = genNode.CreateNavigator();
                        }
                    }

                    generator.Initialize(configNode);
                    generators.Add(generator);
                }
                catch(Exception ex)
                {
                    this.WriteMessage(MessageLevel.Error, "An error occurred while attempting to instantiate " +
                        "the '{0}' syntax generator. The error message is: {1}{2}", id, ex.Message,
                        ex.InnerException != null ? "\r\n" + ex.InnerException.Message : String.Empty);
                }
            }

            this.WriteMessage(MessageLevel.Info, "Loaded {0} syntax generators.", generators.Count);

            // If this is not found or set, we'll assume the presentation style does not support grouping
            var containerElement = configuration.SelectSingleNode("containerElement");

            if(containerElement != null)
            {
                // If grouping is disabled, skip the remainder of the set up.  This will happen if the user adds
                // a custom configuration to a project for a presentation style that doesn't support it.
                bool groupingEnabled;

                containerElementName = containerElement.GetAttribute("name", String.Empty);
                attrValue = containerElement.GetAttribute("groupingEnabled", String.Empty);

                if(String.IsNullOrWhiteSpace(attrValue) || !Boolean.TryParse(attrValue, out groupingEnabled))
                    groupingEnabled = false;

                if(!groupingEnabled || String.IsNullOrWhiteSpace(containerElementName))
                    return;

                // Get the "no example tab" options
                attrValue = containerElement.GetAttribute("addNoExampleTabs", String.Empty);

                if(String.IsNullOrWhiteSpace(attrValue) || !Boolean.TryParse(attrValue, out addNoExampleTabs))
                    addNoExampleTabs = true;

                attrValue = containerElement.GetAttribute("includeOnSingleSnippets", String.Empty);

                if(String.IsNullOrWhiteSpace(attrValue) || !Boolean.TryParse(attrValue, out includeOnSingleSnippets))
                    includeOnSingleSnippets = false;

                // Create the XPath queries used for code snippet grouping and sorting
                var context = new CustomContext();

                context.AddNamespace("ddue", "http://ddue.schemas.microsoft.com/authoring/2003/5");

                referenceRoot = XPathExpression.Compile("document/comments|document/syntax");
                referenceCode = XPathExpression.Compile("//code|//div[@codeLanguage]");

                conceptualRoot = XPathExpression.Compile("document/topic");
                conceptualCode = XPathExpression.Compile("//ddue:code|//ddue:snippet");
                conceptualCode.SetContext(context);

                // Hook up the event handler to group and sort code snippets just prior to XSL transformation
                this.BuildAssembler.ComponentEvent += TransformComponent_TopicTransforming;
            }
        }