internal void InsertValueBeforeNode(XmlNode parent, XmlNode reference, DekiScriptLiteral value) { if ((value is DekiScriptXml) || (value is DekiScriptUri)) { XDoc xml = value.AsEmbeddableXml(Mode == DekiScriptEvalMode.EvaluateSafeMode); if (xml.HasName("html")) { // TODO (steveb): merge XML namespaces // merge <head> and <tail> sections AddHeadElements(xml); AddTailElements(xml); // loop over body elements in response foreach (XDoc body in xml["body"]) { string target = body["@target"].AsText; string conflict = body["@conflict"].AsText ?? "ignore"; // check if the main body is targeted or something else if (string.IsNullOrEmpty(target)) { // append body nodes foreach (XmlNode node in body.AsXmlNode.ChildNodes) { parent.InsertBefore(parent.OwnerDocument.ImportNode(node, true), reference); } } else { // check if the targeted body already exists if (Bodies.ContainsKey(target) && !StringUtil.EqualsInvariant(conflict, "replace")) { if (StringUtil.EqualsInvariant(conflict, "append")) { // append nodes to existing body Bodies[target].Add(body.AsXmlNode); } } else { // create a new body element List <XmlNode> list = new List <XmlNode>(); list.Add(body.AsXmlNode); Bodies[target] = list; } } } } else if (!xml.IsEmpty) { // replace the current node with the entire document parent.InsertBefore(parent.OwnerDocument.ImportNode(xml.AsXmlNode, true), reference); } } else if (value is DekiScriptComplexLiteral) { // append text respresentation of value parent.InsertBefore(CreateTextNode(value.ToString()), reference); } else { // append value cast to text string text = value.AsString(); if (!string.IsNullOrEmpty(text)) { parent.InsertBefore(CreateTextNode(text), reference); } } }
//--- Methods --- public DekiScriptEvaluationAccumulator Add(DekiScriptLiteral literal, bool safe) { if(literal == null) { throw new ArgumentNullException("literal"); } if(literal is DekiScriptNil) { // nothing to do return this; } // check if any value was accumulated if(_value == null) { if(literal is DekiScriptXml) { _value = ((DekiScriptXml)literal).Value.Clone(); } else { _value = literal; } return this; } // check if we can append a string value if(literal is DekiScriptString) { AddString(((DekiScriptString)literal).Value, safe); return this; } if(!(literal is DekiScriptUri) && !(literal is DekiScriptXml)) { AddString(literal.ToString(), safe); return this; } // check if we need to append an XML document XDoc doc = literal.AsEmbeddableXml(safe); if(doc.IsEmpty) { return this; } XDoc accumulator = ConvertToXml(safe); // build lookup for existing bodies in accumulator Dictionary<string, XDoc> bodies = new Dictionary<string, XDoc>(); foreach(XmlNode node in accumulator.AsXmlNode.ChildNodes) { if(node.NodeType == XmlNodeType.Element) { XmlElement element = (XmlElement)node; if(StringUtil.EqualsInvariant(node.LocalName, "body")) { string target = element.GetAttribute("target"); bodies[target] = accumulator[node]; } } } // loop over all root children in new document foreach(XmlNode node in doc.AsXmlNode.ChildNodes) { if(node.NodeType == XmlNodeType.Element) { XmlElement element = (XmlElement)node; if(StringUtil.EqualsInvariant(node.LocalName, "body")) { string target = element.GetAttribute("target"); XDoc body; if(bodies.TryGetValue(target, out body)) { // body already exists, check how it should be handled string conflict = element.GetAttribute("conflict"); if(string.IsNullOrEmpty(conflict)) { // default conflict resolution depends on target: no target (i.e. main body) is append, otherwise it is ignore conflict = string.IsNullOrEmpty(target) ? "append" : "ignore"; } switch(conflict) { case "replace": // replace existing body with new one body.RemoveNodes(); body.AddNodes(doc[node]); break; case "append": // append nodes to existing body body.AddNodes(doc[node]); break; case "ignore": // ignore new body break; } } else { // target body does not exist, append it accumulator.Start("body"); if(!string.IsNullOrEmpty(target)) { accumulator.Attr("target", target); } accumulator.AddNodes(doc[node]); accumulator.End(); } } else if(StringUtil.EqualsInvariant(node.LocalName, "head")) { XDoc head = accumulator["head"]; foreach(XmlNode child in node.ChildNodes) { head.Add(doc[child]); } } else if(StringUtil.EqualsInvariant(node.LocalName, "tail")) { XDoc head = accumulator["tail"]; foreach(XmlNode child in node.ChildNodes) { head.Add(doc[child]); } } } } return this; }
//--- Methods --- public DekiScriptEvaluationAccumulator Add(DekiScriptLiteral literal, bool safe) { if (literal == null) { throw new ArgumentNullException("literal"); } if (literal is DekiScriptNil) { // nothing to do return(this); } // check if any value was accumulated if (_value == null) { if (literal is DekiScriptXml) { _value = ((DekiScriptXml)literal).Value.Clone(); } else { _value = literal; } return(this); } // check if we can append a string value if (literal is DekiScriptString) { AddString(((DekiScriptString)literal).Value, safe); return(this); } if (!(literal is DekiScriptUri) && !(literal is DekiScriptXml)) { AddString(literal.ToString(), safe); return(this); } // check if we need to append an XML document XDoc doc = literal.AsEmbeddableXml(safe); if (doc.IsEmpty) { return(this); } XDoc accumulator = ConvertToXml(safe); // build lookup for existing bodies in accumulator Dictionary <string, XDoc> bodies = new Dictionary <string, XDoc>(); foreach (XmlNode node in accumulator.AsXmlNode.ChildNodes) { if (node.NodeType == XmlNodeType.Element) { XmlElement element = (XmlElement)node; if (StringUtil.EqualsInvariant(node.LocalName, "body")) { string target = element.GetAttribute("target"); bodies[target] = accumulator[node]; } } } // loop over all root children in new document foreach (XmlNode node in doc.AsXmlNode.ChildNodes) { if (node.NodeType == XmlNodeType.Element) { XmlElement element = (XmlElement)node; if (StringUtil.EqualsInvariant(node.LocalName, "body")) { string target = element.GetAttribute("target"); XDoc body; if (bodies.TryGetValue(target, out body)) { // body already exists, check how it should be handled string conflict = element.GetAttribute("conflict"); if (string.IsNullOrEmpty(conflict)) { // default conflict resolution depends on target: no target (i.e. main body) is append, otherwise it is ignore conflict = string.IsNullOrEmpty(target) ? "append" : "ignore"; } switch (conflict) { case "replace": // replace existing body with new one body.RemoveNodes(); body.AddNodes(doc[node]); break; case "append": // append nodes to existing body body.AddNodes(doc[node]); break; case "ignore": // ignore new body break; } } else { // target body does not exist, append it accumulator.Start("body"); if (!string.IsNullOrEmpty(target)) { accumulator.Attr("target", target); } accumulator.AddNodes(doc[node]); accumulator.End(); } } else if (StringUtil.EqualsInvariant(node.LocalName, "head")) { XDoc head = accumulator["head"]; foreach (XmlNode child in node.ChildNodes) { head.Add(doc[child]); } } else if (StringUtil.EqualsInvariant(node.LocalName, "tail")) { XDoc head = accumulator["tail"]; foreach (XmlNode child in node.ChildNodes) { head.Add(doc[child]); } } } } return(this); }