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>
我在想,如果一个命名空间的属性名是空的,它就不会被包含在列表中。或者至少它不会被显示。这可能吗?我在网上找到的大多数例子都是关于删除没有子节点的父节点,但在我的例子中,这个父节点有子节点。
最简单的做法是加载 DocumentElement
的 ChildNodes
的 ChildNodes
,而不是 DocumentElement
的 ChildNodes
.
首先,更改 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);
所以我有一个 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>
我在想,如果一个命名空间的属性名是空的,它就不会被包含在列表中。或者至少它不会被显示。这可能吗?我在网上找到的大多数例子都是关于删除没有子节点的父节点,但在我的例子中,这个父节点有子节点。
最简单的做法是加载 DocumentElement
的 ChildNodes
的 ChildNodes
,而不是 DocumentElement
的 ChildNodes
.
首先,更改 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);