private static XmNodeOptions GetNodeOptions(XmlElement xe, string strXPath, XmContext ctx) { XmNodeOptions o = new XmNodeOptions(); ctx.GetNodeOptions(o, strXPath); o.LoadElementAttributes(xe); return(o); }
public static XmElementCollection FromChildNodes(XmlElement xeParent, string strParentXPath, XmContext ctx) { XmElementCollection c = new XmElementCollection(); if (xeParent == null) { Debug.Assert(false); return(c); } if (strParentXPath == null) { Debug.Assert(false); return(c); } if (ctx == null) { Debug.Assert(false); return(c); } Dictionary <string, XmlElement> d = c.m_d; foreach (XmlNode xn in xeParent.ChildNodes) { XmlElement xe = (xn as XmlElement); if (xe == null) { continue; } string strNameC = xe.Name; string strXPathC = strParentXPath + "/" + strNameC; string strKeyCustomC = ctx.GetNodeKey(xe, strXPathC); string strKey = BuildNodeKey(strNameC, strKeyCustomC, 0); if (d.ContainsKey(strKey)) { // In general, custom node keys should be unique Debug.Assert(string.IsNullOrEmpty(strKeyCustomC)); for (int i = d.Count; i >= 0; --i) { string strKeyTest = BuildNodeKey(strNameC, strKeyCustomC, i); if (d.ContainsKey(strKeyTest)) { Debug.Assert(i != d.Count); // Key must change in first iteration break; } strKey = strKeyTest; } Debug.Assert(!d.ContainsKey(strKey)); } c.Add(strKey, xe); } return(c); }
// Old, for plugins public static void MergeNodes(XmlDocument xd, XmlNode xn, XmlNode xnOverride) { XmlElement xeBase = (xn as XmlElement); XmlElement xeOverride = (xnOverride as XmlElement); string strXPath = ((xn != null) ? xn.Name : string.Empty); XmContext ctx = new XmContext(xd, delegate(XmNodeOptions oP, string strXPathP) { }, delegate(XmlNode xnP, string strXPathP) { return(null); }); MergeElements(xeBase, xeOverride, strXPath, null, ctx); }
internal static bool IsAlwaysEnforced(XmlNode xn, string strXPath, XmContext ctx) { if (xn == null) { Debug.Assert(false); return(false); } if (xn.NodeType == XmlNodeType.Document) { return(true); } // If xn is the document node, strXPath is empty if (string.IsNullOrEmpty(strXPath)) { Debug.Assert(false); return(false); } if (ctx == null) { Debug.Assert(false); return(false); } XmlElement xe = (xn as XmlElement); if (xe == null) { Debug.Assert(false); return(false); } XmNodeOptions o = GetNodeOptions(xe, strXPath, ctx); if ((o.NodeMode == XmNodeMode.None) || (o.NodeMode == XmNodeMode.Create)) { return(false); } if (o.ContentMode == XmContentMode.None) { return(false); } XmlNode xnP = xe.ParentNode; if (xnP == null) { Debug.Assert(false); return(false); } if (object.ReferenceEquals(xnP, xn)) { Debug.Assert(false); return(false); } int iSep = strXPath.LastIndexOf('/'); if (iSep < 0) { Debug.Assert(false); return(false); } string strXPathP = strXPath.Substring(0, iSep); return(IsAlwaysEnforced(xnP, strXPathP, ctx)); }
internal static XmlElement MergeElements(XmlElement xeBase, XmlElement xeOverride, string strXPath, XmlElement xeBaseParent, XmContext ctx) { if (xeOverride == null) { throw new ArgumentNullException("xeOverride"); } if (strXPath == null) { throw new ArgumentNullException("strXPath"); } if (ctx == null) { throw new ArgumentNullException("ctx"); } string strName = xeOverride.Name; Debug.Assert((xeBase == null) || (xeBase.Name == strName)); Debug.Assert((strXPath == strName) || strXPath.EndsWith("/" + strName)); Debug.Assert((xeBase == null) || (xeBaseParent == null) || object.ReferenceEquals(xeBase.ParentNode, xeBaseParent)); XmNodeOptions o = GetNodeOptions(xeOverride, strXPath, ctx); bool bContinue = false; switch (o.NodeMode) { case XmNodeMode.None: break; case XmNodeMode.Create: if ((xeBase == null) && (xeBaseParent != null)) { xeBase = ctx.BaseDocument.CreateElement(strName); xeBaseParent.AppendChild(xeBase); bContinue = true; } break; case XmNodeMode.Open: if (xeBase != null) { bContinue = true; } break; case XmNodeMode.OpenOrCreate: if (xeBase != null) { bContinue = true; } else if (xeBaseParent != null) { xeBase = ctx.BaseDocument.CreateElement(strName); xeBaseParent.AppendChild(xeBase); bContinue = true; } break; case XmNodeMode.Remove: if (xeBase != null) { if (xeBaseParent != null) { xeBaseParent.RemoveChild(xeBase); xeBase = null; // Return value, indicate removal } else { // Cannot remove element; clear it instead xeBase.InnerXml = string.Empty; } } break; default: Debug.Assert(false); break; } if (!bContinue) { return(xeBase); } if (xeBase == null) { Debug.Assert(false); return(null); } XmContentMode cm = o.ContentMode; if ((cm == XmContentMode.Merge) && !HasChildElement(xeBase) && !HasChildElement(xeOverride)) { cm = XmContentMode.Replace; } XmElementCollection xcBase = null, xcOverride = null; if (cm == XmContentMode.Merge) { xcBase = XmElementCollection.FromChildNodes(xeBase, strXPath, ctx); xcOverride = XmElementCollection.FromChildNodes(xeOverride, strXPath, ctx); if (o.ChildrenOtherMode == XmChildrenOtherMode.Remove) { List <string> lRemove = new List <string>(); foreach (KeyValuePair <string, XmlElement> kvpBaseC in xcBase) { if (xcOverride[kvpBaseC.Key] == null) { xeBase.RemoveChild(kvpBaseC.Value); lRemove.Add(kvpBaseC.Key); } } // Do not simply rebuild xcBase, because indices in // node keys would change xcBase = xcBase.Except(lRemove); } } switch (cm) { case XmContentMode.None: Debug.Assert(false); break; // Currently unused case XmContentMode.Merge: foreach (KeyValuePair <string, XmlElement> kvpOverrideC in xcOverride) { string strKeyC = kvpOverrideC.Key; XmlElement xeBaseC = xcBase[strKeyC]; XmlElement xeOverrideC = kvpOverrideC.Value; string strXPathC = strXPath + "/" + xeOverrideC.Name; XmlElement xeBaseCNew = MergeElements(xeBaseC, xeOverrideC, strXPathC, xeBase, ctx); if (!object.ReferenceEquals(xeBaseCNew, xeBaseC)) { Debug.Assert((xeBaseCNew == null) || (xeBaseC == null)); if (xeBaseCNew == null) { xcBase.Remove(strKeyC); } else { xcBase.Add(strKeyC, xeBaseCNew); } } } break; case XmContentMode.Replace: xeBase.InnerXml = SafeInnerXml(xeOverride); break; default: Debug.Assert(false); break; } if ((cm == XmContentMode.Merge) && (o.ChildrenSortOrder == XmChildrenSortOrder.This)) { xcBase.SortBy(xcOverride); xcBase.ReorderElementsOf(xeBase); } return(xeBase); }