public override Item newItem(XmlNode node, XmlEditor document) { Item item = null; if (node.NodeType == XmlNodeType.Element) { item = new ElementItem(document); } else if (node.NodeType == XmlNodeType.Attribute ) { item = new AttrItem(document); } else if (node.NodeType == XmlNodeType.Text) { item = new TextItem(document); } else if (node.NodeType == XmlNodeType.ProcessingInstruction ) { item = new ProcessingInstructionItem(document); } else if (node.NodeType == XmlNodeType.XmlDeclaration ) { item = new DeclarationItem(document); } else if (node.NodeType == XmlNodeType.Comment) { item = new CommentItem(document); } else if (node.NodeType == XmlNodeType.CDATA) { item = new CDATAItem(document); } else if (node.NodeType == XmlNodeType.DocumentType) { item = new DocumentTypeItem(document); } else if (node.NodeType == XmlNodeType.EntityReference) { item = new EntityReferenceItem(document); } //item.m_document = document; return item; }
// 假定nsColl中的信息即将还原为xml的属性字符串,插入element节点的属性集合中, // 本函数为确保不会发生属性重名的错误,而特意对nsColl去重 public static void RemoveAttributeDup(ElementItem element, ref NamespaceItemCollection nsColl) { if (nsColl.Count == 0) return; // 对基准元素的属性进行一次去重操作 if (element.attrs != null) { for(int i=0; i<nsColl.Count; i++) { NamespaceItem item = (NamespaceItem)nsColl[i]; string strAttrString = item.AttrName; bool bOccurNamespaceAttr = false; foreach(AttrItem attr in element.attrs) { if (attr.IsNamespace == false) continue; bOccurNamespaceAttr = true; if (attr.Name == strAttrString) { nsColl.RemoveAt(i); i--; break; } } if (bOccurNamespaceAttr == false) break; // 说明element.attrs集合中,全部是普通类型的属性,没有名字空间型的属性,那样就意味着不用去重了 } } }
// 分支版本。不适合外部直接调用。 // 从指定位置向上(祖先),所有元素的属性都是展开状态,这可以直接利用 // 我们自己的DOM对象体系来搜集名字空间信息。 // 收集一个元素节点以外(上方)的名字空间信息。 // 包含element在内 // parameters: // element 基准元素 // return: // 返回名字空间信息集合 public static NamespaceItemCollection GatherOuterNamespacesByNativeDom( ElementItem element) { NamespaceItemCollection nsColl = new NamespaceItemCollection(); ElementItem current = (ElementItem)element; while(true) { if (current == null) break; if (current.m_attrsExpand == ExpandStyle.Collapse) { /* // 为了枚举本层属性,不得不展开属性数组对象,但是暂时没有作收缩回的功能 current.GetControl().ExpandChild(current, ExpandStyle.Expand, current.m_childrenExpand, true); Debug.Assert( current.m_attrsExpand == ExpandStyle.Expand, "展开后m_attrsExpand应当为true"); */ Debug.Assert(false, "调用本函数的人,应当确保从要求位置向上祖先路径中,每个元素的属性集合都是处于展开状态。"); } foreach(AttrItem attr in current.attrs) { if (attr.IsNamespace == false) continue; nsColl.Add(attr.LocalName, attr.GetValue(), true); // 只要prefix重就不加入 } current = (ElementItem)current.parent; } return nsColl; }
// 获得start独有的并且在top圈子以内未被定义的若干prefix // 注: start到top范围内被start以外元素使用过的prefix不包含在内 // parameters: // start 起点元素 // top 范围顶部元素。注意包含这个元素。 public static void GetUndefinedPrefix(ElementItem start, ElementItem top, out ArrayList aResult) { aResult = null; Hashtable aPrefix = start.GetUsedPrefix(true); if (start == top) goto END1; ElementItem current = (ElementItem)start.parent; while(true) { if (current == null) break; Hashtable aCurrentLevelPrefix = current.GetPrefix(ElementItem.GetPrefixStyle.All); // 从aPrefix中去除和aCurrentLevelPrefix相交的部分 RemoveDup(ref aPrefix, aCurrentLevelPrefix); if (current == top) break; current = (ElementItem)current.parent; } END1: aResult = new ArrayList(); aResult.AddRange(aPrefix.Keys); }
internal override string GetOuterXml(ElementItem FragmentRoot) { return "&" + this.Name + ";"; }
/* public virtual XPathNavigator CreateNavigator() { XmlEditorNavigator nav = new XmlEditorNavigator(this); return nav; } */ #endregion #region 创建节点 // 创建一个元素节点 // strName: 元素名称 // 注意本函数可以改造成创建带前缀的元素节点 strName格式为: abc:test // 前缀及对应URI的定义从上级节点找,如果找到,则创建成功,如果未找到,创建失败。 public ElementItem CreateElementItem(string strName) { ElementItem item = new ElementItem(this); item.Name = strName; item.Prefix = ""; item.LocalName = ItemUtil.GetLocalName(strName); // 新建的节点肯定是要初始化visual结构,并是展开状态的 item.m_bWantAttrsInitial =1; item.m_bWantChildInitial = 1; item.AttrsExpand = ExpandStyle.Expand; item.ChildrenExpand = ExpandStyle.Expand; return item; }
// ture 找到 public static bool LocateNamespaceByUri(ElementItem startItem, string strURI, out string strPrefix, out Item namespaceAttr) { strPrefix = ""; namespaceAttr = null; ElementItem currentItem = startItem; while(true) { if (currentItem == null) break; if (currentItem.attrs != null) { foreach(AttrItem attr in currentItem.attrs) { if (attr.IsNamespace == false) continue; if (attr.GetValue() == strURI) { strPrefix = attr.Name; namespaceAttr = attr; return true; } } } currentItem = (ElementItem)currentItem.parent; } return false; }
// 分支版本。不适合外部直接调用。 // 从指定位置向上(祖先),有一个以上元素的属性是收缩状态,这样就没法 // 利用我们自己的DOM对象体系来搜集名字空间信息,只能模拟一个XML局部字符串来借用 // .net DOM来帮助搜集名字空间信息 public static NamespaceItemCollection GatherOuterNamespacesByDotNetDom( ElementItem element) { string strXml = ""; NamespaceItemCollection nsColl = new NamespaceItemCollection(); ElementItem current = (ElementItem)element; while(true) { if (current == null || current is VirtualRootItem) break; strXml = "<" + current.Name + current.GetAttrsXml() + ">" + strXml + "</" + current.Name + ">"; current = (ElementItem)current.parent; } if (strXml == "") return nsColl; XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strXml); } catch (Exception ex) { throw (new Exception("GatherOuterNamespacesByDotNetDom()加载模拟xml代码出错: " + ex.Message)); } // 先确定起点 XmlNode currentNode = dom.DocumentElement; while(true) { if (currentNode.ChildNodes.Count == 0) break; currentNode = currentNode.ChildNodes[0]; } Debug.Assert(currentNode != null, ""); // 开始搜集信息 while(true) { if (currentNode == null) break; foreach(XmlAttribute attr in currentNode.Attributes) { if (attr.Prefix != "xmlns" && attr.LocalName != "xmlns") continue; if (attr.LocalName == "xmlns") nsColl.Add("", attr.Value, true); // 只要prefix重就不加入 else nsColl.Add(attr.LocalName, attr.Value, true); // 只要prefix重就不加入 } currentNode = currentNode.ParentNode; if (currentNode is XmlDocument) // 这样就算到根以上了 break; } return nsColl; }
// 自动判断的版本。适合被外界调用。 // 收集一个元素节点以外(上方)的名字空间信息。 // 包含element在内 // parameters: // element 基准元素 // return: // 返回名字空间信息集合 public static NamespaceItemCollection GatherOuterNamespaces( ElementItem element) { bool bFound = false; // 是否有一个以上的元素属性处于收缩状态 ElementItem current = (ElementItem)element; while(true) { if (current == null) break; if (current.m_attrsExpand == ExpandStyle.Collapse) { bFound = true; break; } current = (ElementItem)current.parent; } if (bFound == true) return GatherOuterNamespacesByDotNetDom(element); else return GatherOuterNamespacesByNativeDom(element); }
// parameters: // FragmentRoot 如果要加入额外名字空间的话,片段的顶部element对象。 // 如果==null,表示不必加入额外的名字空间信息 internal override string GetOuterXml(ElementItem FragmentRoot) { int i; string strOuterXml = ""; string strContent = ""; string strAttrXml = ""; // 通过递归儿子获得strContent for(i=0; i<this.children.Count;i++) { Item child = (Item)this.children[i]; strContent += child.GetOuterXml(FragmentRoot); } if (this == this.m_document.VirtualRoot) { return strContent; } string strAdditional = ""; if (FragmentRoot != null) //需要加额外的名字空间 { // 本层需要加入的额外名字空间属性 ArrayList aPrefix = null; ItemUtil.GetUndefinedPrefix(this, FragmentRoot, out aPrefix); for(i=0;i<aPrefix.Count;i++) { string strPrefix = (string)aPrefix[i]; if (strPrefix == "xml") continue; string strURI = ""; AttrItem foundAttr = null; bool bRet = ItemUtil.LocateNamespaceByPrefix(this, // 可以优化为FragmentRoot的父亲 strPrefix, out strURI, out foundAttr); if (bRet == false) { if (strPrefix != "") { throw(new Exception("前缀" +strPrefix+ "没有找到定义位置")); } else continue; } if (strPrefix != "") strAdditional += " xmlns:" + strPrefix + "='" + StringUtil.GetXmlStringSimple(strURI) + "'"; else strAdditional += " xmlns='" + StringUtil.GetXmlStringSimple(strURI) + "'"; } } // 似乎可以优化,改用GetAttrsXml()? for(i=0; i<this.attrs.Count;i++) { AttrItem attr = (AttrItem)this.attrs[i]; strAttrXml += " " + attr.GetOuterXml(FragmentRoot); } if (strAdditional != "") strAttrXml += strAdditional; //if (strAttrXml != "") // strAttrXml += " "; Debug.Assert(this.Name != "", "ElementItem的Name不应为空"); Debug.Assert(this != this.m_document.VirtualRoot, "前面已经处理了,不可能走到这里"); // 前面已经处理了,不可能走到这里 strOuterXml = "<" + this.Name + strAttrXml + ">" + strContent + "</" + this.Name + ">"; return strOuterXml; }
// 由path得到Item // parameters: // itemRoot 根item // strPath path // item out参数,返回item // return: // -1 error // 0 succeed public static int Path2Item(ElementItem itemRoot, string strPath, out Item item) { item = null; if (itemRoot == null) return -1; if (itemRoot.children == null) return -1; if (strPath == "") return -1; int nPosition = strPath.IndexOf ('/'); string strLeft= ""; string strRight = ""; if (nPosition >= 0) { strLeft = strPath.Substring(0,nPosition); strRight = strPath.Substring(nPosition+1); } else { strLeft = strPath; } //得到序号 int nIndex = getNo(strLeft); //得到名称 nPosition = strLeft.IndexOf ("["); string strName = strLeft.Substring (0,nPosition); int i=0; foreach(Item child in itemRoot.children ) { if (child.Name == strName) { //递归 if (i == nIndex) { if (strRight == "") { item = child; break; } else { if (!(child is ElementItem)) return -1; // text类型节点再也无法继续向下找儿子了 Debug.Assert(child is ElementItem); return Path2Item((ElementItem)child, strRight, out item); } } else i++; } } return 0; }
internal override string GetOuterXml(ElementItem FragmentRoot) { return StringUtil.GetXmlStringSimple(this.GetValue()); }
public void ExpandAttrs(ElementItem element, ExpandStyle expandStyle) { element.ExpandAttrsOrChildren(expandStyle, element.m_childrenExpand, true); }
// 根据一个前缀字符串, 从起点元素开始查找, 看这个前缀字符串是在哪里定义的URI。 // 也就是要找到xmlns:???=???这样的属性对象,返回在namespaceAttr参数中。 // 本来从返回的namespaceAttr参数中可以找到命中URI信息,但是为了使用起来方便, // 本函数也直接在strURI参数中返回了命中的URI // parameters: // startItem 起点element对象 // strPrefix 要查找的前缀字符串 // strURI [out]返回的URI // namespaceAttr [out]返回的AttrItem节点对象 // return: // ture 找到(strURI和namespaceAttr中有返回值) // false 没有找到 public static bool LocateNamespaceByPrefix(ElementItem startItem, string strPrefix, out string strURI, out AttrItem namespaceAttr) { strURI = ""; namespaceAttr = null; /* Debug.Assert(strPrefix != "", "strPrefix参数不应当为空。前缀为空时,无需调用本函数就知道没有找到"); if (strPrefix == "") return false; */ ElementItem currentItem = startItem; while(true) { if (currentItem == null) break; foreach(AttrItem attr in currentItem.attrs) { if (attr.IsNamespace == false) continue; string strLocalName = ""; int nIndex = attr.Name.IndexOf(":"); if (nIndex >= 0) { strLocalName = attr.Name.Substring(nIndex + 1); } else { Debug.Assert(attr.Name == "xmlns", "名字空间型的属性,如果name中无冒号,必然为xmlns。"); if (attr.Name == "xmlns") { strLocalName = ""; } } if (strLocalName == strPrefix) { strURI = attr.GetValue(); namespaceAttr = attr; return true; } } currentItem = (ElementItem)currentItem.parent; } return false; }
public static string GetPartXpath(ElementItem parent, Item item) { string strPath = ""; Item currentItem = null; if (parent.children != null) { currentItem = parent.children[0]; } int nIndex = 1; while(currentItem != null) { if (currentItem == item) { strPath = item.Name + "[" + System.Convert.ToString(nIndex) + "]"; break; } if (currentItem.Name == item.Name) nIndex += 1; currentItem = currentItem.GetNextSibling(); } return strPath; }
// 由item得到path // parameters: // itemRoot 根item // item 给定的item // strPath out参数,返回item的path // return: // -1 出错 // 0 成功 public static int Item2Path(ElementItem itemRoot, Item item, out string strPath) { strPath = ""; if (itemRoot == null) return -1; if (item == null) return -1; Item itemMyself; Item itemTemp; int nIndex; //当为属性节点时,加了属性path字符串 string strAttr = ""; if (item is AttrItem ) { strAttr = "/@" + item.Name; item = item.parent ; } while(item != null) { //与根节点相等 if (item.Equals(itemRoot) == true) break; itemMyself = item; item = item.parent; if (item == null) break; itemTemp = null; if (item is ElementItem && ((ElementItem)item).children != null) { itemTemp = ((ElementItem)item).children[0]; } nIndex = 1; while(itemTemp != null) { if (itemTemp.Equals(itemMyself) == true) { if (strPath != "") strPath = "/" + strPath; strPath = itemMyself.Name + "[" + System.Convert.ToString(nIndex) + "]" + strPath; break; } if (itemTemp.Name == itemMyself.Name) nIndex += 1; itemTemp = itemTemp.GetNextSibling(); } } strPath = strPath + strAttr; if (strPath == "") return 0; else return 1; }
public void SetInfo(string strTitle, string strInfo, ElementItem item) { this.Text = strTitle; this.label_info .Text = strInfo; this.m_element = item; if (m_element.attrs == null) return; foreach(Item attr in m_element.attrs ) { if (this.aExistAttr == null) this.aExistAttr = new ArrayList (); aExistAttr.Add (attr.Name ); } }
// parameter: // FragmentRoot 是否带名字空间,该参数仅对ElementItem有意义 internal virtual string GetOuterXml(ElementItem FragmentRoot) { return ""; }
public void ExpandChildren(ElementItem element, ExpandStyle expandStyle) { element.ExpandAttrsOrChildren(element.m_attrsExpand, expandStyle, true); }
// parameters: // descendant 假设的后代 低 // ancestor 假设的祖先 高 public static bool IsAncestorOf(ElementItem descendant, ElementItem ancestor) { Item currentItem = descendant.parent; while(true) { if (currentItem == null) return false; if (currentItem == ancestor) return true; currentItem = currentItem.parent; } // return false; }
internal override string GetOuterXml(ElementItem FragmentRoot) { return "<?" + this.Name + " " + this.GetValue() + "?>"; }
// 追加属性,带对话框 // return: // -1 error // 0 successed // -2 取消 public int AppendAttrWithDlg(ElementItem item, out string strError) { strError = ""; AttrNameDlg dlg = new AttrNameDlg (); dlg.SetInfo("新属性", "给'" + item.Name + "'追加新属性", item); dlg.ShowDialog(); if (dlg.DialogResult != DialogResult.OK) return -2; AttrItem attr = null; int nRet = this.CreateAttrItemFromUI(dlg.textBox_strElementName.Text, dlg.textBox_URI.Text, out attr, out strError); if (nRet == -1) return -1; attr.SetValue(dlg.textBox_value.Text); return item.AppendAttr(attr, out strError); }
// 得到InnerXml属性 // parameters: // FragmentRoot 是否加入外部名字空间信息,如果要加入,片段根元素是什么。 // 如果==null,所有的节点都不带额外的名称空间信息,如果!=null,所有层如果必要都可能会带上额外的名字空间信息 public string GetInnerXml(ElementItem FragmentRoot) { string strContent = ""; // 通过递归儿子获得strContent for(int i=0; i<this.children.Count;i++) { Item child = (Item)this.children[i]; if (child is ElementAttrBase) { strContent += child.GetOuterXml(FragmentRoot != null ? (ElementItem)child : null); } else { strContent += child.GetOuterXml(null); } } return strContent; }
// parameter: // strFullName: 可以带前缀 prefix:name // strURi: null 或者 空字符串 不带URI public int CreateElementItemFromUI(string strFullName, string strURI, out ElementItem element, out string strError) { strError = ""; element = null; int nIndex = strFullName.IndexOf(":"); if (nIndex == 0) { strError = "元素名称'" + strFullName + "'不合法"; return -1; } else if (nIndex > 0) { string strPrefix = strFullName.Substring(0,nIndex); string strLocalName = strFullName.Substring(nIndex+1); if (strLocalName == "") { strError = "元素名称'" + strFullName + "'不合法"; return -1; } if (strURI != null && strURI != "") { element = this.CreateElementItem(strPrefix, strLocalName, strURI); } else { element = this.CreateElementItem(strPrefix, strLocalName); } } else { if (strURI != null && strURI != "") { strError = "元素名称'" + strFullName + "'未指定前缀"; return -1; } element = this.CreateElementItem(strFullName); } return 0; }
public static XmlNamespaceManager GatherOuterNamespaces( ElementItem element, NameTable nt) { XmlNamespaceManager nsColl = new XmlNamespaceManager(nt); ElementItem current = element; string strName = element.Name; while(true) { if (current == null || current == current.m_document.VirtualRoot) { break; } nsColl.PushScope(); foreach(AttrItem attr in current.attrs) { if (attr.IsNamespace == false) continue; nsColl.AddNamespace(attr.LocalName, attr.GetValue()); // 只要prefix重就不加入 } current = (ElementItem)current.parent; } return nsColl; }
// 右 -- 剪切 public void CutToClipboard(Item item) { string strXml = item.OuterXml; Clipboard.SetDataObject(strXml); // ???????虚根 if (item == this.VirtualRoot) { this.Xml = ""; this.VirtualRoot = null; this.docRoot = null; } else { ElementItem myParent = item.parent; // 移走当前节点 myParent.Remove(item); } }
// 用XML文本替代当前节点以及全部下级 // parameter: // strInputText 输入的即将用来粘贴的文本 // startItem 起始item public int PasteOverwrite(string strInputText, Item startItem, bool bSetFocus, out string strError) { strError = ""; if (String.IsNullOrEmpty(strInputText) == true) { Debug.Assert(false,"Paste(),strInputText为null 或者 空字符串"); strError = "Paste(),strInputText为null 或者 空字符串"; return -1; } if (startItem == null) { this.SetXml(strInputText); return 0; } if (startItem == this.VirtualRoot) { this.SetXml(strInputText); return 0; } // 根据startItem的类型,把输入的字符串拼成xml string strXml = ""; if (startItem is AttrItem) strXml = "<root " + strInputText + " />"; else strXml = "<root>" + strInputText + "</root>"; XmlDocument dom = new XmlDocument(); try { dom.LoadXml(strXml); } catch(Exception ex) { strError = "paste() error,原因:" + ex.Message; return -1; } // item是新创建的临时元素 ElementItem item = new ElementItem(this); ElementInitialStyle style = new ElementInitialStyle(); style.attrsExpandStyle = ExpandStyle.Expand; style.childrenExpandStyle = ExpandStyle.Expand; style.bReinitial = false; item.Initial(dom.DocumentElement,this.allocator,style, false); // !!! // myParent是要覆盖的元素的父亲 ElementItem myParent = (ElementItem)startItem.parent; int nIndex = 0; bool bAttr = false; if (startItem is AttrItem) { bAttr = true; nIndex = myParent.attrs.IndexOf(startItem); Debug.Assert(nIndex != -1,"不可能的情况"); AttrItem startAttr = (AttrItem)startItem; foreach(AttrItem attr in item.attrs) { myParent.InsertAttrInternal(startAttr, attr, false, false); } myParent.RemoveAttrInternal(startAttr,false); } else { bAttr = false; // 找到startItem在myParent所有儿子中的索引位置 nIndex = myParent.children.IndexOf(startItem); Debug.Assert(nIndex != -1,"不可能的情况"); // 在startItem位置前面插入item的所有儿子 foreach(Item child in item.children) { // TODO: try // Exception: // 可能会抛出PrefixNotDefineException异常 myParent.InsertChildInternal(startItem, child, false, false); } // 删除startItem myParent.RemoveChildInternal(startItem,false); } myParent.InitialVisual(); int nWidth , nHeight; myParent.Layout(myParent.Rect.X, myParent.Rect.Y, myParent.Rect.Width, 0, //设为0,主要是高度变化 this.nTimeStampSeed++, out nWidth, out nHeight, LayoutMember.Layout | LayoutMember.Up); if (bSetFocus == true) { if (bAttr == true) { Item curItem = myParent.attrs[nIndex]; this.SetCurText(curItem,null); this.SetActiveItem(curItem); } else { Item curItem = myParent.children[nIndex]; this.SetCurText(curItem,null); this.SetActiveItem(curItem); } } else { this.SetCurText(this.m_selectedItem,this.m_curText); } // 可能会改变文档根, 重设一下 if (startItem.Parent == this.VirtualRoot) this.docRoot = this.GetDocRoot(); // 2006/6/22 xietao this.AfterDocumentChanged(ScrollBarMember.Both); this.Invalidate(); // 文档发生变化 this.FireTextChanged(); myParent.Flush(); return 0; }
// 专为供Xml属性设得私有函数 private void SetXml(string strXml) { strXml = strXml.Trim(); if (strXml == "") { if (this.VirtualRoot != null) { this.VirtualRoot.FireTreeRemoveEvents(this.VirtualRoot.GetXPath()); } this.VirtualRoot = null; this.docRoot = null; this.SetCurText(null,null); this.SetActiveItem(null); AfterDocumentChanged(ScrollBarMember.Both); this.Invalidate(); // 文档发生变化 this.FireTextChanged(); return; } if (this.VirtualRoot == null) { this.VirtualRoot = new VirtualRootItem(this); this.VirtualRoot.LayoutStyle = this.m_layoutStyle ; this.VirtualRoot.m_bConnected = true; } else { this.VirtualRoot.ClearAttrs(); this.VirtualRoot.ClearChildren(); } XmlDocument dom = new XmlDocument(); dom.PreserveWhitespace = true; dom.LoadXml(strXml); ElementInitialStyle style = new ElementInitialStyle(); style.attrsExpandStyle = ExpandStyle.Expand; style.childrenExpandStyle = ExpandStyle.Expand; style.bReinitial = false; this.VirtualRoot.Initial(dom,//dom.DocumentElement, allocator, style, true); this.docRoot = this.GetDocRoot(); this.VirtualRoot.InitialVisual(); int nWidth = 0; int nHeight = 0; this.VirtualRoot.Layout(0, 0, this.ClientSize .Width -1, 0 , nTimeStampSeed++, out nWidth, out nHeight, LayoutMember.Layout ); this.SetCurText(this.VirtualRoot,null); this.SetActiveItem(this.VirtualRoot); if (this.m_bFocused == true) this.curEdit.Focus(); AfterDocumentChanged(ScrollBarMember.Both); this.Invalidate(); // 文档发生变化 this.FireTextChanged(); }
internal override string GetOuterXml(ElementItem FragmentRoot) { return this.Name + "='" + StringUtil.GetXmlStringSimple(this.GetValue()) + "'"; }
internal override string GetOuterXml(ElementItem FragmentRoot) { return "<!DOCTYPE " + this.Name + " [" + this.GetValue() + "]>"; }