我目前在一个项目中,应用程序将处理XML文件并将其显示为C#的树状视图。我正在使用Visual Studio 10编写此代码。
我不能限制属性显示的次数。我使用了一个foreach循环来遍历它具有的每个属性并显示它,但是它为该节点下具有的每个子节点显示一次属性。如何修改此代码以仅显示属性一次?
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Xml; namespace xmlToTreeview { public partial class Form1 : Form { string samplePath = Application.StartupPath + @"\\sample.xml"; public Form1() { InitializeComponent(); DisplayTreeView(samplePath); } private void DisplayTreeView(string pathname) { try { // SECTION 1. Create a DOM Document and load the XML data into it. XmlDocument dom = new XmlDocument(); dom.Load(pathname); // SECTION 2. Initialize the TreeView control. treeView1.Nodes.Clear(); treeView1.Nodes.Add(new TreeNode(dom.DocumentElement.Name)); TreeNode tNode = new TreeNode(); tNode = treeView1.Nodes[0]; // SECTION 3. Populate the TreeView with the DOM nodes. AddNode(dom.DocumentElement, tNode); } catch (XmlException xmlEx) { MessageBox.Show(xmlEx.Message); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void AddNode(XmlNode inXmlNode, TreeNode inTreeNode) { XmlNode xNode; TreeNode tNode; XmlNodeList nodeList; int i; // Loop through the XML nodes until the leaf is reached. // Add the nodes to the TreeView during the looping process. if (inXmlNode.HasChildNodes) { nodeList = inXmlNode.ChildNodes; for (i = 0; i <= nodeList.Count - 1; i++) { xNode = inXmlNode.ChildNodes[i]; inTreeNode.Nodes.Add(new TreeNode(xNode.Name)); tNode = inTreeNode.Nodes[i]; //Check if the XmlNode has attributes if (inXmlNode.Attributes.Count != 0) { foreach (XmlAttribute att in inXmlNode.Attributes) { inTreeNode.Text = inTreeNode.Text + " " + att.Name + ": " + att.Value; } } AddNode(xNode, tNode); } } else { // Here you need to pull the data from the XmlNode based on the // type of node, whether attribute values are required, and so forth. inTreeNode.Text = (inXmlNode.OuterXml).Trim(); } treeView1.ExpandAll(); } } }
这是我的xml的示例
<?xml version="1.0" encoding="utf-8"?> <DataConfiguration xmln="abcefg12345" xmlns:xsi="12345abcefg" xsi:schemaLocation="12345abcefg12345abcefg"> <Hosts> <Sites> <Site Name="ss"> <Host Id="aa"> <Address Host="www.www.com"> </Address> </Host> <Host Id="ee"> <Address Host="www.www.com"> </Address> </Host> <Host Id="dd"> <Address Host="www.www.com"> </Address> </Host> <Host Id="pp"> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com/"/> </Host> <Host Id="ss"> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> </Host> <Host Id="561"> <Address Host="www.www.com"> </Address> </Host> </Site> <Site Name="hihi"> <Host Id="cc"> <Address Host="www.www.com"> </Address> </Host> <Host Id="sdD"> <Address Host="www.www.com"> </Address> </Host> <Host Id="8uj"> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> </Host> <Host Id="222"> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> </Host> <Host Id="hhh"> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> </Host> <Host Id="hhh"> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> </Host> </Site> </Sites> <Host Id="hhh"> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> </Host> <Host Id="hhh"> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> </Host> <Host Id="hhh"> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> </Host> <Host Id="hhh"> <Address Scheme="ppp" Host="www.www.com" Path="www.www.com"/> </Host> </Hosts> <DataPools> <DataPool Id="sss" default="sure"> <DataGroup Id="sss" Parent="aaa" UserCanSelectHost="sure" > <HostId Parent="hhhh">I'm breaking here</HostId> <DataSources> <empty/> </DataSources> </DataGroup> <DataGroup Id="ccc" UserCanSelectHost="whynot" > <HostId>God I'm breaking here again, i hope you can fix me</HostId> <DataSources> <empty/> </DataSources> </DataGroup> <DataGroup Id="sss" UserCanSelectHost="yessure" > <HostId>cry face</HostId> <webfg displaygroup="sss" provider="sss" id="ccc" principal="ccc" nioarc="ccc" nap="ccc" group="ccc"> </webfg> <nhood port="1234"/> <ServerNames> <!-- insert comment --> <!-- insert comment --> <!-- insert comment --> <ServerName>myname</ServerName> <ServerName>yourname</ServerName> </ServerNames> <!-- insert comment --> <Implementations> <Implementation> <Name>yourname</Name> <Type>typeme</Type> <Assembly>visionme</Assembly> <Path>ohno</Path> </Implementation> </Implementations>--> <cfgman port="ccc" /> <webservice provider="ccc" /> <webservice provider="ccc" /> <webservice provider="ccc" /> <parameters> <useeventpush value="ccc"/> </parameters> <webservice provider="ccc" /> <pollingFrequency value="1000"/> </DataGroup> </DataPool> <DataGroup Id="ccc " UserCanSelectHost="ccc" > <DataGroup Id="ccc " UserCanSelectHost="ccc" > <HostId>idk</HostId> <DataSources> <empty/> </DataSources> </DataGroup> <DataGroup Id="ccc " UserCanSelectHost="ccc" > <HostId>idk</HostId> <DataSources> <empty/> </DataSources> </DataGroup> <DataGroup Id="default" UserCanSelectHost="true" > <HostId>idk</HostId> </DataGroup> </DataGroup> </DataPools> </DataConfiguration>
您需要将循环属性通过子节点移出循环:
private void AddNode(XmlNode inXmlNode, TreeNode inTreeNode) { // Loop through the XML nodes until the leaf is reached. // Add the nodes to the TreeView during the looping process. if (inXmlNode.HasChildNodes) { //Check if the XmlNode has attributes foreach (XmlAttribute att in inXmlNode.Attributes) { inTreeNode.Text = inTreeNode.Text + " " + att.Name + ": " + att.Value; } var nodeList = inXmlNode.ChildNodes; for (int i = 0; i < nodeList.Count; i++) { var xNode = inXmlNode.ChildNodes[i]; var tNode = inTreeNode.Nodes[inTreeNode.Nodes.Add(new TreeNode(xNode.Name))]; AddNode(xNode, tNode); } } else { // Here you need to pull the data from the XmlNode based on the // type of node, whether attribute values are required, and so forth. inTreeNode.Text = (inXmlNode.OuterXml).Trim(); } treeView1.ExpandAll(); }
更新资料
如果要过滤名称空间属性,可以添加扩展方法:
public static class XmlNodeExtensions { public static bool IsDefaultNamespaceDeclaration(this XmlAttribute attr) { if (attr == null) return false; if (attr.NamespaceURI != "http://www.w3.org/2000/xmlns/") return false; return attr.Name == "xmlns"; } public static bool IsNamespaceDeclaration(this XmlAttribute attr) { if (attr == null) return false; if (attr.NamespaceURI != "http://www.w3.org/2000/xmlns/") return false; return attr.Name == "xmlns" || attr.Name.StartsWith("xmlns:"); } }
然后使用它跳过不需要的XmlAttribute实例。您还可以将所有类型的所有节点的文本显式设置XmlElement为名称+属性数据,而不仅仅是具有子元素的元素,OuterXml仅用于文本节点:
XmlAttribute
XmlElement
OuterXml
private void AddNode(XmlNode inXmlNode, TreeNode inTreeNode) { if (inXmlNode is XmlElement) { // An element. Display element name + attribute names & values. foreach (var att in inXmlNode.Attributes.Cast<XmlAttribute>().Where(a => !a.IsNamespaceDeclaration())) { inTreeNode.Text = inTreeNode.Text + " " + att.Name + ": " + att.Value; } // Add children foreach (XmlNode xNode in inXmlNode.ChildNodes) { var tNode = inTreeNode.Nodes[inTreeNode.Nodes.Add(new TreeNode(xNode.Name))]; AddNode(xNode, tNode); } } else { // Not an element. Character data, comment, etc. Display all text. inTreeNode.Text = (inXmlNode.OuterXml).Trim(); } treeView1.ExpandAll(); }
如果您确实只想过滤掉默认的名称空间定义,而保留其他名称空间定义,则可以执行以下操作:
// An element. Display element name + attribute names & values. foreach (var att in inXmlNode.Attributes.Cast<XmlAttribute>().Where(a => !a.IsDefaultNamespaceDeclaration())) { inTreeNode.Text = inTreeNode.Text + " " + att.Name + ": " + att.Value; }
顺便说一句,我不建议这样做,因为以下内容实际上是同一件事,即DataConfiguration在名称空间中具有本地名称的元素http://somenamespace:
DataConfiguration
http://somenamespace
<ss:DataConfiguration xmlns:ss="http://somenamespace"/> <DataConfiguration xmlns="http://somenamespace"/>
您的树将显示第一个元素的名称空间,而不显示第二个元素的名称空间。
更新2
要将包含XmlDeclaration在树中,请将顶级循环更改为:
XmlDeclaration
treeView1.Nodes.Clear(); foreach (XmlNode xNode in dom.ChildNodes) { var tNode = treeView1.Nodes[treeView1.Nodes.Add(new TreeNode(xNode.Name))]; AddNode(xNode, tNode); }
更新3
将循环包括在以下内容XmlDeclaration中DisplayTreeView:
DisplayTreeView
private void DisplayTreeView(string pathname) { try { // SECTION 1. Create a DOM Document and load the XML data into it. XmlDocument dom = new XmlDocument(); dom.Load(pathname); // SECTION 2. Initialize the TreeView control. treeView1.Nodes.Clear(); // SECTION 3. Populate the TreeView with the XML nodes. foreach (XmlNode xNode in dom.ChildNodes) { var tNode = treeView1.Nodes[treeView1.Nodes.Add(new TreeNode(xNode.Name))]; AddNode(xNode, tNode); } } catch (XmlException xmlEx) { MessageBox.Show(xmlEx.Message); } catch (Exception ex) { MessageBox.Show(ex.Message); } }