【问题标题】:XML Parsing. Hide Parent nodeXML 解析。隐藏父节点
【发布时间】:2015-03-13 02:26:52
【问题描述】:

所以我有一个解析为 TreeView 列表的 xml 文件,目前我只需要三个节点时大约有四个级别的节点。我想隐藏/删除父节点或顶部节点,因为它没有多大用处。我可以通过编辑 XML 文件本身来做到这一点,但我不允许这样做。代码如下:

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 文件本身上删除它。该列表应该只显示类别和对象。仅供参考,命名空间在列表中显示为命名空间。以下是 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>

我在想,如果命名空间的属性名称为空,它将不会包含在列表中。或者至少不会显示。这可能吗?我在网上找到的大多数示例都与删除没有子节点的父节点有关,但在我的例子中,这个父节点有子节点。

【问题讨论】:

    标签: c# xml parsing treeview .net-2.0


    【解决方案1】:

    最简单的做法是加载DocumentElementChildNodesChildNodes,而不是DocumentElementChildNodes

    首先,将XmlTreeViewHelper.AddOrMergeNodes() 更改为与任何IEnumerable&lt;XmlNode&gt; 一起使用:

    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);
    

    【讨论】:

    • 嗯哇。有效。但我对 IEnumerable 并不熟悉,它有什么用?
    • @Kurisuchin - 这是一个通用接口,用于循环某些东西。比ICollection&lt;T&gt; 更基本,因为它没有Count 方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-17
    相关资源
    最近更新 更多