XML 正在解析。隐藏父节点

XML Parsing. Hide Parent node

所以我有一个 xml 文件解析为 TreeView 列表,目前我有大约四级节点,而我只需要三级。我想 hide/remove 父节点或顶级节点,因为它用处不大。我可以通过编辑 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;
    }

有一个 class 名为 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>

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

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

首先,更改 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);