递归,使用属性为树形C#解析XML文件 [英] Recursion, parsing xml file with attributes into treeview c#
问题描述
我目前工作的一个项目,其中一个应用程序将在XML文件,它显示为C#中的树视图。我使用的Visual Studio 10写这篇code。
我不能限制的时间被显示的属性编号。我用了一个foreach循环遍历每个拥有并显示它的属性,但它是它具有节点下的每个childnode一次显示的属性。我怎么能修改此code,只显示一次属性?
使用系统;
使用System.Collections.Generic;
使用System.ComponentModel;
使用System.Data这;
使用System.Drawing中;
使用System.Linq的;
使用System.Text;
使用System.Windows.Forms的;
使用的System.Xml;命名空间xmlToTreeview
{
公共部分Form1类:表格
{
字符串samplePath = Application.StartupPath + @\\\\ sample.xml的;
公共Form1中()
{
的InitializeComponent();
DisplayTreeView(samplePath);
} 私人无效DisplayTreeView(字符串路径名)
{
尝试
{
//第1.创建一个DOM文档和XML数据加载到它。
XmlDocument的DOM =新的XmlDocument();
dom.Load(路径);
//第2节初始化TreeView控件。
treeView1.Nodes.Clear();
treeView1.Nodes.Add(新的TreeNode(dom.DocumentElement.Name));
树节点TNODE =新的TreeNode();
TNODE = treeView1.Nodes [0]; //第3部分填充与DOM节点树视图。
ADDNODE(dom.DocumentElement,TNODE); }
赶上(XmlException xmlEx)
{
MessageBox.Show(xmlEx.Message);
}
赶上(异常前)
{
MessageBox.Show(ex.Message);
}
}
私人无效ADDNODE(XmlNode的inXmlNode,树节点inTreeNode)
{
XmlNode的xNode;
树节点TNODE;
XmlNodeList中节点列表;
INT I; //循环通过XML节点,直至到达叶。
//在循环过程中添加到TreeView的节点。 如果(inXmlNode.HasChildNodes)
{
节点列表= inXmlNode.ChildNodes; 对于(i = 0; I< = nodeList.Count - 1;我++)
{
xNode = inXmlNode.ChildNodes [I]
inTreeNode.Nodes.Add(新的TreeNode(xNode.Name));
TNODE = inTreeNode.Nodes [I] //检查XmlNode的有属性
如果(inXmlNode.Attributes.Count!= 0)
{
的foreach(在inXmlNode.Attributes XmlAttribute ATT)
{
inTreeNode.Text = inTreeNode.Text ++ att.Name +:+ att.Value;
}
}
ADDNODE(xNode,TNODE);
}
}
其他
{
//这里您需要从基础上的XmlNode的拉取数据
//节点类型,属性值是否是必需的,等等。
inTreeNode.Text =(inXmlNode.OuterXml).Trim();
}
treeView1.ExpandAll();
}
}
}
这是我的XML的例子
<?XML版本=1.0编码=UTF-8&GT?;
< DataConfiguration xmln =abcefg12345的xmlns:XSI =12345abcefgXSI:的schemaLocation =12345abcefg12345abcefg>
<主机和GT;
<网站与GT;
<网站名称=SS>
<主机ID =AA>
<地址主机=www.www.com> < /地址>
< /主机>
<主机ID =EE>
<地址主机=www.www.com> < /地址>
< /主机>
<主机ID =DD>
<地址主机=www.www.com> < /地址>
< /主机>
<主机ID =PP>
<地址方案=PPP主机=www.www.comPATH =www.www.com/>
<地址方案=PPP主机=www.www.comPATH =www.www.com //>
< /主机>
<主机ID =SS>
<地址方案=PPP主机=www.www.comPATH =www.www.com/>
<地址方案=PPP主机=www.www.comPATH =www.www.com/>
< /主机>
<主机ID =561>
<地址主机=www.www.com> < /地址>
< /主机>
< /网站>
<网站名称=日冰>
<主机ID =CC>
<地址主机=www.www.com> < /地址>
< /主机>
<主机ID =SDD>
<地址主机=www.www.com> < /地址>
< /主机>
<主机ID =8uj>
<地址方案=PPP主机=www.www.comPATH =www.www.com/>
<地址方案=PPP主机=www.www.comPATH =www.www.com/> < /主机>
<主机ID =222>
<地址方案=PPP主机=www.www.comPATH =www.www.com/>
<地址方案=PPP主机=www.www.comPATH =www.www.com/>
< /主机>
<主机ID =HHH>
<地址方案=PPP主机=www.www.comPATH =www.www.com/>
< /主机>
<主机ID =HHH>
<地址方案=PPP主机=www.www.comPATH =www.www.com/>
< /主机>
< /网站>
< /网站与GT;
<主机ID =HHH>
<地址方案=PPP主机=www.www.comPATH =www.www.com/>
< /主机>
<主机ID =HHH>
<地址方案=PPP主机=www.www.comPATH =www.www.com/>
< /主机>
<主机ID =HHH>
<地址方案=PPP主机=www.www.comPATH =www.www.com/>
< /主机>
<主机ID =HHH>
<地址方案=PPP主机=www.www.comPATH =www.www.com/>
< /主机>< /主机和GT;
<&数据池GT;
<数据池n =SSS默认为确保>
< DATAGROUP n =SSS父=AAAUserCanSelectHost =确定>
<主机标识父=HHHH>我打破此处< /主机ID>
<数据源>
<空/>
< /数据源>
< / DATAGROUP>
< DATAGROUP n =CCCUserCanSelectHost =whynot>
<主机标识>上帝,我再次破这里,我希望你能解决我< /主机ID>
<数据源>
<空/>
< /数据源>
< / DATAGROUP>
< DATAGROUP n =SSSUserCanSelectHost =yessure>
<主机标识>哭脸< /主机ID>
< webfg显示组=SSS供应商=SSSID =CCC本金=CCCnioarc =CCC午睡=CCC组=CCC>
< / webfg> < nhood端口=1234/>
<&servernames节点GT;
<! - 插入注释 - >
<! - 插入注释 - >
<! - 插入注释 - >
<服务器>&MYNAME LT; /服务器名>
<服务器>提供yourname< /服务器名>
< / servernames节点>
<! - 插入注释 - >
<实现>
<实施>
<名称>&提供yourname LT; /名称>
<类型> typeme< /型号>
<大会> visionme< /组装>
<路径>&大野LT; /路径和GT;
< /实施>
&所述; /实现与GT - →;
< cfgman端口=CCC/>
< Web服务提供=CCC/>
< Web服务提供=CCC/>
< Web服务提供=CCC/>
<&参数GT;
< useeventpush值=CCC/>
< /参数>
< Web服务提供=CCC/>
< pollingFrequency值=1000/>
< / DATAGROUP>
< /&数据池GT;
< DATAGROUP n =CCCUserCanSelectHost =CCC>
< DATAGROUP n =CCCUserCanSelectHost =CCC>
<主机标识>&IDK的LT; /主机ID>
<数据源>
<空/>
< /数据源>
< / DATAGROUP>
< DATAGROUP n =CCCUserCanSelectHost =CCC>
<主机标识>&IDK的LT; /主机ID>
<数据源>
<空/>
< /数据源>
< / DATAGROUP>
< DATAGROUP n =默认UserCanSelectHost =真>
<主机标识>&IDK的LT; /主机ID>
< / DATAGROUP>
< / DATAGROUP>
< /数据池>
< / DataConfiguration>
您需要通过属性通过子节点移动的循环圈外的:
私人无效ADDNODE(XmlNode的inXmlNode,树节点inTreeNode)
{
//循环通过XML节点,直至到达叶。
//在循环过程中添加到TreeView的节点。 如果(inXmlNode.HasChildNodes)
{
//检查XmlNode的有属性
的foreach(在inXmlNode.Attributes XmlAttribute ATT)
{
inTreeNode.Text = inTreeNode.Text ++ att.Name +:+ att.Value;
} VAR节点列表= inXmlNode.ChildNodes;
的for(int i = 0; I< nodeList.Count;我++)
{
VAR xNode = inXmlNode.ChildNodes [I]
VAR TNODE = inTreeNode.Nodes [inTreeNode.Nodes.Add(新的TreeNode(xNode.Name))];
ADDNODE(xNode,TNODE);
}
}
其他
{
//这里您需要从基础上的XmlNode的拉取数据
//节点类型,属性值是否是必需的,等等。
inTreeNode.Text =(inXmlNode.OuterXml).Trim();
}
treeView1.ExpandAll();
}
更新
如果你想过滤掉命名空间的属性,你可以添加扩展方法一>:
公共静态类XmlNodeExtensions
{
公共静态布尔IsDefaultNamespaceDeclaration(此XmlAttribute ATTR)
{
如果(ATTR == NULL)
返回false;
如果(attr.NamespaceURI!=http://www.w3.org/2000/xmlns/)
返回false;
返回attr.Name ==的xmlns
} 公共静态布尔IsNamespaceDeclaration(此XmlAttribute ATTR)
{
如果(ATTR == NULL)
返回false;
如果(attr.NamespaceURI!=http://www.w3.org/2000/xmlns/)
返回false;
返回attr.Name ==的xmlns|| attr.Name.StartsWith(的xmlns:);
}
}
然后用它来跳过不必要的 XmlAttribute
实例。您也可以明确设置类型的XmlElement
的所有节点的文本是名称+属性数据,而不仅仅是那些有孩子的因素,使用 OuterXml
仅适用于文本节点:
私人无效ADDNODE(XmlNode的inXmlNode,树节点inTreeNode)
{
如果(inXmlNode是XmlElement的)
{
//一个元素。显示元素名称+属性名和放大器;值。
的foreach(VAR ATT在inXmlNode.Attributes.Cast&所述; XmlAttribute方式>()如(A =>!a.IsNamespaceDeclaration()))
{
inTreeNode.Text = inTreeNode.Text ++ att.Name +:+ att.Value;
}
//添加儿童
的foreach(XmlNode的xNode在inXmlNode.ChildNodes)
{
VAR TNODE = inTreeNode.Nodes [inTreeNode.Nodes.Add(新的TreeNode(xNode.Name))];
ADDNODE(xNode,TNODE);
}
}
其他
{
//无的元素。人物资料,评论等,显示所有文本。
inTreeNode.Text =(inXmlNode.OuterXml).Trim();
}
treeView1.ExpandAll();
}
如果你真的想筛选出只是默认命名空间定义,但离开别人,你可以这样做:
//的元素。显示元素名称+属性名和放大器;值。
的foreach(VAR ATT在inXmlNode.Attributes.Cast&所述; XmlAttribute方式>()如(A =>!a.IsDefaultNamespaceDeclaration()))
{
inTreeNode.Text = inTreeNode.Text ++ att.Name +:+ att.Value;
}
顺便说一句,我不建议,因为实际上下面的意思是一样的,即以本地名称 DataConfiguration
命名空间中的元素这样做HTTP:// somenamespace
:
< SS:DataConfiguration的xmlns:SS =HTTP:// somenamespace/>
< DataConfiguration的xmlns =HTTP:// somenamespace/>
您树将显示命名为第一元件而非第二
更新2
要包括 XmlDeclaration
在树中,更改顶层循环是:
treeView1.Nodes.Clear();
的foreach(XmlNode的xNode在dom.ChildNodes)
{
VAR TNODE = treeView1.Nodes [treeView1.Nodes.Add(新的TreeNode(xNode.Name))];
ADDNODE(xNode,TNODE);
}
更新3
把循环包括在 XmlDeclaration
循环 DisplayTreeView
:
私人无效DisplayTreeView(字符串路径名)
{
尝试
{
//第1.创建一个DOM文档和XML数据加载到它。
XmlDocument的DOM =新的XmlDocument();
dom.Load(路径); //第2节初始化TreeView控件。
treeView1.Nodes.Clear(); //第3部分填充的XML节点树视图。
的foreach(XmlNode的xNode在dom.ChildNodes)
{
VAR TNODE = treeView1.Nodes [treeView1.Nodes.Add(新的TreeNode(xNode.Name))];
ADDNODE(xNode,TNODE);
}
}
赶上(XmlException xmlEx)
{
MessageBox.Show(xmlEx.Message);
}
赶上(异常前)
{
MessageBox.Show(ex.Message);
}
}
I'm currently working on a project where an application will take on XML files and display it into a treeview in C#. I'm using Visual Studio 10 to write this code.
I cannot limit number of times the attributes are displayed. I used a foreach loop to loop through each of the attributes it has and display it, but it's displaying the attributes once for each childnode it has under the node. How can I modify this code to only display the attributes once?
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();
}
}
}
And here is an example of my 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>
You need to move the loop through attributes out of the loop through child nodes:
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();
}
Update
If you want to filter out namespace attributes, you can add extension methods:
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:");
}
}
Then use it to skip unwanted XmlAttribute
instances. You can also explicitly set the text of all nodes of type XmlElement
to be name + attribute data, not just those elements with children, using OuterXml
only for text nodes:
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();
}
If you really want to filter out just the default namespace definitions but leave others, you could do:
// 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;
}
Incidentally, I don't recommend doing this since the following actually mean the same thing, namely an element with local name DataConfiguration
in the namespace http://somenamespace
:
<ss:DataConfiguration xmlns:ss="http://somenamespace"/>
<DataConfiguration xmlns="http://somenamespace"/>
Your tree will display the namespace for the first element but not the second.
Update 2
To include the XmlDeclaration
in the tree, change the top level loop to be:
treeView1.Nodes.Clear();
foreach (XmlNode xNode in dom.ChildNodes)
{
var tNode = treeView1.Nodes[treeView1.Nodes.Add(new TreeNode(xNode.Name))];
AddNode(xNode, tNode);
}
Update 3
Put the loop to include the XmlDeclaration
loop in 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);
}
}
这篇关于递归,使用属性为树形C#解析XML文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!