内容简介:OPML 全称是本文将介绍这个古老的格式,并提供一个 .NET 上的简易解析器。本文是两个部分的第二篇,前者是理解 OPML 格式,此篇是解析此格式:
OPML 全称是 Outline Processor Markup Language ,即 大纲处理标记语言 。目前流行于收集博客的 RSS 源,便于用户转移自己的订阅项目。
本文将介绍这个古老的格式,并提供一个 .NET 上的简易解析器。
本文是两个部分的第二篇,前者是理解 OPML 格式,此篇是解析此格式:
OPML 格式
在解析之前,最好先理解此格式的的元素组成和元素属性,所以如果你没有阅读概念篇,请先前往阅读。
创建适用于 RSS 的简易 OPML 模型
我们先为模型创建基类 OpmlModel
。
为了方便在客户端应用中使用,可以使其继承自 INotifyPropertyChanged
。
namespace Walterlv.Rssman.Models { public abstract class OpmlModel : NotificationObject { public void Deserialize(XElement element) { OnDeserializing(element); } protected abstract void OnDeserializing(XElement element); } }
namespace Walterlv.Rssman.Models { public abstract class NotificationObject : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; [NotifyPropertyChangedInvocator] protected void SetValue<T>(ref T field, T value, [CallerMemberName] string propertyName = null) { if (Equals(field, value)) return; field = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } [NotifyPropertyChangedInvocator] protected void NotifyPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
拿出我们关心的 outline
的属性来解析,于是有:
namespace Walterlv.Rssman.Models { [DebuggerDisplay("RssOutline {Text,nq}, {XmlUrl,nq}, Count={Children.Count,nq}")] public sealed class RssOutline : OpmlModel { private string _text; private OutlineType _type; private string _xmlUrl; private string _htmlUrl; public string Text { get => _text; set => SetValue(ref _text, value); } public OutlineType Type { get => _type; set => SetValue(ref _type, value); } public string XmlUrl { get => _xmlUrl; set => SetValue(ref _xmlUrl, value); } public string HtmlUrl { get => _htmlUrl; set => SetValue(ref _htmlUrl, value); } public bool HasChildren => Children.Any(); public ObservableCollection<RssOutline> Children { get; } = new ObservableCollection<RssOutline>(); protected override void OnDeserializing(XElement element) { // 等待编写解析代码。 } } }
还有表示 OPML 文档的模型:
namespace Walterlv.Rssman.Models { [DebuggerDisplay("RssOpml {Title,nq}, Count={Children.Count,nq}")] public sealed class RssOpml : OpmlModel { private string _title; public string Title { get => _title; set => SetValue(ref _title, value); } public ObservableCollection<RssOutline> Children { get; } = new ObservableCollection<RssOutline>(); protected override void OnDeserializing(XElement element) { // 等待编写解析代码。 } } }
从 OPML 文档中解析出模型
在以上的模型代码中,我为基类留有 OnDeserializing
方法以供反序列化。
为了尽可能简化此博客的代码,参数我直接使用了 XElement
类型,以便在方法中使用 XPath 语法来解析。(当然,如果你是做库或者进行大型可维护项目的开发,这里就需要一些抽象了。)
现在,我们写一个新的静态类型 Opml
来解析 OPML 文档:
namespace Walterlv.Rssman.Services { public static class Opml { public static async Task<RssOpml> ParseAsync(Stream stream) { var document = await XDocument.LoadAsync(stream, LoadOptions.None, CancellationToken.None); var root = document.XPathSelectElement("opml"); var opml = new RssOpml(); opml.Deserialize(root); return opml; } } }
于是,再补全模型 RssOpml
和 RssOutline
的反序列化部分:
// RssOpml.cs protected override void OnDeserializing(XElement element) { var title = element.XPathSelectElement("head/title"); Title = title?.Value; var outlines = element.XPathSelectElements("body/outline"); Children.Clear(); foreach (var value in outlines) { var outline = new RssOutline(); outline.Deserialize(value); Children.Add(outline); } }
// RssOutline.cs protected override void OnDeserializing(XElement element) { var text = element.Attribute("text"); Text = text?.Value; var type = element.Attribute("type"); if (type != null && Enum.TryParse(type.Value, out OutlineType outlineType)) { Type = outlineType; } var xmlUrl = element.Attribute("xmlUrl"); XmlUrl = xmlUrl?.Value; var htmlUrl = element.Attribute("htmlUrl"); HtmlUrl = htmlUrl?.Value; var outlines = element.XPathSelectElements("outline"); Children.Clear(); foreach (var value in outlines) { var outline = new RssOutline(); outline.Deserialize(value); Children.Add(outline); } }
注意,以上两个方法请分别填充到 RssOpml.cs
和 RssOutline.cs
的 OnDeserializing
方法中。
这里,所有的 XML 解析均使用的是 XPath 语法,关于 XPath 语法,可以阅读 XML 的 XPath 语法 - walterlv ,关于如何使用 XPath 在 .NET 中读写 XML 文件,可以阅读 .NET 使用 XPath 来读写 XML 文件 - walterlv 。
使用此 OPML 模型
当你把这些类都准备好,那么你就可以使用简单的几句话来完成 OPML 文档的解析了。
在 UWP 应用中,可以通过 StorageFile
来打开一个文件流:
var folder = Package.Current.InstalledLocation; using (var stream = await folder.OpenStreamForReadAsync("sample-opml.xml")) { var opml = await Opml.ParseAsync(stream); // 使用此 OPML 文档 }
在 .NET Framework 传统应用中,可以使用 File.Read
来打开一个文件流。
由于我们本文中创建的模型均实现了 INotifyPropertyChanged
接口,所以你甚至可以直接将 Opml.ParseAsync
的返回结果应用于绑定。
本文会经常更新,请阅读原文: https://walterlv.com/post/deserialize-opml-using-dotnet.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接:https://walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 (walter.lv@qq.com) 。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 设计模式之发布订阅模式(5) Spring Events源码解析
- 设计模式之发布订阅模式(2) Redis实现发布订阅模式
- 设计模式之发布订阅模式(1) 一文搞懂发布订阅模式
- Redis订阅与发布
- 消息队列和发布订阅
- JavaScript 发布-订阅模式
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Rationality for Mortals
Gerd Gigerenzer / Oxford University Press, USA / 2008-05-02 / USD 65.00
Gerd Gigerenzer's influential work examines the rationality of individuals not from the perspective of logic or probability, but from the point of view of adaptation to the real world of human behavio......一起来看看 《Rationality for Mortals》 这本书的介绍吧!