// Parses a single book. Book ParseBook(XmlReader reader) { var book = new Book(); while (reader.Read()) if (reader.NodeType == XmlNodeType.Element) { string parseType; switch (reader.LocalName) { case "etext": book.Number = int.Parse(reader.GetAttribute("ID", RDF).Substring(5), CultureInfo.InvariantCulture); break; case "title": parseType = reader.GetAttribute("parseType", RDF); if (parseType != "Literal") throw new ApplicationException("Unrecognized parse type."); book.Title = reader.ReadElementContentAsString(); break; case "description": book.Notes = ParseText(reader); break; case "creator": book.Authors = ParsePersonsAndEra(book, reader); break; case "contributor": // Eras of contributors do not affect the era of the book intentionally. // Contributors might be not only illustrators, who would live at the // same time as authors, but also people who retyped the book and // uploaded it to the Project Gutenberg web site. They would mess the // era of the book which is supposed to embrace the time when the actual // paper book was written. book.Contributors = ParsePersons(reader); break; case "language": if (!reader.ReadToDescendant("value", RDF)) throw new ApplicationException("Missing language value."); book.Language = reader.ReadElementContentAsString(); break; case "subject": using (var subreader = reader.ReadSubtree()) book.Tags = ParseTags(subreader).ToArray(); break; case "created": if (!reader.ReadToDescendant("value", RDF)) throw new ApplicationException("Missing creation date value."); book.Included = reader.ReadElementContentAsDate(); break; case "downloads": if (!reader.ReadToDescendant("value", RDF)) throw new ApplicationException("Missing download count value."); book.Downloads = reader.ReadElementContentAsInt(); break; } } return book; }
// Gets the creation date of the Project Gutenberg catalog. This method should be called // before parsing the books and volumes because the creation date is at the beginning; // calling it later would not find the XML element with the date any more and would // continue reading the content to the end, skipping all content. This method expects a // reader returned by the method Open. public Date GetCreated(XmlReader reader) { Log.Verbose("Getting creation date..."); if (!reader.ReadToFollowing("Description", RDF)) throw new ApplicationException("Missing creation time."); if (!reader.ReadToDescendant("value", RDF)) throw new ApplicationException("Missing creation date value."); return reader.ReadElementContentAsDate(); }
// Parses a single book volume. Volume ParseVolume(XmlReader reader) { var volume = new Volume(); var formats = new List<string>(); while (reader.Read()) if (reader.NodeType == XmlNodeType.Element) switch (reader.LocalName) { case "file": volume.URL = ParseVolumeUrl(reader); break; case "format": if (!reader.ReadToDescendant("value", RDF)) throw new ApplicationException("Missing format value."); formats.Add(reader.ReadElementContentAsString()); break; case "extent": volume.Size = reader.ReadElementContentAsInt(); break; case "modified": if (!reader.ReadToDescendant("value", RDF)) throw new ApplicationException("Missing modified date value."); volume.Uploaded = reader.ReadElementContentAsDate(); break; case "isFormatOf": volume.Number = int.Parse(reader.GetAttribute("resource", RDF). Substring(6), CultureInfo.InvariantCulture); break; } volume.Formats = formats.Count > 0 ? formats.ToArray() : null; return volume; }