我正在尝试编写一个XML解析器来解析大学提供给定日历年和学期的所有课程。特别是,我试图获得部门的首字母缩略词(即FIN财务等),课程编号(即数学415,415将是数字),课程名称以及课程价值的学分数。
我正在尝试解析的文件HERE
编辑和更新
读者深入了解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分钟之间),但是在解析大量数据的情况下可以预期。感谢所有发布答案的人,非常感谢。我希望这可以帮助其他可能有类似问题的人。
谢谢,
大卫
答案 0 :(得分:3)
好吧,显然加载XML文件有点慢(例如因为它们很大或因为下载它们所花费的时间)并且使用XDocument
将加载并将它们全部解析到内存中,即使你是只使用它的一小部分。以递归方式递增三个级别将使整个过程非常缓慢,但最终它将结束(无论是按预期还是通过OutOfMemoryException
)。 1
看看XmlReader
class。它允许您按顺序读取XML文件,挑选出您需要的任何内容,并在获得所需的所有信息时中止读取。但是,它与XDocument
的工作方式有很大不同,而且不那么直观。该MSDN页面上有一些示例,on Stackoverflow也是如此。
作为旁注:在开始阅读另一个XML文件之前,使用XmlReader
时,请考虑阅读并关闭阅读器。这样可以最大限度地减少应用程序的内存占用。
1 )例如,考虑一下您正在阅读一个包含10年3个季节的60个课程文件的文件,然后您的代码正在下载,解析,验证和处理10 * 3 * 60 = 1800个文件。它需要从(与本地PC相比)慢速互联网下载它们。不要指望整个过程很快。
答案 1 :(得分:1)
循环不会变得无限,它变得非常非常慢。这是因为
的召唤XDocument hoursDoc = XDocument.Load(crsePath);
打开另一个XML文件并解析它。考虑到当所有信息都在内存中时处理持续25秒,因此为您遇到的每个课程打开一个额外的文件会使进程变慢,这就不足为奇了。