/// <summary> /// Loads an XmlDocument from the filecontainer, replacing GET parameters and verifying permissions /// </summary> /// <param name="xml"></param> /// <param name="xmlParseMode">The kind of text that's being parsed</param> /// <param name="fullpath"></param> /// <returns></returns> public XmlDocument LoadXmlDocument(string xml, XmlParseMode xmlParseMode, string fullpath) { XmlDocument xmlDocument = new XmlDocument(); if (XmlParseMode.Html == xmlParseMode) { // see http://htmlagilitypack.codeplex.com // see http://htmlagilitypack.codeplex.com/SourceControl/changeset/view/67079#52182 xml = "<!DOCTYPE html><html>" + xml.Split(new char[] { '>' }, 2)[1]; HtmlDocument htmlDocument = new HtmlDocument(); // Create a stream that's used for reading and writing Stream stream = new MemoryStream(xml.Length + (xml.Length / 5)); // Create the XML writer XmlWriterSettings settings = new XmlWriterSettings(); //settings.ConformanceLevel = ConformanceLevel.Fragment; settings.OmitXmlDeclaration = true; XmlWriter xmlWriter = XmlWriter.Create(stream, settings); try { htmlDocument.LoadHtml(xml); // Write the html to XML htmlDocument.OptionOutputAsXml = true; htmlDocument.Save(xmlWriter); } catch (Exception e) { log.Error("An error occured trying to parse html:\n" + xml, e); throw new WebResultsOverrideException(WebResults.From(Status._500_Internal_Server_Error, "An error occured trying to parse HTML, see the logs for more information")); } stream.Seek(0, SeekOrigin.Begin); // Read xml from the stream XmlReader xmlReader = XmlReader.Create(stream); xmlDocument.Load(xmlReader); // Get rid of junk nodes while ("html" != xmlDocument.FirstChild.LocalName) xmlDocument.RemoveChild(xmlDocument.FirstChild); // Convert the namespace and clean up < > that are converted incorrectly // TODO: There really needs to be a better way to do this XmlAttribute namespaceAttribute = xmlDocument.CreateAttribute("xmlns"); namespaceAttribute.Value = TemplateHandlerLocator.TemplatingConstants.HtmlNamespace; xmlDocument.DocumentElement.Attributes.Append(namespaceAttribute); xml = xmlDocument.OuterXml; foreach (KeyValuePair<string, string> toReplace in TemplateHandlerLocator.TemplatingConstants.HTMLReplacementChars) xml = xml.Replace(toReplace.Key, toReplace.Value); } try { xmlDocument.LoadXml(xml); } catch (XmlException xmlException) { // When the Xml parse mode is to try HTML, then try HTML but if an error occurs swallow it and throw the original if (XmlParseMode.XmlThenHtml == xmlParseMode) try { return LoadXmlDocument(xml, XmlParseMode.Html, fullpath); } catch { } // Everyone else can see a nice descriptive error StringBuilder errorBuilder = new StringBuilder(string.Format("An error occured while loading {0}\n", fullpath)); errorBuilder.AppendFormat("{0}\n\n\nFrom:\n", xmlException.Message); string[] xmlLines = xml.Split('\n', '\r'); for (int ctr = 0; ctr < xmlLines.Length; ctr++) { int lineNumber = ctr + 1; if (ctr < 9) errorBuilder.Append(" "); else if (ctr < 99) errorBuilder.Append(" "); else if (ctr < 999) errorBuilder.Append(" "); else if (ctr < 9999) errorBuilder.Append(" "); errorBuilder.AppendFormat("{0}: {1}\n", lineNumber, xmlLines[ctr]); if (lineNumber == xmlException.LineNumber) errorBuilder.AppendFormat(" -: {0}^\n", "".PadLeft(xmlException.LinePosition)); } throw new WebResultsOverrideException(WebResults.From(Status._500_Internal_Server_Error, errorBuilder.ToString())); } return xmlDocument; }
/// <summary> /// Loads an XmlDocument from the filecontainer, replacing GET parameters and verifying permissions /// </summary> /// <param name="arguments"></param> /// <param name="fileContainer"></param> /// <param name="xmlParseMode">The kind of text that's being parsed</param> /// <returns></returns> public XmlDocument LoadXmlDocumentAndReplaceGetParameters( IDictionary<string, object> arguments, IFileContainer fileContainer, XmlParseMode xmlParseMode) { XmlDocument xmlDocument = LoadXmlDocument(fileContainer, xmlParseMode); // Do the replacements HandleArguments(arguments, xmlDocument); if (WebConnection.CookiesFromBrowser.ContainsKey(TemplateHandlerLocator.TemplatingConstants.XMLDebugModeCookie)) { StringBuilder commentBuilder = new StringBuilder("\n\nDEBUG INFO\n"); SortedDictionary<string, object> sortedArguments = new SortedDictionary<string, object>(arguments); foreach (KeyValuePair<string, object> getArgument in sortedArguments) if (null != getArgument.Value) commentBuilder.AppendFormat("\t{0}: {1}\n", getArgument.Key, getArgument.Value.ToString()); else commentBuilder.AppendFormat("\t{0}: null\n", getArgument.Key); commentBuilder.Append("\n\n"); XmlComment comment = xmlDocument.CreateComment(commentBuilder.ToString()); XmlNode firstChild = xmlDocument.FirstChild; if ((firstChild.LocalName == "componentdef") && (firstChild.NamespaceURI == TemplateHandlerLocator.TemplatingConstants.TemplateNamespace)) firstChild.InsertBefore(comment, firstChild.FirstChild); else if ("html" != xmlDocument.FirstChild.LocalName) xmlDocument.InsertBefore(comment, firstChild); else firstChild.InsertBefore(comment, firstChild.FirstChild); } return xmlDocument; }
/// <summary> /// Loads an XmlDocument from the filecontainer, replacing GET parameters and verifying permissions /// </summary> /// <param name="fileContainer"></param> /// <param name="xmlParseMode">The kind of text that's being parsed</param> /// <returns></returns> public XmlDocument LoadXmlDocument(IFileContainer fileContainer, XmlParseMode xmlParseMode) { WebConnection.TouchedFiles.Add(fileContainer); // Verify permission if (null == fileContainer.LoadPermission(WebConnection.Session.User.Id)) throw new WebResultsOverrideException(WebResults.From(Status._401_Unauthorized, "You do not have permission to read " + fileContainer.FullPath)); if (!(fileContainer.FileHandler is ITextHandler)) throw new WebResultsOverrideException(WebResults.From(Status._400_Bad_Request, fileContainer.FullPath + " must be a text file")); return LoadXmlDocument( fileContainer.CastFileHandler<ITextHandler>().ReadAll(), xmlParseMode, fileContainer.FullPath); }