优化c#自定义Xml解析器类
本文关键字:Xml 自定义 优化 | 更新日期: 2023-09-27 18:06:50
我正在尝试编写一个XML解析器来解析大学提供的给定日历年和学期的所有课程。特别是,我想要得到系首字母缩略词(例如FIN代表金融等),课程编号(例如数学415,415将是数字),课程名称和课程值的学分数。
我试图解析的文件可以在这里找到
编辑和更新
在读者深入了解XML解析和优化它的最佳方法时,我偶然发现了这个博客POST
假设那篇文章中运行的测试结果既真实又准确,那么XmlReader的性能似乎远远超过XDocument和XmlDocument,这证实了下面精彩答案中所说的内容。话虽如此,我使用XmlReader重新编码了解析器类,并限制了单个方法中使用的读取器的数量。
下面是新的解析器类: public void ParseDepartments()
{
// Create reader for the given calendar year and semester xml file
using (XmlReader reader = XmlReader.Create(xmlPath)) {
reader.ReadToFollowing("subjects"); // Navigate to the element 'subjects'
while (!reader.EOF) {
string pth = reader.GetAttribute("href"); // Get department's xml path
string acro = reader.GetAttribute("id"); // Get the department's acronym
reader.Read(); // Read through current element, ensures we visit each element
if (acro != null && acro != string.Empty) { // If the acronym is valid, add it to the department list
deps.AddDepartment(acro, pth);
}
}
}
}
public void ParseDepCourses()
{
// Loop through all the departments, and visit there respective xml file
foreach (KeyValuePair<string, string> department in deps.DepartmentPaths) {
try {
using (XmlReader reader = XmlReader.Create(department.Value)) {
reader.ReadToFollowing("courses"); // Navigate to the element 'courses'
while (!reader.EOF) {
string pth = reader.GetAttribute("href");
string num = reader.GetAttribute("id");
reader.Read();
if (num != null && num != string.Empty) {
string crseName = reader.Value; // reader.Value is the element's value, i.e. <elementTag>Value</elementTag>
deps[department.Key].Add(new CourseObject(num, crseName, termID, pth)); // Add the course to the department's course list
}
}
}
} catch (WebException) { } // WebException is thrown (Error 404) when there is no xml file found, or in other words, the department has no courses
}
}
public void ParseCourseInformation()
{
Regex expr = new Regex(@"^'S(L*)'d'b|^'S(L*)'b|^'S'd'b|^'S'b", RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace); // A regular expression that will check each section and determine if it is a 'Lecture' section, at which point, that section's xml file is visited, and instructor added
foreach (KeyValuePair<string, Collection<CourseObject>> pair in deps) {
foreach (CourseObject crse in pair.Value) {
try {
using (XmlReader reader = XmlReader.Create(crse.XmlPath)) {
reader.ReadToFollowing("creditHours"); // Get credit hours for the course
crse.ParseCreditHours(reader.Value); // Class method to parse the string and grab the correct integer values
reader.ReadToFollowing("sections"); // Navigate to the element 'sections'
while (!reader.EOF) {
string pth = reader.GetAttribute("href");
string crn = reader.GetAttribute("id");
reader.Read();
if (crn != null && crn != string.Empty) {
string sction = reader.Value;
if (expr.IsMatch(sction)) { // Check if sction is a 'Lecture' section
using (XmlReader reader2 = XmlReader.Create(pth)) { // Navigate to its xml file
reader2.ReadToFollowing("instructors"); // Navigate to the element 'instructors'
while (!reader2.EOF) {
string firstName = reader2.GetAttribute("firstName");
string lastName = reader2.GetAttribute("lastName");
reader2.Read();
if ((firstName != null && firstName != string.Empty) && (lastName != null && lastName != string.Empty)) { // Check and make sure its a valid name
string instr = firstName + ". " + lastName; // Concatenate into full name
crse.AddSection(pth, sction, crn, instr); // Add section to course
}
}
}
}
}
}
}
} catch (WebException) { } // No course/section information found
}
}
}
虽然这段代码的执行需要相当长的时间(大约在10-30分钟之间),但是考虑到要解析的大量数据,这是意料之中的。感谢每个张贴答案的人,非常感谢。我希望这对其他可能有类似问题的人有所帮助。
谢谢,大卫
嗯,显然加载XML文件有点慢(例如,因为它们很大或因为下载它们所需的时间),并且使用XDocument
将加载并解析它们全部到内存中,即使您只使用其中的一小部分。三层递归地执行此操作将使整个过程非常缓慢,但最终它将结束(如预期的那样或通过OutOfMemoryException
)。1
看看XmlReader
类。它允许您按顺序读取XML文件,选择需要的内容,并在获得所需的所有信息时终止读取。然而,它的工作原理与XDocument
有很大的不同,而且不那么直观。在那个MSDN页面上有一些例子,在Stackoverflow上也有。
作为旁注:当使用XmlReader
时,请考虑在开始读取另一个XML文件之前读取并关闭阅读器。这将使应用程序的内存占用最小化。
1)考虑一下,例如,您正在阅读一个包含10年3季60课程的文件的文件,然后您的代码正在下载,解析,验证和处理10 * 3 * 60 = 1800个文件。它需要从(与你的本地电脑相比)缓慢的互联网下载它们。不要期望整个过程很快。
循环不是无限的,它只是变得非常非常慢。这是因为
的调用XDocument hoursDoc = XDocument.Load(crsePath);
打开另一个XML文件并解析它。考虑到当所有信息都在内存中时,处理时间为25秒,因此为遇到的每个课程打开一个额外的文件会减慢处理速度,这并不奇怪。