Пример #1
0
        private void ProcessIncludes(XmlNode contextElement, SageContext context)
        {
            var state = new IncludeProcessingState(context);
            if (!string.IsNullOrWhiteSpace(this.BaseURI))
            {
                var cacheEntry = state.VisitedNodes[this.BaseURI] = new Dictionary<string, XmlNode>();
                cacheEntry["/"] = this.DocumentElement;
            }

            this.ProcessIncludes(contextElement, state);
        }
Пример #2
0
        private void ProcessIncludes(XmlNode contentElement, IncludeProcessingState state)
        {
            var nm = XmlNamespaces.Manager.MergeWith(new XmlNamespaceManager(contentElement.OwnerDocument.NameTable));
            var includeElements = contentElement.SelectNodes(".//sage:include[not(ancestor::sage:literal)]", XmlNamespaces.Manager);

            bool debugMode = false;
            if (state.Context != null)
                debugMode = state.Context.ProjectConfiguration.IsDebugEnabled;

            XmlDocument elementDocument = contentElement.OwnerDocument;
            foreach (XmlElement includingElement in includeElements)
            {
                XmlNode fallbackNode = includingElement.SelectSingleNode("sage:fallback", XmlNamespaces.Manager);
                XmlNode includedNode = this.ProcessInclude(nm, includingElement, state);
                XmlNode elementParent = includingElement.ParentNode;

                if (state.IsError)
                {
                    if (state.IncludeStack.Count == 0)
                    {
                        log.ErrorFormat(state.ErrorMessage);
                        if (debugMode)
                        {
                            var debugElement = this.CreateErrorElement(state.ErrorMessage);
                            elementParent.ReplaceChild(elementDocument.ImportNode(debugElement, true), includingElement);
                        }
                    }
                    else
                        elementParent.RemoveChild(includingElement);
                }
                else
                {
                    if (includedNode == null && fallbackNode != null)
                    {
                        var fragment = elementDocument.CreateDocumentFragment();
                        foreach (XmlNode childNode in fallbackNode.ChildNodes)
                            fragment.AppendChild(childNode.CloneNode(true));

                        this.ProcessIncludes(fragment, state);
                        includedNode = fragment;
                    }

                    if (includedNode != null)
                    {
                        elementParent.ReplaceChild(elementDocument.ImportNode(includedNode, true), includingElement);
                    }
                    else
                    {
                        var includeId = this.GetIncludeId(includingElement);
                        var errorMessage = string.Format("NOT FOUND: {0}", includeId);
                        log.ErrorFormat(errorMessage);

                        if (debugMode)
                        {
                            var debugElement = this.CreateErrorElement(errorMessage);
                            elementParent.ReplaceChild(elementDocument.ImportNode(debugElement, true), includingElement);
                        }
                        else
                            elementParent.RemoveChild(includingElement);
                    }
                }
            }
        }
Пример #3
0
        private XmlNode ProcessInclude(XmlNamespaceManager nm, XmlElement element, IncludeProcessingState state)
        {
            XmlNode includedNode = null;

            string href = element.GetAttribute("href");
            string xpath = Kelp.Util.GetParameterValue(element.GetAttribute("xpath"), "/");

            if (string.IsNullOrWhiteSpace(href) && string.IsNullOrWhiteSpace(xpath))
            {
                state.ErrorMessage = Messages.IncludeElementMissingRequiredAttributes;
                return null;
            }

            var includeId = this.GetIncludeId(element);
            if (state.IncludeStack.Count >= MaxIncludeDepth)
            {
                state.ErrorMessage = string.Format(Messages.MaxIncludeDepthExceeded, includeId, MaxIncludeDepth);
                return null;
            }

            string parse = Kelp.Util.GetParameterValue(element.GetAttribute("parse"), "xml", "^text|xml$");
            string encoding = Kelp.Util.GetParameterValue(element.GetAttribute("encoding"), "ascii", "^utf-8|ascii$");

            var directory = string.Empty;
            var includePath = href;

            if (!string.IsNullOrWhiteSpace(this.BaseURI))
            {
                if (string.IsNullOrWhiteSpace(href))
                    includePath = this.BaseURI;

                directory = Path.GetDirectoryName(this.BaseURI);
            }

            if (UrlResolver.GetScheme(includePath) == "file")
            {
                if (includePath.StartsWith("~/"))
                    includePath = state.Context.Path.Resolve(includePath);

                if (!Path.IsPathRooted(includePath) && !string.IsNullOrWhiteSpace(directory))
                    includePath = Path.Combine(directory, includePath);
            }

            IDictionary<string, XmlNode> cacheEntry;
            if (state.VisitedNodes.ContainsKey(includePath))
            {
                cacheEntry = state.VisitedNodes[includePath];
                if (cacheEntry.ContainsKey(xpath))
                {
                    if (state.IncludeStack.Contains(includeId))
                    {
                        state.ErrorMessage = string.Format(Messages.IncludeRecursionError, includeId);
                        return null;
                    }
                }
            }
            else
            {
                cacheEntry = state.VisitedNodes[includePath] = new Dictionary<string, XmlNode>();
            }

            if (cacheEntry.ContainsKey(xpath))
            {
                includedNode = cacheEntry[xpath];
            }
            else
            {
                try
                {
                    if (string.IsNullOrWhiteSpace(href))
                    {
                        includedNode = this.ResolveIntraDocumentInclude(nm, parse, element, xpath);
                        if (includedNode.Contains(element))
                        {
                            // intra-document circular-reference inclusion
                            state.ErrorMessage = string.Format(Messages.IncludeRecursionErrorInternal, includeId);
                            return null;
                        }
                    }
                    else
                    {
                        includedNode = this.ResolveExtraDocumentInclude(nm, parse, includePath, xpath, encoding, state.Context);
                    }

                    if (includedNode != null)
                    {
                        var xmlElement = includedNode as XmlElement;
                        if (xmlElement != null)
                        {
                            state.IncludeStack.Add(includeId);
                            this.ProcessIncludes(xmlElement, state);
                            state.IncludeStack.RemoveAt(state.IncludeStack.Count - 1);
                        }
                    }
                }
                catch (Exception ex)
                {
                    string target = string.IsNullOrWhiteSpace(href) ? xpath : href;
                    state.ErrorMessage = string.Format("Error fetching '{0}': {1}", target, ex.Message);
                }
            }

            return includedNode;
        }