赶紧写完,不然就忘了
仅代表本新手的个人小结,如有错误恳请指出!
示例代码均(大概)来自https://github.com/DiamondMofeng/HFUT-AutoSignGUI
微软官方最详细的文档:https://docs.microsoft.com/zh-cn/dotnet/api/system.xml(个人觉得还是某些地方有纰漏..)
XmlDocument
XmlDocument可通过文件路径或字符串加载xml至内存中。
好处是方便易用,坏处是可能占用较多的内存。
继承自XmlNode类,所以可以用XmlNode类的属性或方法来对内部进行操作
对xml内已有内容进行修改
下列代码是一个实例,加载模板xml,对指定内容进行修改之后保存为新xml。
通过doc的DocumentElement属性获取整个xml文件的所有元素,再用以xpath的方式选择对应元素(XmlNode.SelectSingleNode(xpath) ,直接对内部文本进行修改,最后保存修改后的XmlDocument.
public static void GenerateTaskXMLFromPattern(string PathXMLpattern, string PathXMLExport
, string taskID
, string hh , string mm
, string TimerEnabled
, string LogonEnabled
, string ExecPath
, string Arguments
, string DirectoryPath)
{
XmlDocument doc = new XmlDocument();
doc.Load(PathXMLpattern);
// 加载命名空间,因为模板文档里面带了命名空间
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("p", "http://schemas.microsoft.com/windows/2004/02/mit/task");
XmlNode node;
XmlNode root = doc.DocumentElement;
//taskID
node = root.SelectSingleNode("/p:Task/p:RegistrationInfo/p:URI", nsmgr);
node.InnerText = "\\HFUT\\" + taskID;
//运行时间
if (TimerEnabled == "true")
{
node = root.SelectSingleNode("/p:Task/p:Triggers/p:CalendarTrigger/p:StartBoundary", nsmgr);
node.InnerText = "2021-01-01T" + hh + ":" + mm + ":00";
}
//是否定时运行
node = root.SelectSingleNode("/p:Task/p:Triggers/p:CalendarTrigger/p:Enabled", nsmgr);
node.InnerText = TimerEnabled;
//是否登陆时运行
node = root.SelectSingleNode("/p:Task/p:Triggers/p:LogonTrigger/p:Enabled", nsmgr);
node.InnerText = LogonEnabled;
//要运行的软件的路径
node = root.SelectSingleNode("/p:Task/p:Actions/p:Exec/p:Command", nsmgr);
node.InnerText = ExecPath;
//启动项参数
node = root.SelectSingleNode("/p:Task/p:Actions/p:Exec/p:Arguments", nsmgr);
node.InnerText = Arguments;
//工作目录
node = root.SelectSingleNode("/p:Task/p:Actions/p:Exec/p:WorkingDirectory", nsmgr);
node.InnerText = DirectoryPath;
//写入用户id,以通过安全性检查;无需外部参数
node = root.SelectSingleNode("/p:Task/p:Principals/p:Principal/p:UserId", nsmgr);
node.InnerText = Environment.UserName;
doc.Save(PathXMLExport);
//doc.Save(Console.Out);
//Console.ReadKey(true);
}
向xml内添加新节点、属性
下面的实例中,xml是已在别处加载好的文档,含有根节点<TaskList/>
public static void addTaskToXML(XmlDocument xml, string TaskID, string account, string mode, string hh, string mm)
{
//为TaskList添加元素Task
XmlNode TaskList = xml.SelectSingleNode("TaskList");//查找<TaskList>节点
XmlElement Task = xml.CreateElement("Task");//创建一个<Task>元素节点
Task.SetAttribute("id", TaskID);//设置该节点id属性
TaskList.AppendChild(Task);//添加<Task>到<TaskList>节点中
//为Task添加内容
XmlElement acc = xml.CreateElement("account");//添加<account>元素节点
acc.InnerText = account;//设置<account>元素节点的文本节点内容
Task.AppendChild(acc);//添加<account>到<Task>节点中
XmlElement solution = xml.CreateElement("solution");
solution.InnerText = mode;
Task.AppendChild(solution);
XmlElement time = xml.CreateElement("time");
time.InnerText = hh + ":" + mm;
Task.AppendChild(time);
}
删除Xml内节点
下面的代码实例了一个根据变量taskID,匹配xml内节点的ID属性符合条件的节点,并进行删除。
(最后保存覆盖原文件)
public static void DeleteTaskInXML(string XMLPath, string taskID)
{
XmlDocument xml = new XmlDocument();
xml.Load(XMLPath);
XmlElement taskToRemove = xml.GetElementById(taskID);
xml.DocumentElement.RemoveChild(taskToRemove);
xml.Save(XMLPath);
}
XmlReader
XmlReader是一个抽象类,但可以通过XmlReader.Create()方法来创建对象
如官方文档所写, “XmlReader 表示提供对 XML 数据进行快速、非缓存、只进访问的读取器。”,是一个流式读取。
可以用.Read()、.MoveTo……()等方法让读取器移动至想要的地方,此外还有丰富的属性和方法供使用
(官方文档https://docs.microsoft.com/zh-cn/dotnet/api/system.xml.xmlreader)
用XmlReader遍历xml指定内容并输出
下面是一个例子,用XmlReader遍历xml文件中的指定节点,并输出(这里是输出到ListView中)
这是用到的XML文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TaskList[
<!ELEMENT Task ANY>
<!ATTLIST Task id ID #REQUIRED>
]>
<TaskList>
<Task id="test01">
<account>123456789</account>
<solution>定时打卡</solution>
<time>22:00</time>
</Task>
<Task id="test03">
<account>123456789</account>
<solution>开机时&定时</solution>
<time>22:30</time>
</Task>
<Task id="test02">
<account>987654321</account>
<solution>定时打卡</solution>
<time>22:20</time>
</Task>
</TaskList>
这是代码
用到了.ReadSubTree()方法,在主Reader经过Task节点时为其创建一个针对Task节点的子Reader,再用子Reader对Task节点内元素进行遍历
(注:读取节点属性时,.MoveToAttribute()方法不知道为何无效,官方文档中也没有写清楚使用案例,我这里换用了.MoveToContent()和.GetAttribute()两个方法来实现获取节点属性)
public static void LoadTasks(string xmlPath, System.Windows.Forms.ListView listView)
{
//先清空listview
foreach (System.Windows.Forms.ListViewItem item in listView.Items)
{
listView.Items.Remove(item);
}
//打开XMLTasks.xml
XmlReaderSettings set = new XmlReaderSettings();
set.DtdProcessing = DtdProcessing.Parse;
using (XmlReader reader = XmlReader.Create(xmlPath, set))
{
//Console.WriteLine("test");//debug
while (reader.ReadToFollowing("Task"))
{
XmlReader taskReader = reader.ReadSubtree();
string id = "";
string acc = "";
string mode = "";
string time = "";
if (taskReader.HasAttributes == true)
{
//taskReader.MoveToAttribute(0);//这个函数有毛病
taskReader.MoveToContent();
id = taskReader.GetAttribute("id");
}
while (taskReader.Read())
{
if (taskReader.NodeType == XmlNodeType.Whitespace) continue;
if (taskReader.NodeType == XmlNodeType.Element)
{
switch (taskReader.Name)
{
case "account":
acc = reader.ReadElementContentAsString();
continue;
case "solution":
mode = reader.ReadElementContentAsString();
continue;
case "time":
time = reader.ReadElementContentAsString();
continue;
}
}
}
System.Windows.Forms.ListViewItem listViewItem_Task = new System.Windows.Forms.ListViewItem(new string[] {
id,
acc,
mode,
time}, -1);
listView.Items.Add(listViewItem_Task);
}
}
}
输出结果(ListView设定了根据ID自动升序排列):
Xml.Linq
说在前面:我是一个纯noob,sql用的也不熟。。
Linq大概是微软的.Net系语言中独特的查询语言,和sql既相似又有很大差异(废话)
官方文档:
Linq to xml:https://docs.microsoft.com/zh-cn/dotnet/api/system.xml.linq
Linq:https://docs.microsoft.com/zh-cn/dotnet/api/system.linq
官方指导:
C# 中的 LINQ:https://docs.microsoft.com/zh-cn/dotnet/csharp/linq/linq-in-csharp
用Linq查询xml中符合条件的项
本例为根据string taskID,查询XML中是否已存在指定的ID,防止在添加新节点时发生ID重复的情况。
public static bool isTaskIDExists(string taskID, string XMLPath)
{
//试试Linq
XDocument xdoc = XDocument.Load(XMLPath);
var queryIDs =
from att_id in xdoc.Element("TaskList").Elements("Task").Attributes("id")
where att_id.Value == taskID
select att_id.Value;
if (queryIDs.Take(1).Count() >= 1)
{
return true;
}
else return false;
}
其他
写的很肤浅,只涉及了基本简单的使用…………
但无论怎样,这是自己的经验总结,从这里出发,慢慢扩展自己的知识…………
Comments | NOTHING