正题:xml文件如下:
<?xml version="1.0" encoding="utf-8" standalone="no"?> <!-- 编制人:DOCFlying --> <!-- 编制时间:2007-08-05 --> <KeywordsDefinition> <!--KeywordType:分为Keyword(关键字)、Control(控件类型缩写)、Variable(变量类型缩写)、Class(类名称缩写)--> <Keyword> <No.>1</No.> <KeywordName>i_[variable name]</KeywordName> <KeywordType>Variable</KeywordType> <Describe>int 型变量的缩写定义。如:int i_year = 2007;</Describe> <InputTime>2007-08-01 15:13:40</InputTime> </Keyword> <Keyword> <No.>2</No.> <KeywordName>l_[variable name]</KeywordName> <KeywordType>Variable</KeywordType> <Describe>long 型变量的缩写定义。如:long l_personal = 1500000000;</Describe> <InputTime>2007-08-01 15:14:10</InputTime> </Keyword> <Keyword> <No.>3</No.> <KeywordName>bl_[variable name]</KeywordName> <KeywordType>Variable</KeywordType> <Describe>boolean 型变量的缩写定义。如:boolean bl_flag = true;</Describe> <InputTime>2007-08-01 15:14:55</InputTime> </Keyword> <Keyword> <No.>6</No.> <KeywordName>us_[variable name]</KeywordName> <KeywordType>Variable</KeywordType> <Describe>ushort 型变量的缩写定义。如:ushort us_personal = 8;</Describe> <InputTime>2007-08-01 15:15:40</InputTime> </Keyword> </KeywordsDefinition> |
1)生成制定文件名的xml文件;
2)追加xml文件节点;
3)遍历xml文件的节点;
4)修改匹配值的xml文件的节点;
5)删除匹配值的xml文件节点;
主要运用了xml的操作类,熟悉了XPath表达的写法。下边代码省略了前台ASP.NET代码,只提供C#的主要代码,代码中没有容错,仅以说明解决的方法为目的。
代码如下:
1)生成制定文件名的XML文件:TextBox1制定文件名;TextBox2描述文档信息(文档开头备注);TextBox3制定xml开始标记。在生成xml的同时,也可以一并添加节点,如下面代码中已注释的部分。
protected void Button1_Click(object sender, EventArgs e) ...{ //生成一个新的xml文件; if (this.TextBox1.Text.Trim() == "" || this.TextBox3.Text.Trim() == "") ...{ Response.Write("<script>alert('要生成的文件名称、文件的开始标记不能为空!');</script>"); return; } XmlTextWriter _xmlWriter = new XmlTextWriter(MapPath("xml/" + TextBox1.Text.Trim() + ".xml"),System.Text.Encoding.UTF8); |
2)追加节点:在追加节点是,为了确定节点No.的最大值,用了三种方法。其中第三种方法,用了遍历比较的办法,也是效率最差最笨的办法,是我最初的解决算法,而前两种是我再论坛中求教后改进的代码。第一种方法是在确保最后一个节点的No.值最大的情况下用的方法,第二种方法是在No.值大小顺序不定的情况下的解决办法。
而在真正插入节点的时候,也用了两种方法。第一种方法是我最初的解决办法,第二种是在论坛求教后改经的代码(在此特别感谢BearRui(开心熊 | 来地球抢分)的指教,求教原文见论坛:http://community.csdn.net/Expert/topic/5695/5695643.xml?temp=.7378656)。两种方法均能实现追加节点的功能。最大的区别在于,方法一向XmlElement.DocumentElement中AppendChild()XmlElement;方法二向XmlNode中AppendChild()XmlElement。
TextBox4设置No.值;TextBox5设置KeywordName值;DropDownList1确定KeywordType的值;TextBox6设置Describe的值。
/**//// <summary>
/// 向XML文件中插入节点。
/// </summary>
protected void Button2_Click(object sender, EventArgs e)
...{
//向xml文档中插入节点;
if (this.TextBox5.Text.Trim() == "" || this.TextBox6.Text.Trim() == "")
...{
Response.Write("<script>alert('No.、KeywordName、Describe的值均不能为空!')</script>");
return;
}
if (this.DropDownList1.SelectedItem.Value == "0")
...{
Response.Write("<script>alert('Type值必须选择!')</script>");
return;
}
if (this.TextBox1.Text.Trim() != "")
...{
string filename = MapPath("xml/" + this.TextBox1.Text.Trim() + ".xml");
XmlDocument xml_Doc = new XmlDocument();
xml_Doc.Load(filename);
//确定节点No.最大值,方法一:**********************************************
//如果xml文件的最后一个节点始终是最大的,可用以下的方法;
//string maxNo = xml_Doc.DocumentElement.LastChild.FirstChild.InnerText;
//确定节点No.最大值,方法一结束。******************************************
//确定节点No.最大值,方法二:********************************************
//查找xml文件节点No.的最大值;
string str_xpath = "//No.[not(text() < //No./text())]";
int maxNo;
XmlNode xn_testnode = xml_Doc.SelectSingleNode(str_xpath);
if (xn_testnode != null)
...{
maxNo = Convert.ToInt32(xn_testnode.ChildNodes[0].InnerText);
maxNo++;
}
else
...{
maxNo = 0;
}
//确定节点No.最大值,方法二结束。**********************
//确定节点No.最大值,方法三:**************************
/**//*
XPathNavigator xp_nav = xml_Doc.CreateNavigator();
//下面这行代码生成XpathExpression表达式,不过可以省略,在xp_nav.Compile()中直接用字符的Xpath路径也可。
//如:XPathNodeIterator xp_nodeite = xp_nav.Select("KeywordsDefinition/Keyword/No.")
XPathExpression xp_exp = xp_nav.Compile("KeywordsDefinition/Keyword/No.");
int i_no = 0; //(int)xp_nav.Evaluate(xp_exp);
XPathNodeIterator xp_nodeite = xp_nav.Select(xp_exp);
if(xp_nodeite.Count == 0)
goto TestEnd;
while (xp_nodeite.MoveNext())
{//寻找No.的最大值;
if (i_no < Convert.ToInt32(xp_nodeite.Current.Value))
{
i_no = Convert.ToInt32(xp_nodeite.Current.Value);
}
}
i_no++;
this.TextBox4.Text = i_no.ToString();
//确定节点No.最大值,方法三结束****************************。
//插入节点的方法一:
XmlElement xml_ele = xml_Doc.CreateElement("Keyword");
XmlElement xml_no = xml_Doc.CreateElement("No.");
xml_no.InnerText = i_no.ToString();
//xml_no.InnerText = maxNo.ToString();
xml_ele.AppendChild(xml_no);
XmlElement xml_name = xml_Doc.CreateElement("Name");
xml_name.InnerText = this.TextBox5.Text.Trim();
xml_ele.AppendChild(xml_name);
XmlElement xml_type = xml_Doc.CreateElement("Type");
xml_type.InnerText = this.DropDownList1.SelectedItem.Text;
xml_ele.AppendChild(xml_type);
XmlElement xml_dec = xml_Doc.CreateElement("Describe");
xml_dec.InnerText = this.TextBox6.Text.Trim();
xml_ele.AppendChild(xml_dec);
XmlElement xml_time = xml_Doc.CreateElement("InputTime");
xml_time.InnerText = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
xml_ele.AppendChild(xml_time);
xml_Doc.DocumentElement.AppendChild(xml_ele);
XmlTextWriter xml_writer = new XmlTextWriter(filename, System.Text.Encoding.UTF8);
xml_writer.Formatting = Formatting.Indented;
xml_Doc.WriteContentTo(xml_writer);
xml_writer.Close();
TestEnd:
return;
*/
//插入节点的方法二;
XmlNode xml_node = xml_Doc.SelectSingleNode("KeywordsDefinition");
XmlElement xml_ele = xml_Doc.CreateElement("Keyword");
XmlElement xmlEle_no = xml_Doc.CreateElement("No.");
xmlEle_no.InnerText = maxNo.ToString();
xml_ele.AppendChild(xmlEle_no);
XmlElement xe_name = xml_Doc.CreateElement("KeywordName");
xe_name.InnerText = TextBox5.Text.Trim();
xml_ele.AppendChild(xe_name);
XmlElement xe_type = xml_Doc.CreateElement("KeywordType");
xe_type.InnerText = DropDownList1.SelectedItem.Text;
xml_ele.AppendChild(xe_type);
XmlElement xe_des = xml_Doc.CreateElement("Describe");
xe_des.InnerText = TextBox6.Text.Trim();
xml_ele.AppendChild(xe_des);
XmlElement xe_date = xml_Doc.CreateElement("InputTime");
xe_date.InnerText = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
xml_ele.AppendChild(xe_date);
xml_node.AppendChild(xml_ele);
xml_Doc.Save(filename);
}
}
3)遍历xml文件的节点:这个功能的实现没那么轻松了,为了确定遍历到的当前节点,我设置用了static属性。方法一用了三个隐藏的TextBox,一个用来设置No.的最大值+1;一个用来设置No.的最小值-1;一个用来设置当前遍历的No.值。这样就可以实现xml结点的双向按顺序遍历,下面代码只实现了下后遍历查看。方法二虽然用static属性实现了功能,但是大家都知道,static的值在服务端是不变的,任何一个客户端对它的改变都会体现或影响其他的客户端。
TextBox7用来接受显示InputTime的值。
/**//// <summary>
/// 遍历xml文档节点;
/// </summary>
protected void Button5_Click(object sender, EventArgs e)
...{
XmlDocument xd_document = LoadXML(TextBox1.Text.Trim());
if (xd_document == null)
...{
Response.Write("<script>alert("指定的文件不存在,或文件名称为空!请查证!")</script>");
return;
}
//遍历文档节点之方法一***********************************
int i_pos;
if (h1.Text == string.Empty || h2.Text == string.Empty || h3.Text == string.Empty)
...{
string str_maxstr = "//No.[not(text() < //No./text())]";
string str_minstr = "//No.[not(text() > //No./text())]";
XmlNode xn_maxNode = xd_document.SelectSingleNode(str_maxstr);
XmlNode xn_minNode = xd_document.SelectSingleNode(str_minstr);
int i_max, i_min;
if (xn_maxNode != null || xn_minNode != null)
...{//向隐藏域赋值
i_max = Convert.ToInt32(xn_maxNode.ChildNodes[0].InnerText) + 1;
i_min = Convert.ToInt32(xn_minNode.ChildNodes[0].InnerText) - 1;
i_pos = i_min;
h1.Text = i_max.ToString();//最大值赋给隐藏域h1
h2.Text = i_min.ToString();//最小值赋给隐藏域h2
h3.Text = i_pos.ToString();//当前访问值赋给隐藏域h3
}
else
...{
Response.Write("<script>alert("不能遍历空文档!")</script>");
return;
}
}
i_pos = Convert.ToInt32(h3.Text);
Skip:
i_pos++;
if (i_pos == Convert.ToInt32(h1.Text))
...{
Response.Write("<script>alert("已经到了文档结尾!")</script>");
return;
}
XmlNode xn_posNode = xd_document.SelectSingleNode("//No.[text() = "" + i_pos.ToString() + ""]");
if (xn_posNode == null) goto Skip;
TextBox4.Text = xn_posNode.ParentNode.SelectSingleNode("No.").InnerText;
TextBox5.Text = xn_posNode.ParentNode.SelectSingleNode("KeywordName").InnerText;
DropDownList1.Items[DropDownList1.SelectedIndex].Selected = false;
for (int i_x = 0; i_x < DropDownList1.Items.Count; i_x++)
...{
if (DropDownList1.Items[i_x].Text == xn_posNode.ParentNode.SelectSingleNode("KeywordType").InnerText)
...{
DropDownList1.Items[i_x].Selected = true;
break;
}
}
TextBox6.Text = xn_posNode.ParentNode.SelectSingleNode("Describe").InnerText;
TextBox7.Text = xn_posNode.ParentNode.SelectSingleNode("InputTime").InnerText;
h3.Text = i_pos.ToString();
//遍历文档节点之方法一:End
//*******************************************
/**//*遍历文档节点之方法二:
if (!IsRead)
{
XPathNavigator xpn_nav = xd_document.CreateNavigator();
XPathNodeIterator xnp_NIter = xpn_nav.Select("KeywordsDefinition/Keyword/No.");
if (xnp_NIter.Count == 0) return;
IsRead = true;
}
XmlDocument xd_newdoc = LoadXML(TextBox1.Text.Trim());
//XmlNode xn_noede = xd_newdoc.SelectSingleNode("/Keyword/[No.=" + IDValue[NodeCount] + "]");
XmlNodeList xn_noede = xd_newdoc.SelectNodes("KeywordsDefinition/Keyword");
if (NodeCount >= xn_noede.Count)
{
Response.Write("<script>alert("已经到了文档的尾部!")</script>");
return;
}
XmlElement my_xmlele = (XmlElement)xn_noede.Item(NodeCount);
XmlNodeList my_nodelist = my_xmlele.ChildNodes;
foreach (XmlNode xn_mynode in my_nodelist)
{
switch(xn_mynode.Name)
{
case "No.":
TextBox4.Text = xn_mynode.InnerText;
break;
case "KeywordName":
TextBox5.Text = xn_mynode.InnerText;
break;
case "KeywordType":
DropDownList1.Items[DropDownList1.SelectedIndex].Selected = false;
for (int y = 0; y < DropDownList1.Items.Count; y++)
{
if (DropDownList1.Items[y].Text == xn_mynode.InnerText)
{
DropDownList1.Items[y].Selected = true;
break;
}
}
break;
case "Describe":
TextBox6.Text = xn_mynode.InnerText;
break;
case "InputTime":
TextBox7.Text = xn_mynode.InnerText;
break;
default:
break;
}
}
NodeCount++;
遍历文档节点之方法二:End */
}
代码中用到的static属性的代码如下:
private static bool bl_isRead = false;
private static int i_nodeCount = 0;
//确定遍历节点是否已经开始,
//如果没有在读取第一个结点之后将其设置为true;
private static bool IsRead
...{
get ...{ return bl_isRead; }
set ...{ bl_isRead = value; }
}
//获取或设置xml文档节点的总数;
private static int NodeCount
...{
get ...{ return i_nodeCount; }
set ...{ i_nodeCount = value; }
}
代码中还用到了两个方法:返回XmlDocument型的LoadXML(String XmlFileName);返回String型xml路径的XmlFilePath(string FilePath)。代码如下:
/**//// <summary>
/// 生成一个加载了xml文件的XmlDocument实例,并返回System.Xml.XmlDocument对象。
/// </summary>
/// <param name="XmlFileName">文件名称</param>
/// <returns>操作成功返回XmlDocument对象,否则返回null。</returns>
private XmlDocument LoadXML(String XmlFileName)
...{
XmlDocument xd_doc = new XmlDocument();
string filename = XmlFileName.Trim();
//int i_strlen = filename.Length;
if (filename != string.Empty)
...{
filename = XmlFilePath(filename);
xd_doc.Load(filename);
return xd_doc;
}
else
...{
return null;
}
}
/**//// <summary>
/// 构造文件路径字符串。
/// </summary>
/// <param name="FilePath">文件名称</param>
/// <returns>操作成功返回string,否则返回 String.Empty。</returns>
private String XmlFilePath(string FilePath)
...{
if (FilePath != string.Empty)
...{
int i_strlen = FilePath.Length;
if (FilePath.Substring(i_strlen - 4, 4) != ".xml")
...{
FilePath = MapPath("xml/" + FilePath + ".xml");
}
return FilePath;
}
else
...{
return string.Empty;
}
}
4)修改匹配指定No.值的xml节点:此功能也用了两种方法来实现,方法二是我最初的实现方法,是不是比较笨拙?方法一也是在求教后改进过的代码,最起码看起来代码简单多了。
/**//// <summary>
/// 保存xml文档节点的修改;
/// </summary>
protected void Button4_Click(object sender, EventArgs e)
...{
XmlDocument xd_document = this.LoadXML(TextBox1.Text.Trim());
if (xd_document == null)
...{
Response.Write("<script>alert("文件名称不能为空!")</script>");
return;
}
//修改节点数据之方法一:×××××××××
string str_xpath = "//No.[text() = "" + TextBox4.Text.Trim() + ""]";//此句代码与下句相同,只不过为XPath的简写方式;
//string str_xpath = "KeywordsDefinition/Keyword/No.[text() = "" + TextBox4.Text.Trim() + ""]";
XmlNode xn_testNode = xd_document.SelectSingleNode(str_xpath);
if (xn_testNode != null)
...{
xn_testNode.ParentNode.SelectSingleNode("KeywordName").InnerText = TextBox5.Text.Trim();
xn_testNode.ParentNode.SelectSingleNode("KeywordType").InnerText = DropDownList1.SelectedItem.Text;
xn_testNode.ParentNode.SelectSingleNode("Describe").InnerText = TextBox6.Text.Trim();
xn_testNode.ParentNode.SelectSingleNode("InputTime").InnerText = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
}
else
...{
Response.Write("<script>alert("当前文本没有匹配此值的节点供修改,请检查输入的修改匹配条件!")</script>");
return;
}
//End ×××××××××××××××××××××
/**//*修改节点数据之方法二:
XmlNodeList xn_nodelist = xd_document.SelectNodes("KeywordsDefinition/Keyword");
bool isdel = false;
foreach (XmlNode xn_newnode in xn_nodelist)
{
XmlElement xe_newele = (XmlElement)xn_newnode;
XmlNodeList xnl_mynode = xe_newele.ChildNodes;
foreach (XmlNode xn_mynode in xnl_mynode)
{
XmlElement xe_myele = (XmlElement)xn_mynode;
if (xe_myele.Name == "No." && xe_myele.InnerText == TextBox4.Text.Trim())
{
isdel = true;
break;
}
}
if (isdel)
{
XmlNode xn_node1 = xe_newele.SelectSingleNode("KeywordName");
xn_node1.InnerText = TextBox5.Text.Trim();
XmlNode xn_node2 = xe_newele.SelectSingleNode("KeywordType");
xn_node2.InnerText = DropDownList1.SelectedItem.Text;
XmlNode xn_node3 = xe_newele.SelectSingleNode("Describe");
xn_node3.InnerText = TextBox6.Text.Trim();
break;
}
}
End **/
xd_document.Save(XmlFilePath(TextBox1.Text.Trim()));
Response.Write("<script>alert("文件节点修改保存成功!")</script>");
}
5)删除匹配指定No.值的xml节点:下面的代码也用了两种方法实现删除的功能。同样,方法二是我最初的实现方法,方法一是求教后的改进代码。
/**//// <summary>
/// 删除xml文档节点;
/// </summary>
protected void Button3_Click(object sender, EventArgs e)
...{
XmlDocument xd_document = this.LoadXML(TextBox1.Text.Trim());
if (xd_document == null)
...{
Response.Write("<script>alert("文件名称不能为空!")</script>");
return;
}
//删除节点之方法一:
string str_xpath = "//No.[text() = "" + TextBox4.Text.Trim() + ""]";//此句代码与下句相同,只不过为XPath的简写方式;
//string str_xpath = "KeywordsDefinition/Keyword/No.[text() = "" + TextBox4.Text.Trim() + ""]";c
XmlNode xn_testNode = xd_document.SelectSingleNode(str_xpath);
if (xn_testNode != null)
...{
xn_testNode.ParentNode.ParentNode.RemoveChild(xn_testNode.ParentNode);
}
else
...{
Response.Write("<script>alert("当前文本没有匹配此值的节点供删除,请检查输入的匹配条件!")</script>");
return;
}
//删除节点之方法一:End
/**//*
* 删除节点之方法二:
XmlNodeList xn_nodelist = xd_document.SelectNodes("KeywordsDefinition/Keyword");
bool isdel = false;
foreach (XmlNode xn_newnode in xn_nodelist)
{
XmlElement xe_newele = (XmlElement)xn_newnode;
XmlNodeList xnl_mynode = xe_newele.ChildNodes;
foreach (XmlNode xn_mynode in xnl_mynode)
{
XmlElement xe_myele = (XmlElement)xn_mynode;
if (xe_myele.Name == "No.")
{
if (xe_myele.InnerText == TextBox4.Text.Trim())
{
//xn_mynode.ParentNode.ParentNode.RemoveChild(xn_mynode.ParentNode);
//上句代码和此foreach外的xn_newnode.ParentNode.RemoveChild(xn_newnode)功能相同;
isdel = true;
break;
}
else
{
break;
}
}
else
{
break;
}
}
if (isdel)
{
xn_newnode.ParentNode.RemoveChild(xn_newnode);
break;
}
}
End **/
xd_document.Save(XmlFilePath(TextBox1.Text.Trim()));
Response.Write("<script>alert("文件节点删除成功!")</script>");
}
好了,到这里关于xml文档的生成、追加、修改、删除、遍历都简单的实现了。可能确实很笨拙,不过不要紧,欢迎各位方家提出更好的实现方法,让小弟再学习学习。谢谢!
本文来自CSDN博客,转载请标明出处: