2015-03-13 2 views
0

Итак, у меня есть XML-файл, обработанный списком TreeView, в настоящее время у меня есть четыре уровня узлов, когда мне нужно только три. Я хочу скрыть/удалить родительский узел или верхний узел, так как он не очень полезен. Я мог бы это сделать, отредактировав сам файл XML, но мне не разрешено. Вот код:XML Parsing. Скрыть родительский узел

private void Form1_Load_1(object sender, EventArgs e) 
    { 
     // Initialize the controls and the form. 
     textBox2.Text = Application.StartupPath + "\\Continental.vsysvar"; 
    } 

    private void button6_Click(object sender, EventArgs e) 
    { 
     treeView1.BeginUpdate(); 
     try 
     { 
      // SECTION 1. Create a DOM Document and load the XML data into it. 
      XmlDocument dom = new XmlDocument(); 
      dom.Load(textBox2.Text); 
      // SECTION 2. Initialize the TreeView control. 
      try 
      { 
       // SECTION 2. Initialize the TreeView control. 
       //treeView1.Nodes.Clear(); 
       XmlTreeViewHelper.AddOrMergeNodes(treeView1.Nodes, dom.DocumentElement.ChildNodes, GetTreeNodeName, GetTreeNodeText, FilterNode); 
       // SECTION 3. Populate the TreeView with the DOM nodes. 
       treeView1.ExpandAll(); 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show(ex.Message); 
      } 
      finally 
      { 
       treeView1.EndUpdate(); 
      } 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message); 
     } 
    } 

    static string GetTreeNodeName(XmlNode inXmlNode) 
    { 
     string text = GetAttributeText(inXmlNode, "name"); 
     if (string.IsNullOrEmpty(text)) 
      text = inXmlNode.Name; 
     return text; 
    } 

    static string GetTreeNodeText(XmlNode inXmlNode) 
    { 
     string text = GetAttributeText(inXmlNode, "name"); 
     if (string.IsNullOrEmpty(text)) 
     { 
      if (inXmlNode.HasChildNodes) 
      { 
       text = inXmlNode.Name; 
      } 
      else 
      { 
       text = (inXmlNode.OuterXml).Trim(); 
      } 
     } 
     return text; 
    } 

    string filter = "_start"; // Reload when this changes. 

    bool FilterNode(XmlNode inXmlNode) 
    { 
     return FilterNode(inXmlNode, filter); 
    } 

    bool FilterNode(XmlNode inXmlNode, string nodeNameFilter) 
    { 
     if (inXmlNode.Name == "namespace" && inXmlNode.ChildNodes.Count == 0 && string.IsNullOrEmpty(GetAttributeText(inXmlNode, "name"))) 
      return false; 
     if (!string.IsNullOrEmpty(nodeNameFilter)) 
     { 
      string text = GetTreeNodeText(inXmlNode); 
      if (text.Contains(nodeNameFilter)) 
       return false; 
     } 
     return true; 
    } 
    static string GetAttributeText(XmlNode inXmlNode, string name) 
    { 
     XmlAttribute attr = (inXmlNode.Attributes == null ? null : inXmlNode.Attributes[name]); 
     return attr == null ? null : attr.Value; 
    } 

Там есть класс с именем XmlTreeViewHelper, но это довольно долго, так что я решил не включать его здесь (и это главная цель, чтобы отфильтровать узлы с определенным набором строки). Дайте мне знать, если я также включу его здесь.

Во всяком случае, когда я нажимаю на кнопку, результат будет выглядеть так:

имен
| --- Категория A
| ------- Объект A1
| --- ---- Объект A2
| --- Категория B
| ------- Объект B1
| ------- Объект B2

Как скрыть пространство имен? Мне не разрешено удалять его в самом файле xml. В списке должны отображаться только категории и объекты. FYI, пространство имен отображается в списке как пространство имен. Ниже приведен образец XML-файла.

<?xml version="1.0" encoding="utf-8"?> 
<systemvariables version="4"> 
    <namespace name="" comment=""> 
    <namespace name="_01_Test_Preparation" comment=""> 
     <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_02_Shipping_Status_Check" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" /> 
     <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_01_02_Shipping_Status_Check_start" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" /> 
    </namespace> 
    <namespace name="_02_Communication" comment=""> 
     <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_02_04_VCAN_StartLoad" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" /> 
     <variable anlyzLocal="2" readOnly="false" valueSequence="false" unit="" name="_02_08_XCP_Restbus_RAM_Monitor" comment="" bitcount="32" isSigned="true" encoding="65001" type="int" startValue="0" minValue="0" minValuePhys="0" maxValue="4" maxValuePhys="4" /> 
    </namespace> 
    </namespace> 
</systemvariables> 

Я думаю, что если имя атрибута пространства имен пуст, оно не будет включено в список. или, по крайней мере, он не будет показан. Это возможно? Большинство примеров, которые я нашел в Интернете, касаются удаления родительских узлов без дочерних узлов, но в моем случае этот родительский узел имеет дочерние узлы.

ответ

1

Проще всего сделать бы, чтобы загрузить ChildNodes из ChildNodes в DocumentElement, а не ChildNodes в DocumentElement.

Во-первых, изменить XmlTreeViewHelper.AddOrMergeNodes() работать с любым IEnumerable<XmlNode>:

public static class XmlNodeHelper 
{ 
    public static IEnumerable<XmlNode> ChildNodes(IEnumerable<XmlNode> xmlNodeList) 
    { 
     if (xmlNodeList == null) 
      yield break; 
     foreach (XmlNode node in xmlNodeList) 
      foreach (XmlNode childNode in node.ChildNodes) 
       yield return childNode; 
    } 

    public static IEnumerable<TNode> OfType<TNode>(XmlNodeList xmlNodeList) where TNode : XmlNode 
    { 
     // Convert XmlNodeList which implements non-generic IEnumerable to IEnumerable<XmlNode> by downcasting the nodes 
     if (xmlNodeList == null) 
      yield break; 
     foreach (XmlNode xmlNode in xmlNodeList) 
      if (xmlNode is TNode) 
       yield return (TNode)xmlNode; 
    } 
} 

public static class XmlTreeViewHelper 
{ 
    public static void AddOrMergeNodes(TreeNodeCollection treeNodeCollection, IEnumerable<XmlNode> xmlNodeList, GetString<XmlNode> getNodeName, GetString<XmlNode> getNodeText, Predicate<XmlNode> filter) 
    { 
     Dictionary<string, List<TreeNode>> dict = ToNodeDictionary(treeNodeCollection); 
     int index = 0; 
     foreach (XmlNode inXmlNode in xmlNodeList) 
     { 
      AddOrMergeNode(treeNodeCollection, inXmlNode, ref index, getNodeName, getNodeText, filter, dict); 
     } 

     foreach (List<TreeNode> list in dict.Values) 
      foreach (TreeNode leftover in list) 
      { 
       treeNodeCollection.Remove(leftover); 
      } 
    } 

    static bool IsNodeAtIndex(TreeNodeCollection nodes, TreeNode node, int index) 
    { 
     // Avoid n-squared nodes.IndexOf(node). 
     if (index < 0 || index >= nodes.Count) 
      return false; 
     return nodes[index] == node; 
    } 

    static void AddOrMergeNode(TreeNodeCollection treeNodeCollection, XmlNode inXmlNode, ref int index, GetString<XmlNode> getNodeName, GetString<XmlNode> getNodeText, Predicate<XmlNode> filter, Dictionary<string, List<TreeNode>> dict) 
    { 
     if (filter != null && !filter(inXmlNode)) 
      return; 

     string treeName = getNodeName(inXmlNode); 
     string treeText = (getNodeText == null ? treeName : getNodeText(inXmlNode)); 

     bool added = false; 

     TreeNode treeNode; 
     if (!DictionaryExtensions.TryRemoveFirst(dict, treeName, out treeNode)) 
     { 
      treeNode = new TreeNode(); 
      treeNode.Name = treeName; 
      treeNode.Text = treeText; 
      added = true; 
      treeNodeCollection.Insert(index, treeNode); 
     } 
     else 
     { 
      if (!IsNodeAtIndex(treeNodeCollection, treeNode, index)) 
      { 
       treeNodeCollection.Remove(treeNode); 
       treeNodeCollection.Insert(index, treeNode); 
      } 
     } 

     index++; 

     if (treeNode.Text != treeText) 
      treeNode.Text = treeText; 

     if (inXmlNode.HasChildNodes) 
      AddOrMergeNodes(treeNode.Nodes, XmlNodeHelper.OfType<XmlNode>(inXmlNode.ChildNodes), getNodeName, getNodeText, filter); 
     else 
      treeNode.Nodes.Clear(); 

     if (added) 
      treeNode.ExpandAll(); 
    } 

    /// <summary> 
    /// Returns a dictionary of tree nodes by node name. 
    /// </summary> 
    /// <param name="nodes"></param> 
    /// <returns></returns> 
    static Dictionary<string, List<TreeNode>> ToNodeDictionary(TreeNodeCollection nodes) 
    { 
     Dictionary<string, List<TreeNode>> dict = new Dictionary<string, List<TreeNode>>(); 
     foreach (TreeNode node in nodes) 
      DictionaryExtensions.Add(dict, node.Name, node); 
     return dict; 
    } 
} 

Затем просто загрузить узлы один уровень ниже в документе:

  XmlTreeViewHelper.AddOrMergeNodes(treeView1.Nodes, XmlNodeHelper.ChildNodes(XmlNodeHelper.OfType<XmlNode>(dom.DocumentElement.ChildNodes)), GetTreeNodeName, GetTreeNodeText, FilterNode); 
+0

Ухм вау. это сработало. Но я вообще не знаком с IEnumerable, для чего он нужен? – Kurisuchin

+0

@ Kurisuchin - это общий интерфейс для прохождения через что-то. Более простой, чем 'ICollection ', потому что у него нет метода 'Count'. – dbc

 Смежные вопросы

  • Нет связанных вопросов^_^