/// <summary> /// Treats all include tags, if there are bad reference on document, catches exception and tries to find fallback, which is treated as document. /// </summary> /// <param name="includeNodes">Nodes, which will be replace</param> /// <param name="document">Document, which contains includeNodes</param> /// <param name="absoluteUri">Uri of document</param> /// <param name="nsPrefix">Prefix of include namespace</param> /// <param name="nsm">Namespace Manager of document</param> /// <returns></returns> bool TreatIncludes(XmlElement[] includeNodes, XmlDocument document, string absoluteUri, string nsPrefix, XmlNamespaceManager nsm) { foreach (var includeElement in includeNodes) { var valueOfXPoiner = includeElement.GetAttribute(atXPointer); var valueOfHref = includeElement.GetAttribute(atHref); if (string.IsNullOrEmpty(valueOfHref)) // There must be xpointer Attribute, if not, fatal error.. { if (string.IsNullOrEmpty(valueOfXPoiner)) { PhpLibXml.IssueXmlError(_ctx, PhpLibXml.LIBXML_ERR_WARNING, 0, 0, 0, $"DOMDocument::xinclude(): detected a local recursion with no xpointer in {absoluteUri} in {_ctx.MainScriptFile.Path}", absoluteUri); return(true); } _documents.Push(document); var includeUri = includeElement.BaseURI + valueOfXPoiner; if (_references.ContainsKey(includeUri)) // fatal error, cycle recursion { PhpLibXml.IssueXmlError(_ctx, PhpLibXml.LIBXML_ERR_WARNING, 0, 0, 0, $"DOMDocument::xinclude(): detected a recursion in {absoluteUri} in {_ctx.MainScriptFile.Path}", absoluteUri); return(true); } _references[absoluteUri] = includeUri; IncludeXml(includeElement.BaseURI, includeElement, null, valueOfXPoiner); return(false); } // Resolving absolute and relative uri... string uri = UriResolver(valueOfHref, Path.GetDirectoryName(absoluteUri)); // Resolving type of parsing. string typeOfParse = includeElement.GetAttribute(atParse); try { if (string.Equals(typeOfParse, "text", StringComparison.OrdinalIgnoreCase)) { _documents.Push(document); IncludeText(uri, includeElement); } else { if (_references.ContainsKey(uri + valueOfXPoiner)) // fatal error, cycle recursion { PhpLibXml.IssueXmlError(_ctx, PhpLibXml.LIBXML_ERR_WARNING, 0, 0, 0, $"DOMDocument::xinclude(): detected a recursion in {absoluteUri} in {_ctx.MainScriptFile.Path}", absoluteUri); //return true; } else { _documents.Push(document); _references[absoluteUri] = uri + valueOfXPoiner; IncludeXml(uri, includeElement, null, string.IsNullOrEmpty(valueOfXPoiner) ? null : valueOfXPoiner); } } } catch (System.IO.FileNotFoundException) { PhpLibXml.IssueXmlError(_ctx, PhpLibXml.LIBXML_ERR_WARNING, 0, 0, 0, $"DOMDocument::xinclude(): I/O warning : failed to load external entity "{absoluteUri}" in {_ctx.MainScriptFile.Path}", absoluteUri); _documents.Pop(); XmlElement[] fallbacks = includeElement.GetElementsByTagName(nsPrefix + ":" + etFallback).OfType <XmlElement>().ToArray <XmlElement>(); if (fallbacks.Length > 1) // fatal error { PhpLibXml.IssueXmlError(_ctx, PhpLibXml.LIBXML_ERR_WARNING, 0, 0, 0, $"DOMDocument::xinclude(): include has multiple fallback children in {_ctx.MainScriptFile.Path}", _ctx.MainScriptFile.Path); return(true); } if (fallbacks.Length == 1) { XmlElement[] includes = fallbacks[0].SelectNodes($".//{nsPrefix}:{etInclude}[ not( descendant::{nsPrefix}:{etFallback} ) ]", nsm).OfType <XmlElement>().ToArray(); while (fallbacks[0].ChildNodes.Count != 0) { includeElement.ParentNode.InsertAfter(fallbacks[0].LastChild, includeElement); } TreatIncludes(includes, document, absoluteUri, nsPrefix, nsm); includeElement.ParentNode.RemoveChild(includeElement); } else // error missing fallback { PhpLibXml.IssueXmlError(_ctx, PhpLibXml.LIBXML_ERR_WARNING, 0, 0, 0, $"DOMDocument::xinclude(): could not load {absoluteUri}, and no fallback was found in {_ctx.MainScriptFile.Path}", absoluteUri); return(true); } } _references = new Dictionary <string, string>(); } return(false); }