recursion,parsing具有属性的xml文件到treeview中c#
我目前正在开发一个应用程序将采取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
types的所有节点的文本显式设置为名称+属性数据,而不仅仅是具有子元素的元素,使用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; }
顺便说一句,我不build议这样做,因为下列实际上意味着同样的事情,即名称DataConfiguration
中的本地名称为DataConfiguration
的元素http://somenamespace
:
<ss:DataConfiguration xmlns:ss="http://somenamespace"/> <DataConfiguration xmlns="http://somenamespace"/>
你的树将显示第一个元素的命名空间,但不是第二个。
更新2
要在树中包含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
放置循环以在DisplayTreeView
包含XmlDeclaration
循环:
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); } }
尝试简单的recursionalgorithm
static void Main(string[] args) { string input = "<a>" + "<b>" + "<c>val1</c>" + "<d>val2</d>" + "</b>" + "<e>val3</e>" + "<f>val4</f>" + "</a>"; XmlDocument doc = new XmlDocument(); doc.LoadXml(input); RecursiveRead(doc.DocumentElement); } static string RecursiveRead(XmlNode node) { List<string> children = new List<string>(); bool done = false; if (node.HasChildNodes) { foreach (XmlNode child in node) { children.Add(RecursiveRead(child)); } Console.WriteLine("table : {0}; children : {1}", node.Name, string.Join(",", children.ToArray())); //string cmd = "INSERT INTO " + second + " (" + first + ") VALUES ('" + xml.Value + "')"; //SqlCommand command = new SqlCommand(cmd, conn); //command.ExecuteNonQuery(); } else { return node.Value; } return node.Name; }